[Pyparsing] Wie am besten Aktionen hinzufügen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

[Pyparsing] Wie am besten Aktionen hinzufügen

Beitragvon sma » Sonntag 6. April 2008, 15:52

Eine PEG (wie Pyparsing sie benutzt) hat den Vorteil, recht lesbar zu sein - jedenfalls solange wie man keine Aktionen hinzufügt. Doch wenn man das will, wie geht man da am besten vor?

Hier ist ein Beispiel:

Code: Alles auswählen

symbol = identifier | operator | OneOrMore(keyword)
symbol_constant = "#" + (symbol | string)
array_constant = Forward()
literal = number | string | "nil" |  "true" | "false" | symbol_constant | array_constant
array = Forward()
array << "(" + ZeroOrMore(literal | symbol | array) + ")"
array_constant << "#" + array

Bei obigem Beispiel möchte ich gerne, dass `literal` ein passendes Objekt erzeugt. Ich muss da insbesondere an jede Alternative eine eigene Aktion hängen, was das ganze unlesbar macht.

Also nachträglich sowas machen?

Code: Alles auswählen

literal.exprs[0].setParseAction(...)
literal.exprs[1].setParseAction(...)
literal.exprs[2].setParseAction(...)
array.setParseAction(...)


Oder in den sauren Apfel beißen und die Lesbarkeit opfern?

Code: Alles auswählen

symbol = identifier | operator | OneOrMore(keyword).setParseAction(lambda r: "".join(r))
symbol_constant = Suppress("#") + (symbol | string).setParseAction(lambda r: rt.Symbol(r[0]))
array_constant = Forward()
literal = (
   number.setParseAction(lambda r: rt.Integer(int(r[0]))) |
   string.setParseAction(lambda r: rt.String(r[0][1:-1].replace("''", "'"))) |
   Literal("nil").setParseAction(lambda r: rt.System.nil) |
   Literal("true").setParseAction(lambda r: rt.System.true) |
   Literal("false").setParseAction(lambda r: rt.System.false) |
   symbol_constant |
   array_constant
)
array = Forward()
array << Suppress("(") + ZeroOrMore(
   literal |
   symbol.setParseAction(lambda r: rt.Symbol(r[0])) |
   array
).setParseAction(lambda r: rt.Array(tuple(r))) + Suppress(")")
array_constant << Suppress("#") + array


Oder doch eine externe DSL benutzen?

Code: Alles auswählen

symbol:
   identifier
   operator
   keyword+        => "".join($0)
   
symbol_constant:
   "#" symbol      => rt.Symbol($0)
   "#" string      => rt.Symbol($0)
   
array_constant:
   "#" array
   
array:
   "(" array_contents* ")" => rt.Array($0)
   
array_contents:
   literal
   symbol         => rt.Symbol($0)
   array

literal:
   number          => rt.Integer(int($0))
   string          => rt.String($0)
   "nil"           => rt.System.nil
   "true"          => rt.System.true
   "false"       => rt.System.false
   symbol_constant
   array_constant

Jede Regel wird durch einen ":" abgeschlossen, dem dann eingerückt die Alternativen folgen. Hinter "=>" steht die Aktion als Python-Ausdruck, wobei "$x" auf das x-te Ergebnis der Unterregeln verweist. Token in "" werden automatisch ignoriert und "=> $0" ist der Standard.

Gibt es noch Alternativen, Zustimmung oder Ablehnung?

Stefan

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot], Google [Bot]