Delphi-PRAXiS
Seite 6 von 9   « Erste     456 78     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Software-Projekte der Mitglieder (https://www.delphipraxis.net/26-software-projekte-der-mitglieder/)
-   -   Sysygy Script Engine - Version 0.99h (https://www.delphipraxis.net/115545-sysygy-script-engine-version-0-99h.html)

Geri 6. Jan 2009 15:28

Re: Sysygy Script Engine - Version 0.99h
 
Hallo Dave

Zuerst mal alle Achtung vor diesem Projekt!

Fürs Verständnis aber ein paar Fragen:

Ich habe ein Programm bei dem Objekte eine hierarchische Datenstruktur bilden.

Der Aufbau sieht in etwa so aus: Projektgruppe->Projekte->Programme->...

Auf ein Programm kann man z.B. über ProjektGruppe[0].Projekte[1] zugreifen.

Sehr praktisch wäre nun, wenn man per Skript z.B. auf ein Objekt der Klasse TProgramm zugreifen und einzelne Methoden davon aufrufen könnte.

Fall es mit einer Script-Engine überhaupt Sinn macht und funktioniert, wie würde die Vorgehensweise bei Sysygy dann bitte aussehen?

Der Download von Deiner hat leider nicht geklappt Dave.

Vielen Dank für die Inputs

Geri

EugenB 7. Jan 2009 13:04

Re: Sysygy Script Engine - Version 0.99h
 
Btw:
Zitat:

Zitat von EugenB
Ich bins mal wieder xD

Wie kann ich dem Script eine vorhandene Variable / Klasse zuweisen? zb. Self:TForm ?

In einem Beispiel wird das schon erklärt, sorry ^^

Paar Bugs:

Wie kann ich ne Klasse im Script erstellen? zb das funktioniert nicht:

Delphi-Quellcode:
type
    TMyClass = Class
    public
          procedure FormPaint(Sender: TObject);
    end;

procedure TMyClass.FormPaint(Sender: TObject);
begin

end;
Zitat:

[Error] myprogram(12): Procedure "tmyclass" already exists
Could not compile the script
Oder wie kann ich Variablen in Klassen nutzen? in Records funktioniert es, in Klassen nicht

Delphi-Quellcode:
program myprogram;

uses
    Classes, Forms;

type
    TTestRec = record
       FVar: String;
    end;

    TMyClass = Class
    private
        FMyVar: String;
    public
        function Create():TMyClass;
    end;
Zitat:

[Error] myprogram(13): "end", "public" expected, but found scsIdentifier instead
[Error] myprogram(13): "end" expected, but found scsIdentifier instead
[Error] myprogram(13): ";" expected, but found : instead
[Error] myprogram(13): "=" expected, but found ; instead
[Error] myprogram(14): scsIdentifier, "(", "set", "class", "record", "type" expected, but found public instead
Could not compile the script

Dann hätte ich noch nen Bug-Fix:

Unit: uSygIncGraphics
Zeilen: 688-692
Neuer Code:
Delphi-Quellcode:
function TBrush_Bitmap(Self: TBrush): TBitmap;
// function TBrush.Bitmap(Self : pointer) : TBitmap;
begin
  result := {$IFDEF FPC}TBitmap(Self.Bitmap){$ELSE}Self.Bitmap{$ENDIF};
end;
Anscheinend ist Dave im Urlaub xD

@Geri
wieso regelst du nicht zb. die ProjektGruppen, Projekte etc im Main Programm, dann sagst du nur diese unitX ist das ProjektX, und dann wenn du genau dieses Projekt brauchst rufste die unitX mit der Script Engine auf?

Geri 8. Jan 2009 16:30

Re: Sysygy Script Engine - Version 0.99h
 
Hallo Eugen

Vielen Dank für Deinen Hinweis. Das "Main"-Formular führt eine Referenz auf den Projektgruppenmanager. Dieser verwaltet eine Liste an Projekten. Jedes Projekt ist eine wie eine Projektgruppe ein Klasse mit Methoden und Eigenschaften.

Die Struktur sieht in etwa so aus:

Delphi-Quellcode:

TfrmMain = class(TForm)
            ... CreateForm(...);
           
           public
             mProjectGroup:TProjectGroup;
           end;

TProjectGroup = class(TComponent)
                     ProjectList:TList;
                     Constructor creaet(...);
                     procedure CreateNewProject):TProject; // erzeuge ein Objekt der Klasse TProject und füge es in ProjectList ein.
                     ....
                  end;

TProject = class(TComponent)
                  ......
                  public
                    Wert1, Wert2:Integer;
                    procedure SetWert1(aWert1:Integer);
                    ....                
                  end;

Im Script würde ich dann z.B gerne

Delphi-Quellcode:
  ...
  ThistProjecd:=mProjectGroup.CreateProject);
  ThisProject.SetWert1(1235);
  ...
