Welche Arten von Mustern könnte ich für den Code erzwingen, um die Übersetzung in eine andere Programmiersprache zu erleichtern? [geschlossen]

95

Ich mache mich auf den Weg zu einem Nebenprojekt, das das Ziel hat, Code von einer Programmiersprache in eine andere zu übersetzen. Die Sprachen, mit denen ich anfange, sind PHP und Python (Python zu PHP sollte einfacher zu beginnen sein), aber im Idealfall könnte ich andere Sprachen mit (relativer) Leichtigkeit hinzufügen. Der Plan ist:

  • Dies ist auf die Webentwicklung ausgerichtet. Der Original- und Zielcode wird auf Frameworks sitzen (die ich auch schreiben muss). Diese Frameworks umfassen ein MVC-Entwurfsmuster und folgen strengen Codierungskonventionen. Dies sollte die Übersetzung etwas erleichtern.

  • Ich beschäftige mich auch mit IOC und Abhängigkeitsinjektion, da sie den Übersetzungsprozess möglicherweise einfacher und weniger fehleranfällig machen.

  • Ich werde das Parser-Modul von Python verwenden , mit dem ich mich mit dem abstrakten Syntaxbaum beschäftigen kann. Anscheinend ist token_get_all () das Beste , was ich mit PHP erreichen kann , was ein Anfang ist.

  • Von da an kann ich den AST, die Symboltabellen und den Kontrollfluss erstellen.

Dann glaube ich, dass ich anfangen kann, Code auszugeben. Ich brauche keine perfekte Übersetzung . Ich muss den generierten Code noch überprüfen und Probleme beheben. Idealerweise sollte der Übersetzer problematische Übersetzungen kennzeichnen.

Bevor Sie fragen "Was zum Teufel ist der Sinn davon?" Die Antwort lautet ... Es wird eine interessante Lernerfahrung. Wenn Sie Einblicke haben, wie Sie dies weniger entmutigen können, lassen Sie es mich bitte wissen.


BEARBEITEN:

Ich bin mehr daran interessiert zu wissen, welche Arten von Mustern ich für den Code erzwingen könnte, um die Übersetzung des Codes zu vereinfachen (dh IoC, SOA?), Als wie die Übersetzung durchgeführt wird.

NullUserException
quelle
6
Haben Sie sich Systeme wie .NET CLR oder Perl6's Parrot angesehen? Sie kompilieren eine Reihe von Sprachen bis hin zu einer Zwischendarstellung, die von einem gemeinsamen Interpreter ausgeführt werden kann. Wenn Sie von der Zwischendarstellung zu einer Sprache zurückkehren können, haben Sie einen Übersetzer.
Borealid
1
@Borealid AFAIK .NET CIL ist (relativ) leicht zu kompilieren in , aber viel Glück immer aus , dass lesbaren Code zurück. Jetzt Papagei anschauen.
NullUserException
Es gibt ähnliche Projekte für andere Sprachen; Ich bin mir nicht sicher, wie reich ihre Autoren sind. Und ich halte mich hier tatsächlich sehr zurück, indem ich ein Framework benötige und strenge Codierungskonventionen einhalte.
NullUserException
2
Ich kann kein spezifisches Wissen hinzufügen, aber haben Sie sich Pyjamas ( pyjs.org ) angesehen, insbesondere translator.py? Dies ist ein Python-zu-Javascript-Compiler.
stephan
3
Erneut BEARBEITEN: Wenn Sie die Kontrolle über den zu übersetzenden Code haben, ist es am naheliegendsten, schwer zu übersetzende Konstrukte zu vermeiden! Zum Beispiel ist C viel einfacher in Java zu übersetzen, wenn es keine Zeigerarithmetik gibt. Für Python würde ich mich wahrscheinlich von Schließungen fernhalten. Sie können den Quellcode auch so schreiben, dass schwieriger zu übersetzende Teile immer idiomatisch codiert werden, sodass sie leichter zu erkennen und Sonderfälle zu behandeln sind.
Ira Baxter

Antworten:

122

Seit 1995 baue ich Tools (DMS Software Reengineering Toolkit) für allgemeine Programmmanipulationen (wobei die Sprachübersetzung ein Sonderfall ist), die von einem starken Team von Informatikern unterstützt werden. DMS bietet generisches Parsen, AST-Erstellen, Symboltabellen, Steuerungs- und Datenflussanalyse, Anwendung von Übersetzungsregeln, Regeneration von Quelltext mit Kommentaren usw., die alle durch explizite Definitionen von Computersprachen parametrisiert werden.

Die Menge an Maschinen, die Sie benötigen, um dies gut zu machen, ist enorm (insbesondere, wenn Sie dies allgemein für mehrere Sprachen tun möchten), und dann benötigen Sie zuverlässige Parser für Sprachen mit unzuverlässigen Definitionen (PHP ist ein perfektes Beispiel dafür ).

Es ist nichts Falsches daran, wenn Sie darüber nachdenken, einen Sprachübersetzer zu bauen oder es zu versuchen, aber ich denke, Sie werden feststellen, dass dies eine viel größere Aufgabe für echte Sprachen ist, als Sie erwarten. Wir haben ungefähr 100 Mannjahre in nur DMS investiert und weitere 6-12 Monate in jede "zuverlässige" Sprachdefinition (einschließlich der, die wir schmerzhaft für PHP erstellt haben), viel mehr für böse Sprachen wie C ++. Es wird eine "verdammt gute Lernerfahrung" sein; es war für uns. (Möglicherweise finden Sie den Abschnitt "Technische Dokumente" auf der obigen Website interessant, um mit dem Lernen zu beginnen.)

