Einen Interpreter in einen Compiler konvertieren?

8

Zunächst einmal weiß ich, dass dies eine Frage ist, die von VIELEN anderen Programmierern vor mir gestellt wurde. Aber ich konnte keine brauchbare Ressource finden, die mir helfen könnte.

Nun, ich erstelle eine Programmiersprache namens "Light". Die Syntax ist vergleichbar mit Python, hat aber ein striktes objektorientiertes Konzept.

Ich habe noch einen Interpreter (in C ++) für diese Sprache erstellt. Mein Problem ist, wie ich daraus eine ausführbare Datei machen kann. (Oder einfach: Wie mache ich einen Compiler?)

Danke für Ihre Aufmerksamkeit

PS: Ich habe einige Links zu einem sehr alten Tutorial gefunden, aber es ist in Pascal ...

EDIT: Gut, gut. Jetzt habe ich ein passendes Tutorial für C ++ gefunden. Über das Projekt: Es wurden einige Änderungen vorgenommen. Jetzt heißt die Sprache "Q". (kju Dot).

LaVolpe
quelle
Lernen Sie zuerst die Zielsprache und sehen Sie dann, wie Sie die grundlegenden Codeblöcke aus Ihrer Sprache in die andere Sprache übersetzen würden
Ratschenfreak
1
Versuchen Sie "nur", einen Compiler zu schreiben (mit dem Hintergrundwissen aus der vorherigen Implementierung eines Interpreters für dieselbe Sprache), oder versuchen Sie buchstäblich, Ihren Interpreter in einen Compiler zu verwandeln? Ihre Formulierung gibt mir Ideen ;-)
4
Eine Futamura-Projektion?
Dan D.
1
Das ist trivial - spezialisieren Sie Ihren Interpreter einfach auf einen bestimmten Quellcode, um dessen kompilierte Version zu erhalten.
SK-Logik
Die Frage
bezieht sich auf

Antworten:

12

Die ersten Schritte zum Lexen / Parsen (und zur Analyse, je nachdem, wie diese strukturiert sind) können gleich sein. Sie müssen Ihre Darstellung jedoch in eine Code-generierende Darstellung konvertieren. Normalerweise wird LLVM für Hobbyisten verwendet, da es so ziemlich die einzige entfernt anständige kostenlose Code-generierende Bibliothek ist.

DeadMG
quelle
Genau das wollte ich schreiben, aber du hast es zuerst geschafft. Habe eine +1.
Mason Wheeler
3
Falsch. Das einfache Ausgeben von C (oder C ++ oder was auch immer) ist für Hobby-Compiler-Projekte viel beliebter. LLVM ist viel komplizierter. Und JVM oder .NET sind für diesen Zweck nicht schlechter als LLVM.
SK-Logik
Diese Compiler erzeugen keine ausführbaren Dateien, die das OP wünscht. Was .NET / JVM betrifft, hängt es wirklich von der Semantik seiner Sprache ab.
DeadMG
1
@DeadMG ghczum Beispiel ist perfekt in der Lage, ausführbare Dateien über C zu erstellen . Ebenso wie Hunderte anderer C-basierter Compiler. Verbietet Ihnen Ihre Religion die Verwendung popen(...)in einem Compiler? Dann muss man sich wegwerfen gcc. Im Gegensatz zu JVM kann .NET aufgrund seiner unsicheren Funktionen eine Vielzahl von Semantiken abdecken.
SK-Logik
Ich habe LLVM (mit Python-Bindungen) verwendet und es hat wie ein Zauber funktioniert. :)
LaVolpe
4

Wenn Sie wirklich nur eine ausführbare Datei benötigen, können Sie das Skript an das Ende einer ausführbaren Interpreter-Datei anhängen und ausführen lassen.

Siehe: /programming/5795446/appending-data-to-an-exe

Alternativ kann der Interpreter den Code einfach aus einer Datei im selben Verzeichnis wie der Interpreter laden und mit mehreren Dateien weitgehend das gleiche Ergebnis erzielen.

Ein echter Compiler würde den Code in eine andere Sprache konvertieren und den Compiler für diese Sprache verwenden. Wenn Sie jedoch nur ausführbare Dateien verteilen möchten, müssen Sie dies nicht tun.

Winston Ewert
quelle
Nun, ich kenne diese Art des Packens :) habe sie für Python verwendet (bevor ich von py2exe gehört habe). Für mich ist das Betrug und das andere Problem ist die Leistung. Meine Sprache, wie sie jetzt ist, ist niedrig, ABER streng objektorientiert.
LaVolpe
es macht Compiler nicht definitiv, nur Interpreter einbetten
Dmitry Ponyatov
1
@DmitryPonyatov, Sie hatten das Bedürfnis, fast sieben Jahre später zu kommentieren, was ich bereits in meiner Antwort gesagt hatte?
Winston Ewert
3

Möglicherweise möchten Sie auch System.Reflection.Emit aus der .NET-Laufzeit verwenden, um eine ausführbare .NET-Datei zu generieren. Auf diese Weise erhalten Sie Zugriff auf eine vorhandene objektorientierte Umgebung, die bereits einige Probleme für Sie gelöst hat, und die resultierende Exe kann plattformunabhängig sein. Die Laufzeit kompiliert den Zwischencode in der EXE-Datei nach Bedarf in Maschinencode, sodass die Leistung mit der Leistung vergleichbar sein sollte, die Sie beim direkten Kompilieren in nativen Code erhalten würden.

Vincent Povirk
quelle
Wahrscheinlich eine nette Idee, aber ich habe meine Sprache irgendwann so gestaltet, dass sie auf niedrigem Niveau ist;) Jetzt versuche ich, die Intel-Dokumentation von OpCodes zu durchsuchen.
LaVolpe
0

Sie fragen nach der als "Tracing-Compiler" bekannten Technik: Der Interpreter sammelt Informationen zur Codeausführung und erstellt schrittweise Code auf niedriger Ebene unter Verwendung der gesammelten Daten.

https://en.wikipedia.org/wiki/Tracing_just-in-time_compilation

https://stefan-marr.de/papers/oopsla-marr-ducasse-meta-tracing-vs-partial-evaluation/

Der Unterschied zur klassischen JIT besteht in der Tatsache, dass gesammelte Ablaufverfolgungsdaten und kompilierter Code bei jedem Programmlauf erhalten bleiben, wodurch Sie nicht nur ausführbaren Maschinencode erhalten, sondern auch echte (oder Trainings-) Daten optimieren können. Der erste Durchgang besteht aus einer Reihe von Tests, die alle Programmzweige bestehen müssen, um Code für jeden Teil Ihres Programms zu erstellen. Die nächsten sind Programmläufe mit realen Daten (Produktionsnutzung), die Optimierungen sammeln und anwenden (z. B. Verzweigungsreihenfolge für die am häufigsten verwendeten Fälle).

Diese Methode ist viel komplexer zu implementieren als ein klassisches Compiler-Konstruktionsschema, daher wird sie nicht häufig verwendet, und es ist komplex, eine Reihe guter Tutorials zu finden, wie man einen ähnlichen Compiler ausführt.

Dmitry Ponyatov
quelle