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'))