Wie ihr vielleicht wisst, ist das "ScriptSystem" von FireBlade seit neustem StandAlone. Ursprünglich hab ich es nur zur Ansteuerung der ParticleScript Klasse verwendet, und dazu reichte es auch bisher aus. OK - man nimmt so viel Erfahrung mit, wie man kann. Leider ist es sowieso immernoch etwas buggy, sodass ich beschlossen habe, mich jetzt erstmal diesem Scriptsystem zuzuwenden und es zu erweitern/verbessern. Das es schon Scriptsysteme en masse gibt, ist mir bewusst. Aber es geht mir hier wie gesagt in erster Linie um die Erfahrung, und man möchte vielleicht nicht immer diese Boliden nehmen, wenn man sie nicht ausreizen will.
Was ist bisher getan?
Um es kurz zu sagen: Um es als Scriptsystem zu bezeichnen, zu wenig. Im Moment ist es mehr eine Art Batch-Processor. Das soll sich natürlich aber ändern. Bisherige Specs:
- Der extrem ineffiziente TermParser wurde mittlerweile neu aufgelegt.
- If-Abfragen (jetzt auch mit komplexeren Boolschen Ausdrücken)
- Eine Mischung aus For- und Repeatschleife
- Float-Variablen
- Programmseitige Definition eigener Funktionen
Was passiert noch?
- "Echtzeitisierung" : Bisher wird alles immer wieder aufs neue durchgeparsed, was das System für Echtzeitanwendungen absolut unbrauchbar macht (ist seit eben im Gange). Ich hoffe es auf einem Niveau zu bekommen, mit dem man z.B OpenGL mit akzeptabler Geschwindigkeit ansteuern kann.
- Typisierung: Im Moment kann man nur Floatvariablen erzeugen, das wird mindestens auf Integer, String, Float, Boolean und ggf. Pointer erweitert.
- Erweitern des TermParsers auf Bool (schon fertig, aber noch etwas buggy) und String
- Importieren anderer "Units"
- Untergliederung in Funktionen
- ggf. Pointerarithmetik
Vom Syntax her ähnelt sich das System vielleicht einer Mischung aus Delphi und LOGO. So wird es ausschließlich Methodenaufrufe geben bzw gibt es ~. Derzeit sieht zum Beispiel ein Script mit der veröffentlichten Version so aus:
Code:
// Lege a an, schreib 7 rein
::Make(a, 7);
::Make(b, a*55);
::For(i, 1, 15);
::Make(c, i*b*(1+2));
::If(c, >, 100);
MyFunction(c, 11+c);
::EndIf();
::EndFor();
Hinarbeiten werde ich auf sowas:
Code:
::Include('./MatheFunktionen.fbs');
::Function(Float, Mult, a, b: Float);
::Make(float, Result^, a * b);
::End();
::Function(void, MachWas, a, b: Pointer, c: Boolean);
::If((a^ < b^) & c);
::Make(Pointer, d, ::Reference(c));
::Make(Float, a^, Mult(Divide(a^, b^), 4)); // Divide steht in "MatheFunktionen.fbs"
::EndIf();
::EndFunc();
Bis dahin ist es aber noch etwas
Soweit erstmal. Screenshots und Demos werde ich zu Verfügung stellen, wenn das System anfängt, Realtimefähig zu werden - das wird hoffentlich nichtmehr so lange dauern.
Gruß
_________________ I'm not the signature, I'm just cleaning the floor...
So, habe den Interpreter jetzt nach längerer Distanzierung vom Programmieren endlich fertig.
Einige Ziele habe ich erreicht, andere nicht oder nur begrenzt.
Also:
1. Ich habe durchaus was gelernt dabei .
2. Es stehen die simplen Datentypen Integer (genauer Int64), Float (genauer Extended), String (genauer WideString zur FPC-Kompatibilität) und Bool zur Verfügung.
3. Die TermParser für die unterschiedlichen Typen liefen bisher problemlos
4. Ein Importieren anderer Scriptdateien habe ich nicht implementiert, da ich die Relevanz dafür nicht sehe (kommt vllt. noch )
5. Es gibt Funktionen.
6. Es gibt "unechte" Pointerarithmetik (über integrierte Funktionen)
Zur Geschwindigkeit:
Ein erster Test, Sortieren von Zahlen mit BubbleSort, ergab, dass FreePascal 2.1.5 unter kubuntu 7.04 64bit ca. mit 80x Geschwindigkeit arbeitet. Ich finde den Wert nicht so schlecht eigentlich. Ich weiß nicht, ob man es vergleichen kann, aber z.B. ist C ca. 30x schneller als LUAScript, also eine wirklich "professionelle" Scriptsprache. Zumal bei mir auch nichts in ByteCode o.ä. übersetzt und dann von einer virtuellen Maschine interpretiert wird. Im Prinzip funktioniert es ähnlich: ich lege mir eine Liste mit Instruktionen an, die ich einfach der Reihe nach durchgehe. Ich bin extra nochmal über die Routinen zur Ausführung des Scriptes drübergegangen - zwei Sachen fielen mir noch zur Optimierung ein. Um genau zu sein habe ich keine Ahnung, wie man (außer durch Umsetzen in ByteCode) das Ganze noch schneller bekommen kann. Der ausführende Teil des Interpreters sind im Endeffekt nur wenige Zeilen. Ich denke, die Performance wird auf diesem Level nichtmehr durch langsamen Code gebremst, sondern durch den entstehenden Overhead beim Methodenaufruf von Delphi/FPC, gerade deswegen, weil Berechnungen in Rechenbäumen gespeichert werden, die Rekursiv "ausgeführt" werden. Ich denke, dass zumindest die Umsetzung der Rechenoperationen in ByteCode durchaus nochmal einen starken Performancesprung bieten. Wenn ich Zeit und Lust habe, werde ich das mal in Angriff nehmen. Aber davon abgesehen ist es für vorgesehene Anwendungen (z.B zum Ausführen bei bestimmten Events) durchaus schnell genug.
Hier mal ein Script, damit ihr sehen könnt, wie die Syntax nun endgültig aussieht. Es handelt sich hierbei um den besagten BubbleSort-Algo.
Code:
:function void: bubblesort (int: a,int: l);
:make(int: isize,SizeOf('int'));
:make(bool:change,true);
:while(change);
:make(bool: change,false);
:for(:make(int: i,0);:make(int: i, i+1);int: i<l-1);
:make(int: e1, readint(a+i*isize));// readint liest die gegebene Speicheradresse als int aus
:make(int: e2, readint(a+(i+1)*isize));
:if(int: e2<e1);
writeint(a+i*isize, e2);
writeint(a+(i+1)*isize, e1);
:make(bool:change,true);
:end;
:end;
:end;
/*:for(:make(int: i,0);:make(int: i, i+1);int: i<l);
print(readint(a+i*isize));
:end;*/
:end;
Der Interpreter mit Solver zählt etwa 3300 Zeilen Code. Nichts desto trotz ist er vergleichsweise einfach zu handlen:
// "packed", damit die Reihenfolge im Speicher sicher erhalten bleibt
Tparam =packedrecord
aref: TInteger;
alen: TInteger;
end;
const LEN =50;
var
p:^Tparam;
begin
p := sortMethod.ParamMem;
// für Speicherplatz müssen wir nicht sorgen
p^.aref:= TInteger(@a[0]);
p^.alen:= LEN+1;
sortMethod.Call(p, sortMethod.ResultMem);
end;
Was allerdings schon auffällt: Da der Interpreter intern sehr viel mit Pointern arbeitet, bleibt dies dem Benutzer leider nicht erspart. Für den erfahrenen Programmierer sollte das kein Problem sein - ohne Erfahrung mit Pointern jedoch, wird sich der ein oder andere u.U. schwer tun und möglicherweise Fehler produzieren, die (und dafür ist falscher Umgang mit Pointern ja mehr oder weniger bekannt) u.U. erst wesentlich später im Quellcode zu Exceptions führen können, die scheinbar unlogisch sind (z.B beim Schließen des Programms).
Noch gibts den Interpreter nicht zum Download. Ich muss erst noch entsprechende Manuals schreiben und etwas Codecleaning durchführen. Außerdem wollte ich im selben Atemzug gleich ein Interface zu FireBlade schreiben und FireBlade selbst auch noch nach grob unsauberen Code durchforsten. Sollte nicht mehr allzulang dauern.
_________________ I'm not the signature, I'm just cleaning the floor...
Das Projekt ist jetzt auf SourceForge registriert. Das Archiv enthält nur Code+HowTo. Der Interpreter steht unter der GPL. Er ist für all jene gedacht, die keine Boliden wie LUA benötigen und keinen großen Aufwand beim Einbetten haben wollen. Dem ein oder anderen, der auch einen Interpreter schreiben möchte, wird es vielleicht ein paar Anhaltspunkte bieten.
Mitglieder in diesem Forum: 0 Mitglieder und 51 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.