Hallo!
Ich bin dabei eine Programmiersprache zu implementieren und suche im Moment Tools die mir dabei helfen. Optimalerweise bräuchte ich Python-Equivalents zu JLex oder JFlex und CUP.
Bisher habe ich die Wiki-Seite LanguageParsing gefunden, aber darüber hinaus echt wenig, daher würde es mich freuen wenn ihr mir ein paar Tipps in die richtige Richtung geben könntet.
Python Parsergeneratoren
-
- User
- Beiträge: 1790
- Registriert: Donnerstag 28. Oktober 2004, 16:33
- Wohnort: Graz, Steiermark - Österreich
- Kontaktdaten:
Ich hab mir dir bis jetzt noch nicht wirklich angetan, weil die meisten *grausigen* Code generieren. Warum nicht Parser selber schreiben?
TUFKAB – the user formerly known as blackbird
- birkenfeld
- Python-Forum Veteran
- Beiträge: 1603
- Registriert: Montag 20. März 2006, 15:29
- Wohnort: Die aufstrebende Universitätsstadt bei München
Weil das zwar ne gute Übung ist, aber mit der Zeit langweilig wird?
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Weil das mit Hand schreiben zwar nett ist, aber wie ich in der letzten Zeit gemerkt habe, sehr leicht zu Fehlern führt, dass man etwas übersetzt, etc. Das wäre eben ein Fall wo Unit-Testing *sehr* nützlich ist.mitsuhiko hat geschrieben:Warum nicht Parser selber schreiben?
Ich habe von mitsuhiko noch Ned Batchelders Parserliste bekommen.
Was auf den ersten Blick so brauchbar aussah:
- pyparsing - BlackJacks Empfehlung
- ZestyParser - ist vielleicht mächtiger als pyparsing, aber die Syntax gefällt mir nicht besonders.
- yeanpypa (eine Mischung aus pyparsing und boost::spirit)
- SPARK (ist nun tatsächlich in Python enthalten - habe es geprüft) allerdings ist das letzte Release von 2002 und die Dokumentation ist nicht so berauschend. Es gibt allerdings einen Charming Python-Artikel von David Mertz
- Plex - vom Pyrex-Autor, recht aktuell aber leider nur ``lex``-Funktionalität, eine ``yacc/bison``-Kombi wäre praktischer.
- PLY von David Beazley, einer eher bekannten Person in der Python-Welt, auch ziemlich aktuell
- aperiot recht neue Software, sieht auf den ersten Blick brauchbar aus.
- Toy Parser Generator
- Parsing - scheint zumindest von den Spezifikationen ganz brauchbar zu sein. Kaum Dokumentation
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
-
- User
- Beiträge: 1790
- Registriert: Donnerstag 28. Oktober 2004, 16:33
- Wohnort: Graz, Steiermark - Österreich
- Kontaktdaten:
Das mag schon sein aber ich hab noch nichts in Python gefunden, dass einen schönen Syntax Baum und sauberen Quellcode liefertbirkenfeld hat geschrieben:Weil das zwar ne gute Übung ist, aber mit der Zeit langweilig wird?
TUFKAB – the user formerly known as blackbird
Darüberhinaus zeigen Parser- oder Codegeneratoren ein grausiges Fehlerverhalten. Ein gutes Beispiel ist Python selbst. Wohl in der Hälfte aller Fälle führen einen die Fehlermeldungen in die Irre.mitsuhiko hat geschrieben:Ich hab mir die bis jetzt noch nicht wirklich angetan, weil die meisten *grausigen* Code generieren. Warum nicht Parser selber schreiben?
Beim rekursicen Abstieg (recursive descent) hat man das Fehlerverhalten dagegen voll im Griff.
Gruß Granino
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Generiert soweit ich sehe nur Java-Code. Da kann ich auch Bison-in-a-box nehmen, das aus dem Bison-C Python übersetztJona hat geschrieben:was ist mit javaCC?
Alternativ auch ANTLR oder SableCC, die beide Python-Output (experimentell) unterstützen. Aber ich sehe eigentlich keinen Grund, eine Java-Software unnötigerweise ins Boot zu holen, da ich mit keinem dieser Tools Erfahrung habe habe ich somit auch keinen Vorteil dass ich es schon kenne.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
- birkenfeld
- Python-Forum Veteran
- Beiträge: 1603
- Registriert: Montag 20. März 2006, 15:29
- Wohnort: Die aufstrebende Universitätsstadt bei München
Was meinst du denn damit?Granino hat geschrieben:Darüberhinaus zeigen Parser- oder Codegeneratoren ein grausiges Fehlerverhalten. Ein gutes Beispiel ist Python selbst. Wohl in der Hälfte aller Fälle führen einen die Fehlermeldungen in die Irre.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Ok, soweit ich sehe kommen zwei in die engere Auswahl: PLY (weil es scheinbar extra für diesen Zweck geschrieben wurde) und pyparsing (weil es eine bessere Syntax als ZestyParser & Co hat + zudem Dokumentation).
Aperiot ist wegen der Codegeneration weggefallen, yeanpypa wegen der geringen Verbreitung, ZestyParser wegen der auf den ersten Blick echt unübersichtlichen API, SPARK weil mir die API da auch nicht gefällt und es unmaintained ausschaut, Plex wegen der geringen Verbreitung, TPG weden der API, Parsing wegen der geringen Verbreitung.
Schade, dass modelnine nichts mehr in die Richtung macht, sein Pyrr hätte eine brauchbare Alternative sein können.
Aperiot ist wegen der Codegeneration weggefallen, yeanpypa wegen der geringen Verbreitung, ZestyParser wegen der auf den ersten Blick echt unübersichtlichen API, SPARK weil mir die API da auch nicht gefällt und es unmaintained ausschaut, Plex wegen der geringen Verbreitung, TPG weden der API, Parsing wegen der geringen Verbreitung.
Schade, dass modelnine nichts mehr in die Richtung macht, sein Pyrr hätte eine brauchbare Alternative sein können.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
-
- User
- Beiträge: 1790
- Registriert: Donnerstag 28. Oktober 2004, 16:33
- Wohnort: Graz, Steiermark - Österreich
- Kontaktdaten:
birkenfeld hat geschrieben:Was meinst du denn damit?Granino hat geschrieben:Darüberhinaus zeigen Parser- oder Codegeneratoren ein grausiges Fehlerverhalten. Ein gutes Beispiel ist Python selbst. Wohl in der Hälfte aller Fälle führen einen die Fehlermeldungen in die Irre.
Code: Alles auswählen
[(foo])
TUFKAB – the user formerly known as blackbird
Das ist aber keine Meldung, die in die Irre führt. Es wird ganz deutlich auf die erste schliessende, eckige Klammer verwiesen und genau da liegt auch das Problem.
@ Birkenfeld,
ein kleines Beispiel:
x = {2*3 + 4**5)
mit der Fehlermeldung: 'invalid Syntax' vor dem x.
Bei einem längeren Programmtext ist insbesondere für den Anfänger nicht klar, ob er den Fehler vor dieser Zeile oder ab dieser Zeile suchen muss.
Beim Parsen nach dem 'recursive descent' kann eine präzisere Meldung ausgegeben werden. Daneben wird die exakte Position (Spalte) markiert.
Weiterer Vorteil: Enthält ein längeres Programm gleich N Fehler, wird die Syntaxanalyse an der nächst möglichen Textpassage wieder aufgenommen. Mit etwas Glück werden in einem Durchgang alle N Fehler gemeldet.
Gruß Granino
ein kleines Beispiel:
x = {2*3 + 4**5)
mit der Fehlermeldung: 'invalid Syntax' vor dem x.
Bei einem längeren Programmtext ist insbesondere für den Anfänger nicht klar, ob er den Fehler vor dieser Zeile oder ab dieser Zeile suchen muss.
Beim Parsen nach dem 'recursive descent' kann eine präzisere Meldung ausgegeben werden. Daneben wird die exakte Position (Spalte) markiert.
Weiterer Vorteil: Enthält ein längeres Programm gleich N Fehler, wird die Syntaxanalyse an der nächst möglichen Textpassage wieder aufgenommen. Mit etwas Glück werden in einem Durchgang alle N Fehler gemeldet.
Gruß Granino
-
- User
- Beiträge: 773
- Registriert: Mittwoch 5. November 2003, 18:06
- Wohnort: Schweiz
- Kontaktdaten:
Hi
Also bei mir zeigt er den Fehler bei der runden Klammer:
Genau da wo er ist
*edit* ein angezeigter Fehler ist mir eigentlich lieber als 10 Folgefehler
Gruss
Also bei mir zeigt er den Fehler bei der runden Klammer:
Code: Alles auswählen
>>>x = {2*3 + 4**5)
File "<console>", line 1
x = {2*3 + 4**5)
^
SyntaxError: invalid syntax
*edit* ein angezeigter Fehler ist mir eigentlich lieber als 10 Folgefehler
Gruss
- birkenfeld
- Python-Forum Veteran
- Beiträge: 1603
- Registriert: Montag 20. März 2006, 15:29
- Wohnort: Die aufstrebende Universitätsstadt bei München
Hier ist der "Fehlercursor" auch auf der schließenden Klammer.Granino hat geschrieben:@ Birkenfeld,
ein kleines Beispiel:
x = {2*3 + 4**5)
mit der Fehlermeldung: 'invalid Syntax' vor dem x.
Der Fehler kann immer irgendwo vor der angegebenen Stelle liegen, wenn man ein Konstrukt "falsch" anfängt und "richtig" beendet - wie oben mit den Klammern demonstriert.Bei einem längeren Programmtext ist insbesondere für den Anfänger nicht klar, ob er den Fehler vor dieser Zeile oder ab dieser Zeile suchen muss.
Und mit etwas Unglück interpretiert dein Parser genau das Falsche in den Code hinein, und anstatt den Code an den 10 Stellen mit gemeldeten Fehlern zu korrigieren, musst du woanders etwas ändern. Soviel zum Thema "irreführend".Beim Parsen nach dem 'recursive descent' kann eine präzisere Meldung ausgegeben werden. Daneben wird die exakte Position (Spalte) markiert.
Weiterer Vorteil: Enthält ein längeres Programm gleich N Fehler, wird die Syntaxanalyse an der nächst möglichen Textpassage wieder aufgenommen. Mit etwas Glück werden in einem Durchgang alle N Fehler gemeldet.
Tut mir leid,
aber ich habe den Einzeiler unter IDLE getestet, daher die Unterschiede.
Mein Test lief also nicht unter realen Bedingungen.
Doch das Problem ist nicht das Fehlerverhalten von Python, sondern ich möchte aufzeigen, dass Parser nach dem 'rekursiven Abstieg' ein exzellentes Fehlerverhalten haben. Und das liegt schlicht daran, dass der Programmierer exakt nach der Syntax den Parserteil programmiert. Jedem Nonterminal entspricht dann dem Aufruf einer (gleichnamigen) Prozedur.
Der Parser erhält von der lexikalischenn Analyse zu jedem Token (Variablennamen, Schlüsselwörter, Operatoren usw.) zugleich auch deren Zeile/Spalte im Quelltext zur genauen Positionsangabe des Fehlers.
Wenn der Anwender aber beispielsweise einem Pythonparser einen LISP-Quelltext anbietet wird es wohl problematisch. Doch wennn der Programmierer die wichtigsten Sprachen kennt, kann er sogar dafür sorgen, dass bei Verwendung fremder Sprachelemente sinnvolle Meldungen erscheinen. Anderes Beispiel
If a = b : # Wollte der Anwender hier '==' schreiben?
Ein intelligenter Parser würde am Gleichheitszeichen hier eine Warnung (per Option abschaltbar) ausgeben, dass es sich um eine Zuweisung und nicht um einen Vergleich handelt.
Unsinnige Fehlermeldungen sind fast nicht möglich. Der Preis: Der Parser muss völlig von Hand programmiert werden. Aber bei den automatisch generierten Parsern wird einem ja auch nichts geschenkt, die Syntax muss gewaltig überarbeitet werden, damit sie den Nebenbedingungen der Parsergenerators genügt.
Gruß Granino
aber ich habe den Einzeiler unter IDLE getestet, daher die Unterschiede.
Mein Test lief also nicht unter realen Bedingungen.
Doch das Problem ist nicht das Fehlerverhalten von Python, sondern ich möchte aufzeigen, dass Parser nach dem 'rekursiven Abstieg' ein exzellentes Fehlerverhalten haben. Und das liegt schlicht daran, dass der Programmierer exakt nach der Syntax den Parserteil programmiert. Jedem Nonterminal entspricht dann dem Aufruf einer (gleichnamigen) Prozedur.
Der Parser erhält von der lexikalischenn Analyse zu jedem Token (Variablennamen, Schlüsselwörter, Operatoren usw.) zugleich auch deren Zeile/Spalte im Quelltext zur genauen Positionsangabe des Fehlers.
Wenn der Anwender aber beispielsweise einem Pythonparser einen LISP-Quelltext anbietet wird es wohl problematisch. Doch wennn der Programmierer die wichtigsten Sprachen kennt, kann er sogar dafür sorgen, dass bei Verwendung fremder Sprachelemente sinnvolle Meldungen erscheinen. Anderes Beispiel
If a = b : # Wollte der Anwender hier '==' schreiben?
Ein intelligenter Parser würde am Gleichheitszeichen hier eine Warnung (per Option abschaltbar) ausgeben, dass es sich um eine Zuweisung und nicht um einen Vergleich handelt.
Unsinnige Fehlermeldungen sind fast nicht möglich. Der Preis: Der Parser muss völlig von Hand programmiert werden. Aber bei den automatisch generierten Parsern wird einem ja auch nichts geschenkt, die Syntax muss gewaltig überarbeitet werden, damit sie den Nebenbedingungen der Parsergenerators genügt.
Gruß Granino
Das umschreiben muss man bei rekursiv absteigenden Parsern doch auch machen. Linksrekursion beseitigen zum Beispiel. Wenn es nicht gerade um das Lehrbuchbeispiel eines einfachen Parsers für Rechenausdrücke geht, wird das alles per Hand in der Regel ziemlich mühselig zu implementieren.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Für alle die es interessiert, die vielleicht mal in die gleiche Situation kommen wie ich: habe mich nun für PLY entschieden.
Es funktioniert auch ziemlich gut, aber die API ist etwas seltsam (die Reihenfolge der Tokens über die Reihenfolge der ihnen zugeordneten Regulären Ausdrücke definieren? Was?!). Werde wohl auf der ``ply-hack`` ML das zur Sprache bringen.
Bisher habe ich allerdings nur einen funktionsfähigen Lexer gebaut (ist aber wirklich einfach gewesen), der Parser wird in den nächsten Tagen folgen.
Es funktioniert auch ziemlich gut, aber die API ist etwas seltsam (die Reihenfolge der Tokens über die Reihenfolge der ihnen zugeordneten Regulären Ausdrücke definieren? Was?!). Werde wohl auf der ``ply-hack`` ML das zur Sprache bringen.
Bisher habe ich allerdings nur einen funktionsfähigen Lexer gebaut (ist aber wirklich einfach gewesen), der Parser wird in den nächsten Tagen folgen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Hi, Leonidas.
Ich finde SimpleParse ganz gut Du musst natürlich die EBNF Beschreibung mögen. PyParsing finde ich irgendwie nicht so schön, da ich mich mit EBNF wohler fühle.
Nun mal ein par Fakten:
1. Fakt ist das die meisten Pure Python Parser Generatoren Arschlangsamen Code erzeugen PyParsing ist da so ein Kandidat und auch SimpleParse. -- Hängt natürlich davon ab was du implementieren willst. Der Python Gramma in PyParsing implementiert und dann mit ca. 10.000 - 30.000 Zeilen gefüttert ist unzumutbar...
2. Fakt ist das ich es auch so wie BlackBird sehe das ich bisher keinen Parser Generator gesehen habe, der schönen Code oder gar parsetree erzeugt.
3. Je nach dem was du da nun vorhast, ist es alldem aber erstmal eine sehr gute Idee den POC in Python mit nem Parser Generator zu schreiben, da du dein Konzept deiner Sprache(?) auf eine Zeitsparende Art testen kannst Anschließend, wenn du durch bist un dir gefällt was du siehst und dir die Geschwindigkeit ausreicht kannst ja bei der Implementation bleiben. Aber, spätestens wenn du wirklich ernsthaft vor hast eine Sprache(rweiterung) zu entwickeln der Public sein soll, dann würde ich nach dem POC den Parser in C implementieren:
a. Dafür kannst du dann wenn es auf Python aufsetzt, auch die sehr Highlevel Python-C-API nutzen und ne Extension schreiben.
b. Wenn es alerdings eine eigenständige Sprache wird, dann würde ich auf Pyhon gänzlich verzichten und komplett auf C setzen. Denn keiner hat bock auf einen Interpreter im Interpreter. (BTW: Falls du vorhast wirklich eine nue Sprach zu schreiben sage ich mal vorsichtig: Lass es. Es ist sehr Zeitintensiev und ist nicht von heute auf morgen realisiert. Dafür kannst locker mal dein ganzes Leben verplanen, wie man schön an Python und Ruby sehen kann )
Abschließend: Was hast du den Schönes vor?
EDIT: Arghhh!! Hätte mal den kompletten Thread lesen sollen Sehe jetzt erst dein letzten Post und das du dich bereits für PLY entscheiden hast.
Ich finde SimpleParse ganz gut Du musst natürlich die EBNF Beschreibung mögen. PyParsing finde ich irgendwie nicht so schön, da ich mich mit EBNF wohler fühle.
Nun mal ein par Fakten:
1. Fakt ist das die meisten Pure Python Parser Generatoren Arschlangsamen Code erzeugen PyParsing ist da so ein Kandidat und auch SimpleParse. -- Hängt natürlich davon ab was du implementieren willst. Der Python Gramma in PyParsing implementiert und dann mit ca. 10.000 - 30.000 Zeilen gefüttert ist unzumutbar...
2. Fakt ist das ich es auch so wie BlackBird sehe das ich bisher keinen Parser Generator gesehen habe, der schönen Code oder gar parsetree erzeugt.
3. Je nach dem was du da nun vorhast, ist es alldem aber erstmal eine sehr gute Idee den POC in Python mit nem Parser Generator zu schreiben, da du dein Konzept deiner Sprache(?) auf eine Zeitsparende Art testen kannst Anschließend, wenn du durch bist un dir gefällt was du siehst und dir die Geschwindigkeit ausreicht kannst ja bei der Implementation bleiben. Aber, spätestens wenn du wirklich ernsthaft vor hast eine Sprache(rweiterung) zu entwickeln der Public sein soll, dann würde ich nach dem POC den Parser in C implementieren:
a. Dafür kannst du dann wenn es auf Python aufsetzt, auch die sehr Highlevel Python-C-API nutzen und ne Extension schreiben.
b. Wenn es alerdings eine eigenständige Sprache wird, dann würde ich auf Pyhon gänzlich verzichten und komplett auf C setzen. Denn keiner hat bock auf einen Interpreter im Interpreter. (BTW: Falls du vorhast wirklich eine nue Sprach zu schreiben sage ich mal vorsichtig: Lass es. Es ist sehr Zeitintensiev und ist nicht von heute auf morgen realisiert. Dafür kannst locker mal dein ganzes Leben verplanen, wie man schön an Python und Ruby sehen kann )
Abschließend: Was hast du den Schönes vor?
EDIT: Arghhh!! Hätte mal den kompletten Thread lesen sollen Sehe jetzt erst dein letzten Post und das du dich bereits für PLY entscheiden hast.