Anstatt der Referenz ThisProject könne ich auch gut mit dem Listenindex leben..:)
Geht so was, ich weiss nicht ob diese Aufgabe für eine script-Engine Sinn macht, für mich wäre es aber sehr praktisch.

Beste Grüsse

Geri

EugenB 8. Jan 2009 16:57

Re: Sysygy Script Engine - Version 0.99h
 
Das müsste die Script Engine schaffen

jage mal TProjectGroup und TProject durch das ImportTool, diese setzt du dann unter uses

im Script selbst

musste dann uses uProjects (zb)

bei var

mProjectGroup : TProjectGroup exports;

machen

kurz bevor du das Script "Run'st" musste mit SetVariable ( kA welche parameter , einfach mal gucken ^^) diese Variable setzen und schon kannste mProjectGroup im Script nutzen

Hoffe es ist das was du meintest und man kann es verstehen ^^

MfG,
Eugen

Geri 9. Jan 2009 13:22

Re: Sysygy Script Engine - Version 0.99h
 
Hallo zusammen

@Eugen: Vielen Dank für Deine Hinweise. Ich werde mal versuchen diesen Weg in die Tat umzusetzen :) Kannst du mir bitte sagen, von welchem import-tool du sprichst? Ich bin die Demos mal durchgangen. Ein Tool habe ich nicht gefunden :)

Wenn ich richtig verstehe muss ich folgndermassen vorgehen:

1.) Units zuerst auf irgendeine Art importieren damit sie die Script-Engine kennt. (Importtool???)
2.) Im Skript eine Variable vom Typ TProjectGroup (z.B. ProjectGroup1:TProjectGroup) definieren.
3.) Auf Methoden und Eigenschaften der Klasse ProjectGroup und TProject zugreifen - Stimmts?
z.B.
Delphi-Quellcode:

var ProjectGroup1:TProjectGroup;
    Project1: TProject;
begin
  ProjectGroup1:=GetProjectGroupReference(); // Referen von der Mainform holen
  if Assgined(ProjectGroup1) then
  begin
    Project1:=ProjectGroup.GetProject(0);            
    if Assigend(Project1) then Project1.SetProjectName('Testproject 0');
  end;
end;
Habe ich das richtig verstanden? :)


@Dave
Ich bin absolut begeistert! Gibt es zu dieser Library auch eine Beschreibung oder ein Tutorial. Das wäre sehr praktisch, denn wenn man das Konzept versteht, dann kann man die Libary besser nutzen.
Ja, jedenfalls eine super Sache und ich werde mal schauen, ob ich es schaffe, diese Engine für mein Programm zu nutzen.

Beste Grüsse

Geri

EugenB 9. Jan 2009 13:46

Re: Sysygy Script Engine - Version 0.99h
 
zu 1.) Main Programm -> deine Unit laden -> Project -> Export to Delphi Unit
zu 2.) genau, das Beispiel von dir müsste ich auch mal testen ^^ ist leichter als mit export usw^^
zu 3.) genau

Wobei ich nicht weiß ob Assigned in der Engine vorhanden ist

Und die Projekte sollen dann auch noch mal ausführbare Scripts sein?

Wird langsam zeit das sich Dave mal meldet *g*.

Geri 9. Jan 2009 15:33

Re: Sysygy Script Engine - Version 0.99h
 
Hallo Eugen

Die Klasse Projekt enhält Methoden, welche im Programm bestimmte Aktionen ausführt.
Der Inhalt eines Projektes selbst ist kein Script.

Das Script wäre deshalb sehr praktisch, weil der Benutzer bestimmte Abläufe, die er immer wieder ausführt automatisieren könnte (ähnlich einem Macro).

Ich versuche gerade mein Glück :)

Beste Grüsse

Geri

littleDave 3. Mär 2009 19:56

Re: Sysygy Script Engine - Version 0.99h
 
Hallo an alle,

