[Pyparsing] Wie am besten Aktionen hinzufügen
Verfasst: 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:
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?
Oder in den sauren Apfel beißen und die Lesbarkeit opfern?
Oder doch eine externe DSL benutzen?
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
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
Also nachträglich sowas machen?
Code: Alles auswählen
literal.exprs[0].setParseAction(...)
literal.exprs[1].setParseAction(...)
literal.exprs[2].setParseAction(...)
array.setParseAction(...)
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
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
Gibt es noch Alternativen, Zustimmung oder Ablehnung?
Stefan