Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

16.09.2012, 18:48

ExecutionCode - Eine Scriptsprache inspiriert durch Assembler

ExecutionCode

Hi,
ich möchte euch eine Skriptsprache vorstellen, erstellt von mir. Aber bevor ich näher ins Detail gehe, hier erst mal ein Codebeispiel um zu zeigen wie diese Programmiersprache aussieht:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//Kommentare werden wie in C/C++ gehandhabt
 /*also auch diese Mehrzeilenkommentare
sind erlaubt*/

/*
Programme sind nicht gespalten in Funktionen sondern in Modulen (was hier dasselbe ist), 
damit man sie leichter von den registrierten Funktionen aus C++ unterscheiden kann.
 */

//Ein Befehl ist unterteilt in Funktionsgruppenname, Funktionsname und (optional) Parameter
 main {
     //Eckige Klammer bedeuten numerische Variablen
      system.alloc [counter]
      system.alloc [isNowEnd]
      //Zuerst schiebe ich eine numerische Konstante (hier 1) auf den Parameterstack
      system.push 1
      /*dann bewirkt der system.set Befehl, dass der letzte Eintrag vom Parameterstack genommen wird und auf
     den Eintrag, der im Parameter angegeben ist, kopiert wird.
     Wenn man etwas auf den Parameterstack schiebt wird der Wert gespeichert, Variablen können nur als 
     Parameter eines Befehls geändert werden.*/
      system.set [counter]

     //Das ist eine Sprungmarke (sollte aus C bekannt sein?), denn man muss Schleifen selber implementieren
      LoopStart:
      //Zuerst schreibe ich den aktuellen Wert des Zählers und beende die Zeile
      console.println [counter]

     /*Eine mathematische Operation macht man, indem man die zwei Operanten
     auf den Stack schiebt und die Zielvariable mit dem entsprechenden
     Befehl aus der "math" Gruppe aufruft.
      */
      system.push [counter]
      system.push 1
      math.add [counter]

     //genauso funktionieren logische Operationen wie diese, um den Zähler zu überprüfen
      system.push [counter]
      //Spitze Klammern signalisieren Ressourcenvariablen (vergleichbar mit Konstanten)
      system.push <counterEnd>
      logical.equal [isNowEnd] //also wenn counter==11 dann isNowEnd=1 ansonsten isNowEnd=0

     //und wenn wir weit genug gezählt haben, können wir das Zurückspringen zu "LoopStart" überspringen
     /*BEACHTE: Sprungmarken genau wie alle anderen Namen (außer Modulnamen) existieren nur im Quellcode,
      der Compiler ersetzt diese durch entsprechende Zahlen also hier die Zeilennummer vor der Sprungmarke*/
      system.skip [isNowEnd]
      system.jump “LoopStart”

     //Vergiss nicht die Variablen wieder freizugeben!
      system.free [counter]
      system.free [isNowEnd]
}

//Eine Ressourcenvariablen kann wie alle Variablen entweder eine Nummer oder ein Text sein
//Und noch etwas: Wenn du # vor eine Zahl setzt wird sie als hexadezimale Zahl interpretiert
//Also ist diese Ressource dezimal 11
ressource counterEnd #b


Hoffentlich schon viel gelernt, oder?
Aber nun zu dem Teil, was ich mit C++ gemacht habe:
Gestartet habe ich mit einer VM die nicht einen Prozessor (mit Registern usw.) simulieren soll, sondern lediglich eine Reihe von Befehle bekommt und diese ausführt, dabei erkennt man schnell die Ähnlichkeit zwischen den Befehlen in ExecutionCode und dem Bytecode, welcher von der VM eigentlich ausgeführt wird:
Der Befehl "system.push 1" sieht codiert in einzelne (hexadezimale) Bytes so aus: 00 03 04 01 00 00 00 00
Komische Zahlen, die was bitte bedeuten?
1.Byte : Funktionsgruppenindex (00 -> "system")
2.Byte : Funktionsindex (03 -> "push")
3.Byte : Parameterflags (04 -> numerische Konstante)
4. bis 7.Byte : Parameterdata (bei Nummern ist es selbige, bei Text ist es ein Zeiger auf ein char*)
8. Byte : nichts, lediglich da um eine einfachere Handhabung mehrere Zeilen zu ermöglichen

Die VM hat einen Stack der speichert, welches Modul gerade in Ausführung ist, bei welcher Zeile es sich gerade befindet und welche lokalen Variablen es benutzt, wobei das nur für die Skriptmodule gilt: C-Funktionen werden nicht (wozu auch) auf den Stack geschoben.

So, falls ihr weiter Fragen habt, stellt sie einfach hier :)

Todo:
- Mehr Funktionen!!
- Mögliche Bugs beheben?
- Sourcecode zusammenfassen (im Moment ein wenig chaotisch) dass man ihn vorzeigen kann

Changelog:
+ Referenz von ECAssembler (Link siehe unten)
+ Neue Gruppe "string"
+ Namen für Ressourcen
+ Binäres Programmformat (unabhängig der Sprache)
+ Einige neue Befehle in den Gruppen system und math
+ Zahlenrätsel als weiteres Beispiel
* Identifier statt Strings für Aufrufe von Modulen/C++-Funktionen
* Skript-Beispiele aktualisiert
* Modul-lokale statt globale Jumpmarks
- Bugfixes
- system.runEx gelöscht, da der Befehl einfach nur sinnlos war...

Download
Download bei Skydrive
Im Moment lizenziert unter: CC BY-NC 3.0

Mfg
Helco

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Helco« (09.10.2012, 19:40)


Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

2

16.09.2012, 19:50