Menschen versuchen oft, eine Art generalisierte Maschinerie zu bauen, indem sie mit einer Technologie beginnen, mit der sie vertraut sind und die einen Teil der Arbeit erledigt. (Python ASTs sind ein gutes Beispiel). Die gute Nachricht ist, dass ein Teil der Arbeit erledigt ist. Die schlechte Nachricht ist, dass in Maschinen zig Millionen Annahmen eingebaut sind, von denen Sie die meisten erst entdecken werden, wenn Sie versuchen, sie dazu zu bringen, etwas anderes zu tun. An diesem Punkt stellen Sie fest, dass die Maschine so verdrahtet ist, dass sie das tut, was sie ursprünglich getan hat, und dass sie Ihrem Versuch, etwas anderes zu tun, wirklich, wirklich widerstehen wird. (Ich vermute, dass der Versuch, Python AST zum Modellieren von PHP zu bringen, eine Menge Spaß machen wird).

Der Grund, warum ich ursprünglich mit dem Aufbau von DMS begonnen habe, war der Aufbau von Fundamenten, in die nur sehr wenige solcher Annahmen eingebaut waren. Einige haben Kopfschmerzen. Bisher keine schwarzen Löcher. (Der schwierigste Teil meiner Arbeit in den letzten 15 Jahren besteht darin, zu verhindern, dass sich solche Annahmen einschleichen.)

Viele Leute machen auch den Fehler anzunehmen, dass sie auf dem besten Weg sind, etwas Kompliziertes zu tun, wenn sie analysieren (und vielleicht einen AST bekommen) können. Eine der schwierigen Lektionen ist, dass Sie Symboltabellen und Flussanalysen benötigen, um eine gute Programmanalyse oder -transformation durchzuführen. ASTs sind notwendig, aber nicht ausreichend. Dies ist der Grund, warum das Compiler-Buch von Aho & Ullman nicht bei Kapitel 2 endet. (Das OP hat dieses Recht, da er plant, zusätzliche Maschinen über den AST hinaus zu bauen.) Weitere Informationen zu diesem Thema finden Sie unter Leben nach dem Parsen .

Die Bemerkung über "Ich brauche keine perfekte Übersetzung" ist problematisch. Schwache Übersetzer konvertieren die "einfachen" 80% des Codes und lassen die harten 20% von Hand erledigen. Wenn die Anwendung, die Sie konvertieren möchten, ziemlich klein ist und Sie sie nur einmal gut konvertieren möchten, sind diese 20% in Ordnung. Wenn Sie viele Anwendungen konvertieren möchten (oder sogar dieselbe mit geringfügigen Änderungen im Laufe der Zeit), ist dies nicht hilfreich. Wenn Sie versuchen, 100K SLOC zu konvertieren, sind 20% 20.000 ursprüngliche Codezeilen, die im Kontext weiterer 80.000 Zeilen übersetzter Programme, die Sie bereits nicht verstehen, schwer zu übersetzen, zu verstehen und zu ändern sind. Das ist sehr aufwändig. Auf der Ebene der Millionenleitungen ist dies in der Praxis einfach unmöglich.härter und sie finden es normalerweise schmerzhaft mit langen Zeitverzögerungen, hohen Kosten und oft völligem Versagen heraus.)

Was Sie fotografieren müssen, um große Systeme zu übersetzen, sind hohe prozentuale Conversion-Raten der neunziger Jahre, oder es ist wahrscheinlich, dass Sie den manuellen Teil der Übersetzungsaktivität nicht abschließen können.

Ein weiterer wichtiger Aspekt ist die Größe des zu übersetzenden Codes. Der Aufbau eines funktionierenden, robusten Übersetzers erfordert viel Energie, selbst mit guten Werkzeugen. Während es sexy und cool erscheint, einen Übersetzer zu erstellen, anstatt einfach eine manuelle Konvertierung durchzuführen, rechtfertigt die Wirtschaftlichkeit dies für kleine Codebasen (z. B. bis zu etwa 100.000 SLOC nach unserer Erfahrung) einfach nicht. Niemand mag diese Antwort, aber wenn Sie wirklich nur 10K SLOC Code übersetzen müssen, ist es wahrscheinlich besser, nur die Kugel zu beißen und es zu tun. Und ja, das ist schmerzhaft.

Ich halte unsere Tools für extrem gut (aber dann bin ich ziemlich voreingenommen). Und es ist immer noch sehr schwer, einen guten Übersetzer zu bauen. Es dauert ungefähr 1,5-2 Mannjahre und wir wissen, wie man unsere Werkzeuge benutzt. Der Unterschied besteht darin, dass wir mit so viel Maschinerie wesentlich häufiger Erfolg haben als scheitern.