sorry das ich so lange nicht mehr online war - ich habe im Moment sehr viel zu tun und hatte mein Delphi in den letzten 3 Monaten ca. 1 Woche mal gestartet :-(. Aber ich will mir wieder etwas Zeit für meine Lieblingsprache nehmen.

Bevor ich auf eure Beiträge eingehe, habe eine gute und eine schlechte Nachricht für euch:
Die Schlechte: Die Sysygy Script Engine werde ich nicht mehr weiterentwickeln :-(. Das Ding ist vom Quelltext her zu unübersichtlich und die Einbindung zu umständlich.

Die Gute Nachricht: Ich arbeite gerade an einer neuen Script Engine :-)

Die neue Script-Engine wird einiges Anders und Besser machen, da ich viel aus dieser Script-Engine gelernt habe: Ich hab mal schnell eine Liste von Sachen zusammengeschrieben, die ich einbauen WILL:
  • Schnellerer und besserer Compiler (bereits 70% der Features des alten Compilers fertig eingebaut)
  • Caching von bereits kompilierten Units (so wie in Delphi die .DCU - Dateien)
  • Einen Linker, der einen Optimizer behinhaltet (zu 70-80% fertig)
  • Eine kleinerer Byte-Code-Aufbau
  • Eine schnellere RunTime-Engine (ist schon zu ca. 40% fertig)
  • Richtiger Unit-Aufbau (unit ... interface ... implementation ... initialization ... finalization ... end.)
  • Object-Pascal!!! (eigene Klassen im Script erstellen) (noch nicht angefangen)
  • Records und Arrays (noch nicht angefangen)
  • Methoden überlaben (funktioniert schon)
  • Methoden forwarden (funktioniert schon)
  • Ein etwas anderer Unit-Aufbau (nicht vom Quelltext her, sondern von der Benutzung von Units):
    Ich arbeite zur Zeit sehr viel in C# und ich finde das generelle Design von .NET und den Klassen nicht schlecht. Ich hab mir gedacht, dass Units (wie die Namespaces in .NET) über mehrere Dateien gehen können
  • Statische Methoden (class procedure und class function) (funktioniert schon)
  • und noch so einiges mehr ...

Das ist schon eine sehr lange List und sehr komplexe Liste die ich nicht so schnell abarbeiten kann. Jedoch bin ich noch sehr optimistisch, dass ich das hinbekomme.


Zitat:

Zitat von EugenB
irgendwie bin ich grade im Script-Wahn :-D, zuerst hab ich Pascal Script probiert aber irgendwie sind da noch soviele Fehler, dann hab ich schon fast vergessen das es diese Script Engine noch gibt ;)

Danke für die Blumen :-)

Zitat:

Zitat von EugenB
Da ich FPC nutze, musste ich in dieser Datei: uSygConstants

diesen Teil:
...
auch unter das {$IFNDEF FPC} packen
dann konnte ich es schon mal Compilieren :)

Ja, den FPC-Support hab ich leider etwas schleifen lassen

Zitat:

Zitat von EugenB
Was meinste wann diese Sachen funktionieren werden?
Arrays
Class Properties
Gleichnamige Funktionen ( welcher aber verschiedene Parameter haben zB. x(a: Integer); x(a: Float); x(a,b : Integer); etc

Arrays: wird es in der neuen Engine geben
Class properties: wird es in der neuen Engine geben
Overloading methods: wird es in der neuen Engine geben (funktioniert bereits)

Zitat:

Zitat von EugenB
Wie füge ich Funktionen hinzu, auch wenn ich den UnitName nicht weiß?
Delphi-Quellcode:
procedure TForm1.ParserOnAddCustomFunctions(Sender: TObject; UnitName: string);
begin
   if(UnitName='myprogram')then
   begin
      TSygScript_Parser(Sender).AddFunction(@MyWriteLn, 'procedure WriteLn(s: string); register;');
   end;
end;
Wenn ich das ohne UnitName='my...' mache bekomme ich nen Fehler das WriteLn schon existiert, gibt es vllt ne Funktion zum zu gucken ob diese Funktion schon existiert? oder wie löst man es am besten.

Die "AddFuntion" - Method ist noch von ganz früher, daher wollte diese nicht mehr verwendet werden. Am besten, du erstellst eine eigene Unit, die dann per Uses eingebunden wird.

Zitat:

Zitat von EugenB
Ich würde vorschlagen das du die Scipt Engine auf einen SVN Server packst, dann könnte man immer nen aktuellen Code bekommen und man könnte leichter Patches erstellen :)

Die neue Version werd ich wahrscheinlich in ein SVN Packen, das ist jedoch jetzt noch zu früh

Zitat:

Zitat von mschnell
Hast Du Deinen Bytecode komplett neu erfunden, oder hast Du eine Vorlage benutzt ?

Gibt es eine Beschreibung für den Bytecode ?