Schon interessant, auch wenn ich es selbst nie verwenden würde. :) Da ich gerade das Drachenbuch lese, bin ich natürlich schon interessiert und würde mir schon gerne den Quellcode deines Compilers/Interpreters ansehen, jedoch hab' ich irgendwie eine starke Abneigung, mir dazu gleich eine .zip runterzuladen.
Kann ich mir das auf Git angucken oder ist der Source klein genug um ihn online zu posten (nicht hier im Forum)?
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

3

16.09.2012, 22:27

Ist ja ganz nett, aber welchen Zweck hat eine Skriptsprache, wenn sie unkomfortabler zu programmieren ist als eine "normale" Sprache?

4

17.09.2012, 07:18

@Architekt
Ich habe keinen Github Account genauso wie GoogleCode oder Sourceforge, aber falls du meinst dass 2901 Zeilen in 16 verschiedenen Dateien irgendwo online (abgesehen von github usw.) gepostet werden können tu ich das :)
Letzte Möglichkeit, die nicht ein Archiv beinhaltet, wäre dass ich versuche den Code in eine pdf zu quetschen und diese in die gerade entdeckten Dateianhänge dieses Forums hochlade.

@David Scherfgen
Für mich hauptsächlich um zu sehen, wie so eine VM, ein Compiler, eine Skriptsprache, die ich auch tatsächlich schreiben kann, im Quelltext aussieht. Außerdem habe ich vor (vielleicht nicht gerade jetzt sofort) den Compiler zu modifizieren, um solche Dinge wie die bekannten Strukturen (wie Operatoren, Schleifen, usw.) zu implementieren um die Sprache komfortabler zu gestalten. Auch wenn ich natürlich zugebe dass ich in meinen Spiel wohl kaum ExecutionCode verwenden werden, da tendiere ich eher zu Angelscript, welches dann fast genauso einfach zu schreiben ist wie C++

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

5

17.09.2012, 09:38

Könntest ja auch versuchen, darauf aufbauend eine ähnliche Sprache wie AngleScript (oder eine andere, höhere Sprache) zu bauen. Diese würde dann in dein Execution Code kompiliert werden.
Und zum Ansehen deines Codes: Wie wäre es mit Dropbox?
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

foreach

Frischling

Beiträge: 87

Beruf: Student

  • Private Nachricht senden

6

17.09.2012, 12:16

Hättest du das ganze Projekt nicht in C++ sondern in Haskell mit Parsec realisiert wären es vieleicht noch 400 Zeilen Code (warscheinlich aber eher noch weniger). Ich jedenfalls möchte kein anderes Werkzeug mehr für eine solche Aufgabe verwenden müssen.

7

17.09.2012, 16:59

@Architekt
In der Richtung meinte ich auch die Modifizierung des Compilers :D (genau genommen behalte ich diesen Compiler und baue wirklich einen neuen mit der Grundlage des jetzigen)
Soweit ich herausgefunden habe, werden die einzelnen Dateien dann nicht angezeigt sondern ebenfalls gedownloadet, wenn auch einzeln und ohne Archiv dass man erst entpacken muss deswegen hoffe ich dass auch SkyDrive (für das ich schon einen Account habe) ebenfalls geht?
Deswegen hier der Link zu dem entsprechenden Ordner: Ordner
Ich entschuldige mich für manche Kommentare oder Badstylecode, ich hoffe im Laufe der weiteren Entwicklung davon wegzukommen, falls es in den jeweiligen Fällen angebracht ist (z.B. habe ich mir für die meisten mathematischen Funktionen ein Makro geschrieben, dass ca. 15 Zeilen für ebenso viele Skriptfunktionen spart, wo ich finde dass ohne dieses Makro der Code nur noch unübersichtlich wird)
Als Wiedergutmachung findet ihr noch ein Skript das ich für http://www.99-bottles-of-beer.net/ geschrieben habe, allerdings bis jetzt noch nicht angenommen wurde...

@foreach
Das ist vermutlich richtig allerdings lese ich über Parsec

Zitat

Parsec is an industrial strength, monadic parser combinator library for Haskell. It can parse context-sensitive, infinite look-ahead grammars but it performs best on predictive (LL[1]) grammars.

Mein Ziel war es alles für ExecutionCode selber zu schreiben, statt externe Bibliotheken (auch nicht nur als Hilfe für den Compiler) zu benutzen, welche es mit Sicherheit auch für C++ gibt.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

8

17.09.2012, 18:11

Vor allem ist Haskell auch so eine Sache. Viele Sachen sind schön einfach, aber dafür gibt es Geschwindigkeitseinbußen. Das ist bei funktionalen Sprachen nun mal so.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

9

09.10.2012, 19:44

UPDATE:
Einige neue Dinge, einige Dinge verändert, andere gelöscht (steht alles im aktualisierten 1.Post)

Bis jetzt habe ich nur ExecutionCode Assembler (der genaue Name damit die geplante "höhere" Sprache sich keinen neuen Namen ausdenken muss) und die VirtualMachine verbessert und vor allem eine genauere Referenz für Interessierte geschrieben, aber ich finde die ECAsm kann jetzt fürs Erste so gelassen werden und ich kann mich auf etwas anderes (vermutlich erst mal nicht ECBasic) konzentrieren ohne ein schlechtes Gewissen zu haben wenn ich das Projekt als Zuletzt geöffnet in der IDE sehe...

Feedback nehme ich natürlich gerne nicht nur zu den Programmen/Sprachen sondern auch zu der Referenz an, da ich noch nie eine solche in dem Niveau geschrieben habe.

Mfg Helco

Werbeanzeige