Ira Baxter
quelle
8
Haben Sie jemals darüber nachgedacht, Ihre "schmerzhaft aufgebaute" PHP-Definition wieder in die PHP-Community insgesamt einzubringen, oder sind Sie zu eng mit Ihrer eigenen Einnahmequelle verbunden, um dies möglich zu machen?
TML
53
Ich wurde von vielen Leuten gebeten, alles, was wir tun, zu "Open Source" zu machen, die nicht zu einer Einnahmequelle beitragen wollten und nicht die Energie hatten, die Arbeit zu erledigen und sie selbst zu öffnen. Wenn Sie nur einen kleinen Teil zu einem sehr großen Projekt beitragen und / oder eine andere Einnahmequelle haben, scheint "Open Source" in Ordnung zu sein. Wenn Sie die ganze Arbeit selbst erledigt haben und es Ihre einzige Einnahmequelle ist, ist dies viel weniger attraktiv. [Ich möchte nicht in eine Diskussion über die relativen Vorzüge der Philosophie der "freien Software" geraten, daher werde ich an keinen weiteren Kommentaren in dieser Richtung teilnehmen]
Ira Baxter
9
Ich stimme dem zu, was Sie hier gesagt haben, weshalb ich die Frage so formuliert habe, wie ich es getan habe. Ich denke, wir sollten aus dieser Antwort verstehen, dass Sie der Meinung sind, dass sie zu eng mit Ihren Einnahmen verbunden ist, und daran ist absolut nichts auszusetzen - ich dachte nur, es lohnt sich zu fragen.
TML
3
@IraBaxter Sie sagen nur allgemeine Redewendungen über Computerpraktiken, die auf viele andere Praktiken angewendet werden können. Das einzige Interessante an allem, was Sie geschrieben haben, sind die Links zu semanticdesigns.com (das zufällig Ihr Unternehmen ist)
amirouche
1
In Ihren Antworten finden Sie häufig Links zu Clang-bezogenen Seiten. Das beweist nur, dass jemand anderes eine Webseite erstellen kann. Die meisten von uns gehen davon aus, dass eine gut geschriebene Webseite impliziert, dass ernsthafte, echte Arbeit dahinter steckt und nicht nur ein betrügerischer Versuch, den Leser zu täuschen, wie Sie in Ihrer Antwort zu implizieren scheinen. Glauben Sie tatsächlich, dass die Webseite betrügerisch ist? Die Seite enthält Referenzinformationen zur "relevanten" Quelle. es ist anonomisiert, weil der Vertrag für die Arbeit dies vorschrieb. Dass ich nicht helfen kann.
Ira Baxter
13

Meine Antwort wird sich mit der spezifischen Aufgabe befassen, Python zu analysieren, um es in eine andere Sprache zu übersetzen, und nicht mit den übergeordneten Aspekten, die Ira in seiner Antwort gut angesprochen hat.

Kurz gesagt: Verwenden Sie nicht das Parser-Modul, es gibt einen einfacheren Weg.

Das astseit Python 2.6 verfügbare Modul ist viel besser für Ihre Anforderungen geeignet, da es Ihnen einen vorgefertigten AST bietet, mit dem Sie arbeiten können. Ich habe einen Artikel über dieses letzte Jahr geschrieben, aber kurz gesagt, verwenden Sie die parseMethode ast, um Python-Quellcode in einen AST zu analysieren. Das parserModul gibt Ihnen einen Analysebaum, keinen AST. Seien Sie vorsichtig mit dem Unterschied .

Da die ASTs von Python ziemlich detailliert sind, ist der Front-End-Job angesichts eines AST nicht besonders schwierig. Ich nehme an, Sie können einen einfachen Prototyp für einige Teile der Funktionalität ziemlich schnell fertig haben. Das Erreichen einer vollständigen Lösung wird jedoch mehr Zeit in Anspruch nehmen, hauptsächlich weil die Semantik der Sprachen unterschiedlich ist. Eine einfache Teilmenge der Sprache (Funktionen, Grundtypen usw.) kann leicht übersetzt werden. Sobald Sie jedoch in die komplexeren Ebenen eingetreten sind, benötigen Sie schwere Maschinen, um den Kern einer Sprache in einer anderen zu emulieren. Betrachten Sie zum Beispiel Pythons Generatoren und Listenverständnisse, die in PHP nicht existieren (nach meinem besten Wissen, das zugegebenermaßen schlecht ist, wenn es um PHP geht).

Um Ihnen einen letzten Tipp zu geben, betrachten Sie das 2to3von den Python-Entwicklern erstellte Tool zum Übersetzen von Python 2-Code in Python 3-Code. In Bezug auf das Front-End enthält es die meisten Elemente, die Sie benötigen, um Python in etwas zu übersetzen . Da die Kerne von Python 2 und 3 jedoch ähnlich sind, ist dort keine Emulationsmaschinerie erforderlich.

Eli Bendersky
quelle
Weeeell. 2to3ist nur AST zu AST. Es wird nichts unterstützt, was über die Funktionen des astModuls hinausgeht . Beachten Sie, dass alle Übersetzungen gehen von Syntax durch den Host - Python - Prozess unterstützt Syntax durch den Host - Python - Prozess unterstützt. Es gibt keinen Übersetzer, der beispielsweise Funktionsanmerkungen hinzufügt, da 2.6 dies nicht unterstützt.
Hablabit
... und die Frage des OP könnte kurzfristig gestellt werden, wie man von Python 2.6 AST zu ... etwas in PHP kommt. Das ast-Modul möchte die PHP-Syntax wahrscheinlich nicht gut darstellen, daher ist es nicht einmal ast zu ast.
Ira Baxter
2
@Aaron: 2to3kann als Beispiel für die Verwendung des aus generierten AST angesehen werden ast.
Eli Bendersky
AFAIK, 2to3 ist wohl eine einfachere Übersetzung als Python zu PHP (schließlich Python zu Python, richtig)? Und selbst das funktioniert nicht besonders gut. Beachten Sie die große Menge an Python 2.6, die noch nicht durch 2to3 geschoben wurde ... da anscheinend noch eine Reihe von Hand-Patches nach der Übersetzung durchgeführt werden müssen. Wenn 100% automatisiert wäre, wäre Python 2.6 tot.
Ira Baxter
5

Einen Übersetzer zu schreiben ist nicht unmöglich, besonders wenn man bedenkt, dass Joels Praktikant es über einen Sommer getan hat.

Wenn Sie eine Sprache sprechen möchten, ist dies einfach. Wenn Sie mehr tun möchten, ist es etwas schwieriger, aber nicht zu viel. Der schwierigste Teil ist, dass, während jede vollständige Sprache das tun kann, was eine andere vollständige Sprache tut, integrierte Datentypen das, was eine Sprache phänomenal tut, ändern können.

Zum Beispiel:

word = 'This is not a word'
print word[::-2]

Das Duplizieren erfordert viel C ++ - Code (ok, mit einigen Schleifenkonstrukten kann man das ziemlich kurz machen, aber immer noch).

Das ist ein bisschen beiseite, denke ich.