Der ByteCode ist von mir frei erfunden und hat auch leider keine Beschreibung. Jedoch hab ich das für die neue Version besser geplant und umgesetzt - der ByteCode wird dann besser zu verstehen sein.

Zitat:

Zitat von mschnell
(Ich möchte u.U,. den Bytecode-Interpreter in C implementieren, um auf einem Prozessor, für den es keinen Object-Pascal-Compiler gibt, Delphi-Code laufen zu lassen. )

Auch wenn ich das sehr interessant finde würd ich im Moment sagen: bitte warte, bis ich die neue Version veröffentlicht habe, da hat sich alles geändert und den Aufwand wäre umsonst, wenn du umsteigen wollen würdest (was ich dir bereits jetzt für später empfehlen würde)

@Geri:
Wenn das Problem noch aktuell ist, will ich dir noch schnell mal ne grobe Anleitung schreiben:
  • Nimm die Deklaration deiner Klassen (der Teil, der in Delphi im Interface-Teil steht) und kopier ihn in die Zwischenablage
  • Im Download-Paket gibt es im Ordner "main program\bin" eine vorkompilierte Exe, die einen Exporter zur Verfügung stellt. Einfach öffnen
  • Dort erstellst du einen neue Unit und setzt den Unit-Namen auf irgendwas (also "unit [der Name]; begin; end;")
  • Dann fügst du Zwischenablage ein und löscht alles, was im Private oder im Protected-Teil steht - darauf hast du von der Script-Engine sowieso keinen Zugriff
  • Ersetze jeden Constructor durch eine Funktion, die als Return-Wert die entsprechende Klasse hat ("function Create: TKlasse")
  • Lösche den destructor aus dem Script-Quelltext
  • Passe gegebenfalls den Quelltext an, so dass er sich kompilieren lässt
  • Gehe auf "File" - "Open" und öffne die Datei "FormatDelphiExportFunction.scs"
  • Wechle wieder zurück auf deine gerade bearbeitet Unit und wähle unter "Project" - "Export to Delphi Unit"
  • Beantworte die Frage mit ja
  • Kopiere den kompletten Quelltext, der in dem neuem Tab erstellt wurde und kopiere ihn in die Zwischenablage
  • Erstelle in deinem Delphi-Projekt eine neue Unit füge den Quelltext aus der Zwischenablage ein
  • Passe die Unit an, bis sie sich kompilieren lässt - FERTIG

Nun solltest du die Klassen in deinem Script verwenden können (uses-Einbindung nicht vergessen)

Am besten schaust du dir nochmal die Beispiele an, die mit beim Download dabei sind

Viele Grüße

EugenB 25. Mär 2009 14:39

Re: Sysygy Script Engine - Version 0.99h
 
Huhu

gibt es schon irgendwelche Updates, nutzbare Versionen o.ä?

MfG
Eugen

littleDave 25. Mär 2009 15:42

Re: Sysygy Script Engine - Version 0.99h
 
Zitat:

Zitat von EugenB
Huhu

gibt es schon irgendwelche Updates, nutzbare Versionen o.ä?

MfG
Eugen

Hallo EugenB

Also benutzbare Versionen gibt es noch nicht. Aber ich komme gut vorran. Ich kann ja mal schnell nen Status-Update machen:

Also der Compiler ist schon sehr weit fortgeschritten. Ich habe schon einen Unit-Cache eingebaut, was die Compile-Performance schon mal extrem verbessert: wenn man ein Script kompiliert, werden alle benutzen Units erstmal kompiliert. Sind diese erfolgreich kompiliert, werden diese Daten in einen Binärstream (im Moment im Speicher) gespeichert. Wird das Script jetzt nochmal neu kompiliert, werden die verwendeten Units nicht nochmal kompiliert sondern direkt aus dem Cache geladen. Dadurch schaff ich es, relativ "einfache" Scripts in ca. 20 ms zu kompilieren. Das ist natürlich sehr Vorteilhaft für die Code-Completion. Diese habe ich jetzt auch noch erweitert, so dass es jetzt eine Code-Completion und eine Param-Completion gibt (in Delphi Strg+Shift+Leertaste). Das funkioniert bisher ganz prima.

