Seite 1 von 1
JavaScript-Parser in Python?
Verfasst: Samstag 7. November 2009, 10:26
von sma
Ich könnte einen JavaScript bzw. ECMAScript-Parser in Python gebrauchen, da ich gerne damit experimentieren würde, Varianten von JavaScript in JavaScript zu übersetzen. Gibt es da schon etwas Fertiges?
Für ANTLR gibt es wohl eine ECMAScript-3-Grammatik, die man wohl irgendwie auch in Python übersetzen könnte. Aber das ist mir eigentlich zu viel Aufwand, da ich ANTLR-Grammatiken nicht gerade einfach lesbar finde.
Nebenbei: Welchen Parsergenerator würdet ihr warum empfehlen? Ich persönlich bin ja ein Fan von PEG bzw. Packrat-Parsern, habe jedoch noch keinen guten für Python gesehen. Pyparsing missfällt mir schon aufgrund der werbeüberfluteten hässlichen Homepage und der IMHO nicht ideomatischen Benennung. Zudem sieht der Quelltext wüst aus, wenn man da näher hineinschaut.
Stefan
Verfasst: Samstag 7. November 2009, 18:31
von Whitie
Hallo sma,
ich fand
LEPL sehr ansprechend. Hab allerdings bis jetzt nur mal das Tutorial durchgearbeitet.
Mich hat vor allem angesprochen, dass diverse Operatoren überladen werden und somit (in meinen Augen) ansehnlicher und nachvollziehbarer Code entsteht. Außerdem wird die Hauptentwicklung für Python 3.x gemacht (läuft aber auch unter 2.6).
Gruß
Whitie
Verfasst: Samstag 7. November 2009, 18:58
von HWK
PLY gefällt mir. Ist halt ähnlich zu den lex und yacc.
MfG
HWK
Verfasst: Sonntag 8. November 2009, 12:01
von sma
Whitie hat geschrieben:ich fand
LEPL sehr ansprechend.
Interessant.
Packrat-Parser, der
Linksrekursion beherrscht.
Kann man aber hier noch erkennen, dass das ein Parser für JSON-Ausdrücke ist? Dabei fehlt noch die Logik, dass die Pair, Object und Array-Knoten in native Python-Datenstrukturen konvertiert werden. Das ich offenbar jedes Stück Syntax in `Drop` einschließen muss, stört mich auch.
Code: Alles auswählen
from lepl import *
class Pair(Node): pass
class Object(Node): pass
class Array(Node): pass
def none(s): return None
def string(s): return s[1:-1].decode("string-escape")
value = Delayed()
const = Literal("true") >> bool | Literal("false") >> bool | Literal("null") >> none
number = Digit()[1:,...] >> float > 'number'
string = Regexp(r'"(?:\u[0-9a-fA-F]{4}|\["\/bfnrt]|[^"])*"') >> string > 'string'
spaces = Drop(Regexp(r'\s*'))
with Separator(spaces):
pair = string & Drop(":") & value > Pair
members = pair & (Drop(",") & pair)[:]
obj = "{" & members[:1] & "}" > Object
elements = value & (Drop(",") & value)[:]
ary = "[" & elements[:1] & "]" > Array
value += const | number | string | obj | ary
print value.parse_string('[1, "2", {"c": true, "d": "\\r\\n"}]')[0]
Stefan
Verfasst: Sonntag 8. November 2009, 16:42
von derdon
Was hast du denn gegen PLY? Es gefällt mir von den libs, die ich zum Thema Lexer/Parser angeguckt habe (ca. 5), am besten. Es ist nicht sehr elegant, den Docstring einer Funktion zu "missbrauchen", aber eine schönere Möglichkeit habe ich bisher nicht gesehen.
Verfasst: Sonntag 8. November 2009, 22:54
von Leonidas
Naja, PLY ist Lex/Yacc-like und das ist sma sicher zu altmodisch, so wie ich ihn kenne

Allerdings muss ich sagen, dass es ziemlich brauchbar ist, ich finds intuitiver als diese Pyparsing-Seltsamkeiten.
LEPL erinnert ein wenig an boost.spirit, wollts mal antesten aber dann hab ich das Vorhaben erstmal auf Eis gelegt.
Verfasst: Mittwoch 11. November 2009, 10:33
von sma
Leonidas hat geschrieben:Naja, PLY ist Lex/Yacc-like und das ist sma sicher zu altmodisch, so wie ich ihn kenne :)
Lex/Yacc habe ich schon vor 15 Jahren in C benutzt. Also langweilig :) Die Idee mit den Doc-Strings ist aber in der Tat nett und ich hatte hier auch schon mal so ein Beispiel für einen selbstgeschriebenen PEG gepostet. Ich finde PEGs und Parserkombinatoren einfach zur Zeit spannender.
Stefan
Verfasst: Freitag 11. Dezember 2009, 09:04
von snafu
Vielleicht interessiert dich ja auch
pynarcissus, ein Python-Port von Mozillas
Narcissus. Du kannst damit sogar den geparsten Baum in S-Expressions umwandeln:
Code: Alles auswählen
In [1]: import jsparser, sexp
In [2]: js = "alert('hello world');"
In [3]: tree = jsparser.parse(js)
In [4]: print sexp.convert(tree)
------> print(sexp.convert(tree))
(SCRIPT
(CALL alert 'hello world'))