Haben Sie jemals einen Tokenizer / Parser geschrieben, der auf einer Sprachgrammatik basiert? Sie werden wahrscheinlich lernen wollen, wie das geht, wenn Sie es nicht getan haben, denn das ist der Hauptteil dieses Projekts. Was ich tun würde, ist eine grundlegende vollständige Turing-Syntax zu entwickeln - etwas, das dem Python- Bytecode ziemlich ähnlich ist . Anschließend erstellen Sie einen Lexer / Parser, der eine Sprachgrammatik verwendet (möglicherweise mit BNF ) und die Sprache basierend auf der Grammatik in Ihre Zwischensprache kompiliert. Dann möchten Sie das Gegenteil tun - erstellen Sie einen Parser aus Ihrer Sprache in Zielsprachen basierend auf der Grammatik.

Das offensichtlichste Problem, das ich sehe, ist, dass Sie wahrscheinlich zuerst schrecklich ineffizienten Code erstellen , insbesondere in leistungsfähigeren * Sprachen wie Python.

Wenn Sie dies jedoch auf diese Weise tun, können Sie wahrscheinlich Wege finden, um die Ausgabe im Laufe der Zeit zu optimieren. Zusammenfassen:

  • Lesen Sie die bereitgestellte Grammatik
  • Kompilieren Sie das Programm in die Zwischensyntax (aber auch in die vollständige Turing-Syntax)
  • Zwischenprogramm in die endgültige Sprache kompilieren (basierend auf der bereitgestellten Grammatik)
  • ...?
  • Profitieren!(?)

* Mit mächtig meine ich, dass dies 4 Zeilen dauert:

myinput = raw_input("Enter something: ")
print myinput.replace('a', 'A')
print sum(ord(c) for c in myinput)
print myinput[::-1]

Zeigen Sie mir eine andere Sprache, die so etwas in 4 Zeilen kann, und ich zeige Ihnen eine Sprache, die so mächtig ist wie Python.

Wayne Werner
quelle
"Haben Sie jemals einen Tokenizer / Parser geschrieben, der auf einer Sprachgrammatik basiert?" Ich habe es mit JavaCC gemacht.
NullUserException
2
Joels Praktikant hat über einen Sommer einen Teiljob gemacht. Seine Ausgangssprache war eine Teilmenge einer vorhandenen Sprache, und vermutlich konnte diese Teilmenge etwas angepasst werden. Das macht die Arbeit viel einfacher. In ähnlicher Weise möchte NullPointerException möglicherweise mit den einfacheren Teilen von Python beginnen und möglicherweise die schwierigeren Dinge für die manuelle Konvertierung durchlaufen (wie in den Fragen angegeben).
David Thornley
@NullUserException: Sie werden etwas exponiert sein, aber Sie werden im Grunde eine Neuimplementierung von JavaCC durchführen, nur anstelle von Java als Ausgabesprache werden Sie <Sprache hier einfügen> ausführen. @ David, ganz so. Sogar Thistle braucht Hilfe bei einigen Sprachkonstrukten. Wenn ich das OP wäre, würde ich zuerst funktionsfähig sein und dann optimieren, sonst würde ich für immer stecken bleiben und versuchen, C ++ dazu zu bringen, String-Slicing (mit Schritten) durchzuführen: p
Wayne Werner
@WayneWerner Für die Aufzeichnung benötigen Sprachen wie C # überhaupt keine Zeilenumbrüche. (Zumindest nicht, nachdem Sie die einzeiligen Kommentare entfernt haben.) Sie können also jedes C # -Programm in eine Zeile schreiben. Aber natürlich verstehe ich, worauf du hinaus willst.
Leviathanbadger
@ Aboveyou00: Ich denke nicht, dass das richtig ist. Wenn Sie Präprozessor-Bedingungen nicht zulassen, haben Sie möglicherweise Recht.
Ira Baxter
3

Es gibt ein paar Antworten, die Ihnen sagen, dass Sie sich nicht darum kümmern sollen. Wie hilfreich ist das? Du willst lernen? Du kannst lernen. Dies ist eine Zusammenstellung. Es kommt einfach so vor, dass Ihre Zielsprache kein Maschinencode ist, sondern eine andere Hochsprache. Dies geschieht ständig.

Es gibt einen relativ einfachen Weg, um loszulegen. Rufen Sie zuerst http://sourceforge.net/projects/lime-php/ (wenn Sie in PHP arbeiten möchten) oder ähnliches auf und gehen Sie den Beispielcode durch. Als Nächstes können Sie einen lexikalischen Analysator mit einer Folge von regulären Ausdrücken schreiben und Token an den von Ihnen generierten Parser senden. Ihre semantischen Aktionen können entweder Code direkt in einer anderen Sprache ausgeben oder eine Datenstruktur (Think Objects, Man) aufbauen, die Sie massieren und durchlaufen können, um Ausgabecode zu generieren.

Sie haben Glück mit PHP und Python, weil sie in vielerlei Hinsicht dieselbe Sprache sind, aber unterschiedliche Syntax haben. Der schwierige Teil besteht darin, die semantischen Unterschiede zwischen den Grammatikformen und Datenstrukturen zu überwinden. Zum Beispiel hat Python Listen und Wörterbücher, während PHP nur Assoc-Arrays hat.

Der "Lerner" -Ansatz besteht darin, etwas zu erstellen, das für eine eingeschränkte Teilmenge der Sprache in Ordnung ist (z. B. nur Druckanweisungen, einfache Mathematik und Variablenzuweisung), und dann schrittweise Einschränkungen zu entfernen. Das ist im Grunde das, was die "großen" Leute auf dem Gebiet alle getan haben.