Ein weiterer wichtiger Punkt ist die Run-Performance. Diese hab ich schon mal extrem verbessert. Hier mal eine kleine Tabelle (die einzelnen Test stehen unter der Tabelle), bei der ich die alte Script-Engine mit Pascal Script und mit meiner aktuellen vergleiche (alle Angaben in Sekunden)
Code:
-          Sysygy Script Engine  Pascal Script         ScriptEngine2
Test 1     4,76                   0,8                    0,9
Test 2     7,40                   1,6                    1,89
Test 3     12,75                  2,3                    2,8
Test 4     14,22                  8,44                   4,3
Test 5     26,10                  16,81                  8,7
Test 6     38,17                  25,21                  13,3
Test 7     31,39                  26,27                  11,0
Test 8     66,00                  52,61                  22,0
Test 9     99,10                  79,08                  33,0
-----------------------------------------------------------------------
Gesamt    299,89                 213,12                 97,89
Die einzelnen Test sind die Ausführungsgeschwindigkeiten von unterschiedlichen Scripten.
Test 1
Delphi-Quellcode:
program Test;

var i: integer;
begin
  for i:=0 to 1000000 do ;
end.
Test 2
Wie Test 1, nur zählen bis 2000000

Test 3
Wie Test 1, nur zählen bis 3000000

Test 4
Delphi-Quellcode:
program Test;

var i: integer;
begin
  for i:=0 to 1000000 do
  begin
    if i mod 2 = 0 then begin end;
    if i mod 3 = 0 then begin end;
    if i mod 4 = 0 then begin end;
  end;
end.
Test 5
Wie Test 4, nur zählen bis 2000000

Test 6
Wie Test 4, nur zählen bis 3000000

Test 7
Delphi-Quellcode:
program Test;

var i: integer;
begin
  for i:=0 to 1000000 do
  begin
    if i mod 2 = 0 then begin end;
    if i mod 3 = 0 then begin end;
    if i mod 4 = 0 then begin end;
    if i mod 5 = 0 then begin end;
    if i mod 6 = 0 then begin end;
    if i mod 7 = 0 then begin end;
    if i mod 8 = 0 then begin end;
    if i mod 9 = 0 then begin end;
    if i mod 10 = 0 then begin end;
  end;
end.
Test 8
Wie Test 7, nur zählen bis 2000000

Test 9
Wie Test 7, nur zählen bis 3000000

Wie man Anhand den Zeiten sieht, habe ich die Script-Engine gerade für komplexe Aktionen optimiert. Bei einer einfachen for-Schleife ist Pascal-Script noch ein wenig besser als meine Script-Engine. Sobald ich dann aber was in der for-Schleife mache, ist meine Script-Engine bei weitem schneller als Pascal-Script (und sowieso schneller als meine alte Script-Engine).

Dies erreiche ich vorallem durch einen eingebauten Memory-Manager in die Script-Engine. Dieser Memory-Manager ist dabei nicht ein Carbage Collector für die Script-Variablen - meine Script-Engine wird erstmal keinen Managed-Code benutzen. Ein weiterer Performance-Schub ist der eingebaute Linker, der den erstellen Byte-Code noch optimiert.

Mit dem Standard-Unit-Import komme ich auch schon ganz gut vorran. Bisher habe ich schonmal fast alle Funktionen der Unit Math eingebaut. Auch fast alle String-Operationen sind bereits eingebaut. Ach ja, DateTime wird auch kopmlett unterstützt (inklusive der Unit DateUtils). Da die Script-Engine ermöglicht, Units über mehrere Dateien zu spannen, muss man die einzelnen Units nicht mühsam einbinden.

Hier mal ein kleines Demonstations-Script:
Delphi-Quellcode:
program Test;

var i: integer;
    d: TDateTime;
begin
  // Aktuelles Datum ausgeben
  d := DateTime.Now;
  Console.WriteLine(DateTime.DateTimeToStr(d));
 
  // Ne Schleife
  for i:=0 to 5 do
    // Overload-Test
    Console.Write(i);
                     
  // Noch ein Overload-Test
  Console.WriteLine();      
  // Eine Funktion aus Math
  Console.WriteLine(Math.Max(5.0, 10.0));
  // Eine Convert-Routine
  Console.WriteLine(Convert.BoolToStr(False, True));
 
  // Oder einfach nur nen String
  Console.WriteLine('Ende');
 
  Console.ReadKey;
end.
Das Ergebnis:
Code:
25.10.2009 16:33:24
012345
10
False
Ende
Also es geht wirklich gut vorran. Was ich jedoch noch nicht gemacht habe ist: records, array, OOP, ... Es wird also noch ne ganze weile dauern, jedoch wenns so gut weitergeht, nicht mehr all zu lange ;-).

So, das war jetzt erstmal nen kleiner Status-Update. Sobald es wieder was wichtiges gibt, werd ich mich wieder melden.

Grüße
Dave


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:53 Uhr.
Seite 6 von 9   « Erste     456 78     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz