Theorie: AutoIt3-Compiler

  • Durch aktuelle Postings hier im Forum überwinde ich mich jetzt mal und eröffne eine theoretische Diskusionsrunde.


    Ende 2014 Anfang 2015 habe ich mir überlegt welcher Aufwand betrieben werden muss um einen AutoIt3-Compiler schreiben zu können – und ich weiß es gab bereits einige Versuche. Im Forum habe ich mir viele Beiträge zu diesem Thema durchgelesen und denke das ein Codeparser, welcher Au3-Code nach FreeBasic portiert, die einfachste Möglichkeit darstellt einen Compiler bereitzustellen.

    Daher habe ich etwas Theoretisches erarbeitet: Die Umwandlung von AutoIt3-Code zu echten Binären-Code, durch vorige Portierung zu FreeBasic-Code und dessen anschließende Kompilierung… Ta-Ta!! Im Klartext bedeutet das das der Codeparser in AutoIt3 geschrieben wird und die Stammbefehle in FreeBasic gehalten sind, verbunden durch einer Art von Grammatik welche beide Sprachen interpretiert.
    Wie gehabt ist alles nur theoretischer Natur und sollte nur der Durchführungsweise und Inspiration dienen. Seit über 9 Monaten komme ich überhaupt nichtmehr zum Programmieren, und es ist auch keinerlei Besserung in Sicht – Daher die Offenlegung meiner Projekt-Sichtung ;) Aber zur Diskusionsgrundlage ist das Thema durchaus geeignet und es werden bestimmt viele gute Ideen in diesem Thread einfließen.

    Warum ein Coderparser und keine echter Compiler?? Ein Codeparser soll Sprache 1 (AutoIt3) nach Sprache 2 (FreeBasic) auf Basis einer Grammatik portieren – Die Kompilierung erfolgt anschließend durch den FreeBasic-Compiler. Das wird die einfachste Möglichkeit darstellen AutoIt3 von seinem Interpreter lösen zu können OHNE Einsicht in den ursprünglichen AU3 Quellcode haben zu können (dieser ist ja unter Verschluss). Denn ohne diesen Quellcode ist es unmöglich einen “echten“ AutoIt3-Compiler zu schreiben, deswegen der Zwischenschritt Au3 nach FB zu parsen.


    Die Basis des Codeparser sind seine in FreeBasic geschriebenen und im Funktionsumfang 1:1 gehaltenen AutoIt-Keywords (incl. Macros) welche ein identisches Verhalten aufweisen müssen wie dessen Vorlagen, das sind unsere Stammbefehle. Sind alle Stammbefehle vollständig Funktionstüchtig werden die gesamten AutoIt3 Funktionen und UDF´s durch die Parserlogik zu FreeBasic-Code portiert und stellen somit die Ac3-Includes bereit, welche dann in unseren Au3-Scripten vom Parser zur Portierung verwendet werden. Es müssen also alle Funktionen die AutoIt3 bereitstellt bereits zu Ac3-Includes geparst worden sein, damit die ursprünglichen Includes in unseren Skripten durch die Ac3 Pendaten ersetzen werden, nach unserem geparsten Skript sollte der AutoIt-Code 1:1 in FreeBasic vorliegen und Kompiliert werden können – Theoretisch :D

    Hat man alle Stammbefehle ermitteln können, könnte man diese in jeder Sprache interpretieren und mit der gleichen Methode AutoIt3 komplett “Nachschreiben“ – Alles in AutoIt3 basiert auf Verkettung dieser Stammbefehle! “Spaßeshalber“ habe ich mir die Arbeit gemacht 505 Stammbefehle zu lokalisieren und für diese entsprechende FB-Header vorbereitet – Zur Übersichtsgewinnung des Arbeitsaufwandes. Ich habe alle Funktionen in den Headern deklariert und als Funktions-Dummys vorbereitet, den Rückgabe-Typ ermittelt, alle Übergabe-Parameter und dessen Typen berücksichtigt und sogar die Texte aus der Hilfedatei in die Funktionen eingefügt - damit jeder nachvollziehen kann was diese Funktion machen muss… Aber wie immer bei so einer großen Masse an anfallenden Funktionen hat sich wohl hier und da der Schlendrian eingeschlichen, außerdem dient es nur zur Verdeutlichung. Alles im Anhang einzusehen.


    Der Codeparser muss sehr individuell Aufgebaut sein, mit einer raffinierten Parserlogik damit auch unsauberer Code und unterschiedliche Programmierstile erfassbar sind. Außerdem ist ein ständiges Auge auf die Syntaxunterschiede beider Sprachen zu werfen, das kann durchaus sehr Tricky werden. Als ich die Stammbefehle lokalisierte bekam ich schon bedenken weil die Dialekte teils gravierende Unterschiede haben, welche der Parser später ja automatisch kompensieren muss. Dialektspezifisch ist beispielsweise in FreeBasic die Rückgabe einer Stuct oder Array nur durch einen ByRef Funktionsparameter möglich, in Au3 wird ein Array einfach am Funktionsende “Returned“ – das könnte recht einfach umgangen werden indem alle Befehle einfach den ersten Funktionsparameter als Returner verwenden. Aber dieses ist nur ein Beispiel von vielen, man sehe sich nur die Funktion “DllCall()“ an diese kann jeden denkbar möglichen Typen wiedergeben. Es ist also reichlich Hirnschmalz gefragt! Die Parserlogik interpretiert beide Sprachen basierend auf einer “Grammatik“ zu einem lauffähigen Code welcher anschießend kompiliert werden kann…


    Was denkt ihr was es alles zu Berücksichtigen gibt eine halbwegs “echte“ Compiler-Umgebung für unseren AutoIt3-Code erstellen zu können? Welche Innovationen erhofft ihr euch dadurch, welches Problem würde den Genickbruch eines solchen Vorhabens darstellen - abgesehen von dem immensen Arbeitsaufwand?? Alleine kann man so ein Projekt nicht stemmen, wenn sich aber eine kleine Gruppe findiger Programmierer auffindet die das unter sich klar machen – sehe ich durchaus eine realistische Möglichkeit den AutoIt3 Dev´s mal kräftig in den Poppes zu treten :D


    Pro:

    • Alle Compilerflags des FB-Compiler könnten auch manuell in unseren Scripten verwendet werden (aus “-arch < type >“ wird “#FreeBasicCompiler=-arch < type >“).
    • Das Threading aus FreeBasic könnte in Au3 Verwendung finden, es müsste nur über eine kleine UDF integriert werden.
    • Es könnte ein “Varianthebel“ eingebaut werden, damit eben der Typ Variant ausgehebelt werden kann, und somit alle Variablen Typisiert werden müssen.
    • Es könnten DLL´s aus Au3-Code erstellt werden.
    • Der Geschwindigkeitszuwachs sollte in Teilbereichen enorm ausfallen.
    • Das De-Kompilieren von Au3-Programmen sollte dank des geparsten Code´s auch kein Thema mehr sein.

    Contra:

    • Der Variant... Dieser ist unglaublich praktisch aber da Code nach FB portiert werden soll ist er auch kontraproduktiv. Es muss eine Möglichkeit gefunden werden mit diesem umzugehen…
    • Die Dialektinterpretation zwischen Au3 und FB könnte je nach Programmierstil kompliziert ausfallen.
    • Alle Stammbefehle müssen 1:1 mit deren Au3 Vorbildern kompitabel sein! Ebenso müssen die erstellten AutoIt3 Funktionen und UDF´s lauffähig sein. Das bedeutet einen riesen Aufwand…
    • Dialektspezifische Unterschiede beider Sprachen durch ausgefeilter Parserlogik kompensieren.

    Infos:

    AutoIt zu C
    Bleb AutoIt-Compiler
    Funktionssammlung AutoIt


    Ich freue mich auf eine rege Diskusion,
    Grüße von Techmix!

  • Die Dialektinterpretation zwischen Au3 und FB könnte je nach Programmierstil kompliziert ausfallen.

    Im Normalfall sollte das Parsen in keiner Weise davon abhängen in welchem "Stil" jemand programmiert. Das Parsen hängt einzig und allein von der Spezifikation der geparsten Sprache ab. Im Normalfall beschreibt man eine Sprache mit Hilfe einer kontextfreien Grammatik. Ist man einmal im Besitz dieser, ist das Schreiben eines Parsers wirklich kein Porblem mehr, bzw. gibt es fertige Software die aus einer kontextfreien Grammatik einen performanten Parser baut.
    Die Entwickler von Autoit sollten im Besitz einer solchen Grammatik für die Sprache Autoit3 sein, jedoch bezweifle ich, dass sie dir diese aushändigen um einen Übersetzer zu bauen.
    Somit sehe ich zunächst einmal das Kernproblem darin eine solche Grammatik zu definieren, die dann auch exakt der originalen entspricht. Des weiteren wirst du wie du selbst schon angemerkt hast, Autoit des Variant-Datentyps berauben müssen, was ohne Veränderung/Annotation der originalen Autoit-Syntax nicht möglich sein wird.
    Insgesamt wird dieses Übersetzer-Projekt also - zumindest meiner Meinung nach - einen Aufwand ähnlich dem des Entwickelns einer komplett neuen Sprache haben. An diesem Punkt kann man sich nun die Frage stellen ob man sich den "Klotz" Autoit3 denn wirklich ans Bein binden möchte...
    Just my 2 cents :)

    LG
    Christoph :)

  • Genau die gleiche Idee ist vor einiger Zeit doch schonmal aufgetaucht. Was wir damals festgestellt hatten (und die ich noch im Kopf habe) waren folgende:
    [1] - Native Befehle/Macros (GuiCreate, ConsoleWrite, @DesktopWidth, usw usw) müssten in FB implementiert werden ohne dass wir "hineinschauen" können wie diese Befehle intern funktionieren.
    [2] - Die Grammatik (wie oben schon gesagt) muss bekannt sein, damit man von normaler Au3-Syntax zur FB-Syntax wechseln kann.
    [3] - UDFs, verschiedene Programmierstile, usw sind vollkommen egal. Vor dem Kompilieren werden sowieso alle Daten in einem einzigen Skript zusammengefasst, das nach Punkt 2 Übersetzbar ist.
    [4] - Sollte man den Variant-Typ zuverlässig behandeln wird es große Geschwindigkeitseinbußen geben. (Vor jeder Berechnung prüfen wie die Datentypen sind und ggf. casten)
    [5] - DllStructs können wie ein normales Array (mit vorgegebenem Datentyp) verwendet werden, da das in FB Äquivalent gestaltet werden kann, oder umgekehrt. In AutoIt sind normale Arrays aber auf wundersame Weise überall im Speicher verteilt, sodass es keine Arraypointer oder Direktzugriffe gibt.
    [6] - Für auftretende Einschränkungen (die es auf jeden Fall geben wird, da man nicht 100% der Sprache einfach so übersetzen kann) muss ein Au3Check ähnliches Skript geschrieben werden um zu überprüfen ob das Skript nach FB übersetzbar ist.

    Sachen für das Variantproblem waren:
    [1] - Alle Variablen eindeutig deklarieren (MustDeclareVars zur Pflicht machen reicht aus, damit implizit alle Datentypen festgelegt sind). Damit kann der Übersetzer an vielen Stellen bereits feststellen wo gecastet werden muss, sodass das Überprüfen zur Laufzeit wegfällt.
    [2] - Komplett auf Variant verzichten und in AutoIt manuell "casten" z.B. $a = 5.0, $b = 2. Es wird aus $c = $a + $b ein $c = Int($a) + $b, sodass $c eindeutig ein Integer ist, oder $c = $a + Float($b), sodass $c eindeutig Float ist.
    [3] - Funktionen einen eindeutigen Rückgabewert zuweisen. "Func ... Endfunc ; Typ", z.B. "Endfunc ; Int" gibt immer einen Integer zurück. (Kann etwas Arbeit sparen)
    [4] - Einen "Behälter" (der jeden Datentyp enthalten kann) für Funktionsparameter benutzen, damit Funktionen nicht überladen werden müssen.

    Die Liste ist bei weitem nicht vollständig, das sind nur die Sachen die mir direkt zu dem Thema eingefallen sind. Weiterhin weiß ich, dass minx sich auch schonmal an etwas ähnlichem versucht hat (mit seiner selbst gebastelten kompilierbaren Sprache Perseus), wie weit die Entwicklung dort fortgeschritten war weiß ich nicht.

    lg
    M

  • Ich frage mich, warum der ganze Aufwand von Au3 - > FB, abgesehen vom masochistischen Verlangen?

    Da FB keine komplizierte Sprache ist und man sie relativ einfach erlernen kann, gehe ich persönlich eher einen anderen Weg.
    Entweder ich schreibe in FB eine DLL, die ich in AutoIt benutze (z.B. _GDIPlus_BitmapApplyFilter v0.9.5 build 2016-07-14 beta) oder ich schreibe gleich in FB (Battle: Autoit vs. FreeBasic - Runde 1+2+3).

    Meine Meinung: das Konzept Au3 - > FB ist nichts Ganzes, nichts Halbes. Im engl. Forum gibt es den Ansatz Au3 -> C/C++ -> https://www.autoitscript.com/forum/topic/180595-au4-library/

    Viel SM Spaß. :D

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Ich sehe das genau wie UEZ.

    Natürlich wäre ein (auch eingeschränkter) AutoIt-Compiler eine feine Sache, aber wozu? Schnelleren Code erzeugen? In 99% aller Fälle unnötig. Kleinere Files erzeugen? In 99% aller Fälle unnötig.
    Reputation? Lächerlich, sämtliche "Gegner" eines solchen Projekts (ihr wisst, wo diese sitzen) würden ALLES dafür tun, dieses Projekt runterzuziehen...

    Wenn ich schnellstmöglichen Code benötige, dann bediene ich mich für diesen Codeteil (!) einer Dll/AssembleIt/OpenCL. Oder benutze eine andere Programmiersprache!
    An kleineren EXE´s hatte ich in den letzten Jahren absolut keinen Bedarf. Vielleicht wird das aber mit Blick auf kommende x86-IoT-Devices ein Grund.