Oh, und da Sie in Python keine statischen Typen haben, ist es möglicherweise am besten, PHP-Funktionen wie "python_add" zu schreiben und sich darauf zu verlassen, die Zahlen, Zeichenfolgen oder Objekte entsprechend der Vorgehensweise von Python hinzufügen.

Offensichtlich kann dies viel größer werden, wenn Sie es zulassen.

Ian
quelle
3
Eigentlich habe ich nicht "nicht stören" gesagt. Was ich sagte war: "Das allgemeine Übersetzen von Sprachen ist sehr schwierig". Wenn das OP seinen ursprünglichen Weg fortsetzt, Python-Bäume zu verwenden, um PHP zu generieren, wird er viel lernen, und ich bin alle für die Lernerfahrung. Ich habe auch dort angefangen. Er wird nicht einfach neue Sprachen hinzufügen können.
Ira Baxter
@IraBaxter Ich kann Ihre Aussage nicht unterstützen, Python-> PHP und PHP-> Javascript zu machen wäre ziemlich einfach. vgl. letzter Teil von stackoverflow.com/a/22850139/140837 in der Mitte der Antwort Ich beschäftige mich auch mit Ihrer "Argumentation"
amirouche
2

Ich werde den Standpunkt von @EliBendersky bezüglich der Verwendung von ast.parse anstelle von Parser (von dem ich vorher nichts wusste) unterstützen. Ich empfehle Ihnen auch wärmstens, seinen Blog zu überprüfen. Ich habe ast.parse verwendet, um Python-> JavaScript-Übersetzer (@ https://bitbucket.org/amirouche/pythonium ) zu erstellen . Ich habe mir Pythonium-Design ausgedacht, indem ich andere Implementierungen etwas überprüft und selbst ausprobiert habe. Ich habe Pythonium von https://github.com/PythonJS/PythonJS gegabelt, das ich auch gestartet habe. Es ist eigentlich eine vollständige Neufassung. Das Gesamtdesign ist von PyPy- und http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf Papier inspiriert .

Alles, was ich versucht habe, vom Anfang bis zur besten Lösung, auch wenn es wie Pythonium-Marketing aussieht, ist es wirklich nicht (zögern Sie nicht, mir zu sagen, wenn etwas für die Netiquette nicht korrekt erscheint):

  • Implementieren der Python-Semantik in einfachem altem JavaScript mithilfe der Prototypvererbung: AFAIK Es ist unmöglich, die Python-Mehrfachvererbung mithilfe des JS-Prototypobjektsystems zu implementieren. Ich habe es später mit anderen Tricks versucht (vgl. Getattribute). Soweit ich weiß, gibt es keine Implementierung der Python-Mehrfachvererbung in JavaScript. Das Beste, was es gibt, ist Einzelvererbung + Mixins, und ich bin nicht sicher, ob sie mit Diamantvererbung umgehen. Ähnlich wie Skulpt, aber ohne Google Clojure.

  • Ich habe es mit Google Clojure versucht, genau wie Skulpt (Compiler), anstatt den Skulpt-Code #fail zu lesen. Auf jeden Fall wegen des JS-Prototyp-basierten Objektsystems immer noch unmöglich. Das Erstellen einer Bindung war sehr, sehr schwierig. Sie müssen JavaScript und viel Code für das Boilerplate schreiben (vgl. Https://github.com/skulpt/skulpt/issues/50, wo ich der Geist bin). Zu diesem Zeitpunkt gab es keine klare Möglichkeit, die Bindung in das Build-System zu integrieren. Ich denke, Skulpt ist eine Bibliothek und Sie müssen nur Ihre .py-Dateien in den HTML-Code aufnehmen, um ausgeführt zu werden. Der Entwickler muss keine Kompilierungsphase durchführen.

  • Pyjaco (Compiler) ausprobiert, aber das Erstellen von Bindungen (Aufrufen von Javascript-Code aus Python-Code) war sehr schwierig. Es gab zu viel Boilerplate-Code, um jedes Mal erstellt zu werden. Jetzt denke ich, dass Pyjaco derjenige ist, der Pythonium näher kommt. pyjaco ist in Python geschrieben (auch ast.parse), aber viel ist in JavaScript geschrieben und es wird die Vererbung von Prototypen verwendet.

Es ist mir nie gelungen, Pyjamas #fail auszuführen, und ich habe nie wieder versucht, den Code #fail zu lesen. In meinen Augen führte Pyjamas jedoch API-> API-Übersetzungen (oder Framework-zu-Framework) und keine Python-zu-JavaScript-Übersetzung durch. Das JavaScript-Framework verwendet Daten, die sich bereits auf der Seite befinden, oder Daten vom Server. Python-Code ist nur "Sanitär". Danach entdeckte ich, dass Pyjamas tatsächlich ein echter Python-> Js-Übersetzer waren.

Trotzdem denke ich, dass es möglich ist, API-> API- (oder Framework-> Framework-) Übersetzungen durchzuführen, und das ist im Grunde das, was ich in Pythonium mache, aber auf niedrigerer Ebene. Wahrscheinlich verwenden Pyjamas den gleichen Algorithmus wie Pythonium ...

Dann entdeckte ich Brython, das vollständig in Javascript wie Skulpt geschrieben ist, keine Kompilierung und viel Flusen benötigt ... aber in JavaScript geschrieben.

Seit der ersten Zeile im Verlauf dieses Projekts wusste ich über PyPy Bescheid, sogar über das JavaScript-Backend für PyPy. Ja, Sie können, wenn Sie es finden, direkt einen Python-Interpreter in JavaScript aus PyPy generieren. Die Leute sagen, es war eine Katastrophe. Ich lese nein wo warum. Ich denke jedoch, dass der Grund dafür ist, dass die Zwischensprache, mit der der Interpreter RPython implementiert wird, eine Teilmenge von Python ist, die auf die Übersetzung nach C (und möglicherweise asm) zugeschnitten ist. Ira Baxter sagt, dass Sie immer Annahmen treffen, wenn Sie etwas erstellen, und dass Sie es wahrscheinlich so einstellen, dass es das Beste ist, was es im Fall der PyPy: Python-> C-Übersetzung tun soll. Diese Annahmen sind in einem anderen Kontext möglicherweise nicht relevant, da sie den Overhead beeinträchtigen können. Andernfalls ist die direkte Übersetzung höchstwahrscheinlich immer besser.

Den Interpreter in Python schreiben zu lassen, klang nach einer (sehr) guten Idee. Aber ich war aus Leistungsgründen mehr an einem Compiler interessiert, außerdem ist es tatsächlich einfacher, Python in JavaScript zu kompilieren, als es zu interpretieren.

Ich habe PythonJS mit der Idee gestartet, eine Teilmenge von Python zusammenzustellen, die ich leicht in JavaScript übersetzen kann. Anfangs habe ich mich aufgrund früherer Erfahrungen nicht einmal die Mühe gemacht, das OO-System zu implementieren. Die Teilmenge von Python, die ich für die Übersetzung in JavaScript erreicht habe, ist:

  • Funktion mit vollständigen semantischen Parametern sowohl in der Definition als auch beim Aufruf. Dies ist der Teil, auf den ich am meisten stolz bin.
  • während / if / elif / else
  • Python-Typen wurden in JavaScript-Typen konvertiert (es gibt keinerlei Python-Typen)
  • for konnte nur über Javascript-Arrays iterieren (für ein In-Array)
  • Transparenter Zugriff auf JavaScript: Wenn Sie Array in den Python-Code schreiben, wird es in Javascript in Array übersetzt. Dies ist die größte Errungenschaft in Bezug auf die Benutzerfreundlichkeit gegenüber den Wettbewerbern.
  • Sie können die in der Python-Quelle definierte Funktion an Javascript-Funktionen übergeben. Standardargumente werden berücksichtigt.
  • Es hat eine spezielle Funktion namens new, die in JavaScript übersetzt wird. New zB: new (Python) (1, 2, Spam, "Ei") wird in "new Python (1, 2, Spam," Ei ") übersetzt.
  • "var" werden vom Übersetzer automatisch behandelt. (sehr schöne Entdeckung von Brett (PythonJS-Mitarbeiter).
  • globales Schlüsselwort
  • Verschlüsse
  • Lambdas
  • Listenverständnisse
  • Importe werden über requirejs unterstützt
  • Einzelklassenvererbung + Mixin über classyjs

Dies scheint viel zu sein, ist aber im Vergleich zur vollständigen Python-Semantik sehr eng. Es ist wirklich JavaScript mit einer Python-Syntax.

Das erzeugte JS ist perfekt, dh. Es gibt keinen Overhead, es kann nicht in Bezug auf die Leistung verbessert werden, indem es weiter bearbeitet wird. Wenn Sie den generierten Code verbessern können, können Sie dies auch aus der Python-Quelldatei heraus tun. Außerdem hat sich der Compiler nicht auf JS-Tricks verlassen, die Sie in .js finden, die von http://superherojs.com/ geschrieben wurden , sodass er sehr gut lesbar ist.

Der direkte Nachkomme dieses Teils von PythonJS ist der Pythonium Veloce-Modus. Die vollständige Implementierung finden Sie unter https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC + ca. 100 SLOC gemeinsam genutzten Codes mit dem anderen Übersetzer.

Eine angepasste Version von pystones.py kann im Veloce-Modus übersetzt werden, vgl. https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master

Nachdem ich die grundlegende Python-> JavaScript-Übersetzung eingerichtet hatte, wählte ich einen anderen Pfad, um vollständiges Python in JavaScript zu übersetzen. Die Art und Weise, wie glib objektorientierten klassenbasierten Code mit Ausnahme der Zielsprache ausführt, ist JS, sodass Sie Zugriff auf Arrays, kartenähnliche Objekte und viele andere Tricks haben und der gesamte Teil in Python geschrieben wurde. IIRC Es gibt keinen Javascript-Code, der von Pythonium Translator geschrieben wurde. Es ist nicht schwierig, eine einzelne Vererbung zu erhalten. Hier sind die schwierigen Teile, die Pythonium vollständig mit Python kompatibel machen:

  • spam.eggin Python wird immer übersetzt in getattribute(spam, "egg")Ich habe dies nicht besonders profiliert, aber ich denke, dass es viel Zeit verliert und ich nicht sicher bin, ob ich es mit asm.js oder irgendetwas anderem verbessern kann.
  • Reihenfolge der Methodenauflösung: Selbst mit dem in Python geschriebenen Algorithmus war die Übersetzung in Python Veloce-kompatiblen Code ein großes Unterfangen.
  • getattributre : Der eigentliche Algorithmus zur Auflösung von getattribute ist etwas knifflig und unterstützt immer noch keine Datendeskriptoren
  • metaklassenklassenbasiert: Ich weiß, wo ich den Code einstecken muss, aber immer noch ...
  • last bu not least: some_callable (...) wird immer in "call (some_callable)" umgewandelt. AFAIK, der Übersetzer, verwendet überhaupt keine Inferenz. Jedes Mal, wenn Sie einen Anruf tätigen, müssen Sie überprüfen, um welche Art von Objekt es sich handelt, so wie es aufgerufen werden soll.

Dieser Teil ist in https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master enthalten. Er wurde in Python geschrieben, das mit Python Veloce kompatibel ist.

Der tatsächlich kompatible Übersetzer https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master generiert keinen JavaScript-Code direkt und führt vor allem keine ast-> ast-Transformation durch . Ich habe das Ast-> Ast-Ding ausprobiert und Ast, auch wenn es nicht schön ist, mit Ast.NodeTransformer zu arbeiten, und was noch wichtiger ist, ich muss Ast-> Ast nicht machen.

Zumindest in meinem Fall Python Ast mit Python Ast zu tun, wäre vielleicht eine Leistungsverbesserung, da ich manchmal den Inhalt eines Blocks überprüfe, bevor ich den damit verbundenen Code generiere, zum Beispiel:

  • var / global: um etwas var zu können, muss ich wissen, was ich brauche und nicht var. Anstatt einen Block zu generieren, der verfolgt, welche Variablen in einem bestimmten Block erstellt werden, und ihn über den generierten Funktionsblock einzufügen, suche ich beim Eingeben des Blocks nach einer zugewiesenen Variablenzuweisung, bevor ich den untergeordneten Knoten tatsächlich besuche, um den zugehörigen Code zu generieren.
  • Ertrag, Generatoren haben bisher eine spezielle Syntax in JS, daher muss ich wissen, welche Python-Funktion ein Generator ist, wenn ich die "var my_generator = function" schreiben möchte.

Ich besuche also nicht wirklich jeden Knoten einmal für jede Phase der Übersetzung.

Der Gesamtprozess kann beschrieben werden als:

Python source code -> Python ast -> Python source code compatible with Veloce mode -> Python ast -> JavaScript source code

Python-Buildins sind in Python-Code (!) Geschrieben. IIRC Es gibt einige Einschränkungen in Bezug auf Bootstraping-Typen, aber Sie haben Zugriff auf alles, was Pythonium im kompatiblen Modus übersetzen kann. Schauen Sie sich https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master an

Das Lesen von JS-Code, der mit Pythonium-kompatiblem Code generiert wurde, kann verstanden werden, aber Quellkarten helfen sehr.

Die wertvollen Ratschläge, die ich Ihnen angesichts dieser Erfahrung geben kann, sind freundliche alte Fürze:

  • Überprüfen Sie das Thema ausführlich sowohl in der Literatur als auch in bestehenden Projekten. Als ich die verschiedenen bestehenden Projekte durchgesehen habe, hätte ich mehr Zeit und Motivation darauf verwenden sollen.
  • Fragen stellen! Wenn ich vorher wüsste, dass das PyPy-Backend wegen des Overheads aufgrund der semantischen Nichtübereinstimmung mit C / Javascript nutzlos ist. Ich hätte Pythonium vielleicht schon vor 6 Monaten, vielleicht vor 3 Jahren, auf die Idee gebracht.
  • wissen, was Sie tun möchten, haben ein Ziel. Für dieses Projekt hatte ich verschiedene Ziele: ein bisschen Javascript üben, mehr über Python lernen und Python-Code schreiben können, der im Browser ausgeführt wird (mehr und das unten).
  • Misserfolg ist Erfahrung
  • Ein kleiner Schritt ist ein Schritt
  • klein anfangen
  • träume groß
  • Demos machen
  • iterieren

Nur mit dem Python Veloce-Modus bin ich sehr glücklich! Aber auf dem Weg entdeckte ich, dass das, wonach ich wirklich suchte, mich und andere von Javascript befreite, aber vor allem in der Lage war , auf komfortable Weise zu erstellen . Dies führte mich zu Schema, DSL, Modellen und schließlich zu domänenspezifischen Modellen (vgl. Http://dsmforum.org/ ).

Über die Antwort von Ira Baxter:

Die Schätzungen sind überhaupt nicht hilfreich. Ich habe mehr oder weniger 6 Monate Freizeit für PythonJS und Pythonium gebraucht. Ich kann also mehr von Vollzeit 6 Monate erwarten. Ich denke, wir alle wissen, was 100 Mann pro Jahr in einem Unternehmenskontext bedeuten können und was nicht ...

Wenn jemand sagt, dass etwas schwierig oder öfter unmöglich ist, antworte ich: "Es braucht nur Zeit, um eine Lösung für ein unmögliches Problem zu finden."

Wenn es nicht als unmöglich erwiesen ist, lässt es Raum für Fantasie:

  • einen Beweis zu finden, der beweist, dass es unmöglich ist

und

  • Wenn es unmöglich ist, kann es ein "minderwertiges" Problem geben, das eine Lösung haben kann.

oder

  • Wenn es nicht unmöglich ist, eine Lösung zu finden

Es ist nicht nur optimistisches Denken. Als ich Python-> Javascript startete, sagten alle, es sei unmöglich. PyPy unmöglich. Metaklassen zu hart. etc ... Ich denke, dass die einzige Revolution, die PyPy über Scheme-> C-Papier (das 25 Jahre alt ist) bringt, eine automatische JIT-Generierung ist (basierend auf Hinweisen, die im RPython-Interpreter geschrieben wurden, denke ich).

Die meisten Leute, die sagen, dass eine Sache "schwer" oder "unmöglich" ist, geben keine Gründe an. C ++ ist schwer zu analysieren? Ich weiß, dass sie immer noch (kostenlose) C ++ - Parser sind. Das Böse steckt im Detail? Ich weiß das. Zu sagen, dass es allein unmöglich ist, ist nicht hilfreich. Es ist noch schlimmer als "nicht hilfreich", es ist entmutigend, und einige Leute wollen andere entmutigen. Ich habe von dieser Frage über /programming/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus gehört .

Was wäre Perfektion für Sie ? So definieren Sie das nächste Ziel und erreichen möglicherweise das Gesamtziel.

Ich bin mehr daran interessiert zu wissen, welche Arten von Mustern ich für den Code erzwingen könnte, um die Übersetzung des Codes zu vereinfachen (dh IoC, SOA?), Als wie die Übersetzung durchgeführt wird.

Ich sehe keine Muster, die nicht zumindest auf nicht perfekte Weise von einer Sprache in eine andere Sprache übersetzt werden können. Da eine Übersetzung von Sprache zu Sprache möglich ist, sollten Sie dies zuerst anstreben. Da ich denke , dass die Übersetzung zwischen zwei Computersprachen laut http://en.wikipedia.org/wiki/Graph_isomorphism_problem ein Baum- oder DAG-Isomorphismus ist. Auch wenn wir bereits wissen, dass beide vollständig sind, so ...

Framework-> Framework, das ich besser als API-> API-Übersetzung visualisiere, ist möglicherweise immer noch etwas, das Sie berücksichtigen sollten, um den generierten Code zu verbessern. Beispiel: Prolog als sehr spezifische Syntax, aber Sie können trotzdem Prolog-ähnliche Berechnungen durchführen, indem Sie dasselbe Diagramm in Python beschreiben ... Wenn ich einen Prolog-zu-Python-Übersetzer implementieren würde, würde ich die Vereinheitlichung nicht in Python implementieren, sondern in einer C-Bibliothek und kommen mit einer "Python-Syntax", die für einen Pythonisten sehr gut lesbar ist. Am Ende ist Syntax nur "Malen", für das wir eine Bedeutung geben (deshalb habe ich mit dem Schema begonnen). Das Böse steckt im Detail der Sprache und ich spreche nicht über die Syntax. Die Konzepte, die in der Sprache getattribute verwendet werdenHook (Sie können ohne ihn leben), aber erforderliche VM-Funktionen wie die Optimierung der Schwanzrekursion können schwierig zu handhaben sein. Es ist Ihnen egal, ob das ursprüngliche Programm keine Schwanzrekursion verwendet, und selbst wenn es in der Zielsprache keine Schwanzrekursion gibt, können Sie sie mithilfe von Greenlets / Ereignisschleifen emulieren.

Suchen Sie für Ziel- und Quellsprachen nach:

  • Große und spezifische Ideen
  • Winzige und gemeinsame Ideen

Daraus wird hervorgehen:

  • Dinge, die leicht zu übersetzen sind
  • Dinge, die schwer zu übersetzen sind

Sie werden wahrscheinlich auch wissen können, was in schnellen und langsamen Code übersetzt wird.

Es gibt auch die Frage der stdlib oder einer Bibliothek, aber es gibt keine klare Antwort, es hängt von Ihren Zielen ab.

Idiomatischer Code oder lesbarer generierter Code haben auch Lösungen ...

Das Targeting einer Plattform wie PHP ist viel einfacher als das Targeting von Browsern, da Sie die C-Implementierung eines langsamen und / oder kritischen Pfads bereitstellen können.

Angesichts der Tatsache, dass Ihr erstes Projekt Python in PHP übersetzt, ist das Anpassen von veloce.py die beste Wahl, zumindest für die mir bekannte PHP3-Teilmenge. Wenn Sie veloce.py für PHP implementieren können, können Sie wahrscheinlich den kompatiblen Modus ausführen ... Auch wenn Sie PHP in die Teilmenge von PHP übersetzen können, die Sie mit php_veloce.py generieren können, bedeutet dies, dass Sie PHP in das übersetzen können Teilmenge von Python, die veloce.py verbrauchen kann, was bedeuten würde, dass Sie PHP in Javascript übersetzen können. Ich sage nur ...

Sie können sich auch diese Bibliotheken ansehen:

Dieser Blog-Beitrag (und seine Kommentare) könnten Sie auch interessieren: https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/

Amirouche
quelle
Das einzige, was mich an der Übersetzung von Eins-zu-Eins-Computersprache in Computersprache noch begeistert, ist
amirouche
Ich stimme der anderen Antwort über Datentypen zu. In Pythonium hatte ich nicht einmal vor, einen korrekten Integer & Float-Typ im kompatiblen Modus ohne asm.js zu unterstützen.
Amirouche
OK, wenn ich Ihnen ein Python-Paket mit 100K SLOC gebe und Sie es über Ihren "Übersetzer" ausführen, bekomme ich dann ein funktionierendes Programm? Wie viel Handarbeit nach der Übersetzung ist erforderlich, um das Problem zu beheben? Was Sie hier gesagt haben, war: "Angesichts eines bereits vorhandenen guten Parsers für Python, der ASTs erstellt, kann ich in 6 Monaten einen Teilübersetzer erstellen." Niemand ist überrascht. 6 Monate sind für die meisten Leute nicht "einfach" (zitiert aus einem anderen Ihrer Kommentare). Die Lösung der verbleibenden Probleme erfordert mehr Aufwand. Meine Antwort lautete: "Das ist im Grunde nicht einfach" und "es allgemein zu tun ist schwer".
Ira Baxter
... dieser letzte Punkt als Antwort auf den ursprünglichen Wunsch von OP: "Idealerweise könnte ich andere Sprachen mit (relativer) Leichtigkeit hinzufügen.", den meine Antwort speziell anspricht.
Ira Baxter
Ich bin anderer Meinung, besonders wenn Sie wissen, was Sie tun, es einfach ist und das Folgende nicht schwer ist, es ist nur eine Frage der Erledigung von Dingen. Ich bin mir nicht sicher, wo Sie mit etwas Speziellem zu tun haben. Sie sagen in 4 oder 5 Absätzen, dass Ihr Unternehmen es tut, und es ist schwer. Ansonsten verbreiten Sie FUD über das Thema, während Sie nicht zum Thema gehören, wie Sie es in stackoverflow.com/questions/22621164/… tun . In Vollzeit 6 Monate hätte ich einen vollständigen Übersetzer geschrieben.
Amirouche
0

Sie können sich den Vala-Compiler ansehen , der Vala (eine C # -ähnliche Sprache) in C übersetzt.

Ptomato
quelle
Es war ein Designziel von Vala, in C übersetzt zu werden und die Entwicklung mit Gnomenbibliotheken zu vereinfachen.
Amirouche