I have the following toy grammar in Pyparsing:
import pyparsing as pp
or_tok = "or"
and_tok = "and"
lparen = pp.Suppress("(")
rparen = pp.Suppress(")")
Word = pp.Word(pp.alphas)("Word")
Phrase = pp.Forward()
And_Phrase = pp.Group(pp.delimitedList(Phrase, and_tok))("And_Phrase")
Or_Phrase = pp.Group(pp.delimitedList(Phrase, or_tok))("Or_Phrase")
Phrase << (pp.Optional(lparen) + (And_Phrase ^ Or_Phrase) + pp.Optional(rparen)) ^ Word
Expression = pp.OneOrMore(Word ^ Phrase)("Expression")
def test(text):
output = Expression.parseString(text)
print output.asXML()
However, running this program will infinitely recurse, which isn't what I wanted. Rather, I wanted my grammar to be able to handle nested phrases so that the above program would resolve to something equivalent to the below:
>>> test("TestA and TestB and TestC or TestD")
<Expression>
<And_Phrase>
<Word>TestA</Word>
<Word>TestB</Word>
<Or_Phrase>
<Word>TestC</Word>
<Word>TestD</Word>
</Or_Phrase>
</And_Phrase>
</Expression>
I attempted to modify the definitions for And_Phrase and Or_Phrase so that they would match only lists that have two or more elements, but couldn't figure out how to do so.
I also tried using pyparsing.operatorPrecedence, but I don't think I did it right:
import pyparsing as pp
or_tok = "or"
and_tok = "and"
lparen = pp.Suppress("(")
rparen = pp.Suppress(")")
Word = pp.Word(pp.alphas)("Word")
Phrase = pp.Forward()
Phrase << Word ^ \
pp.operatorPrecedence(Phrase, [
(and_tok, 2, pp.opAssoc.LEFT),
(or_tok, 2, pp.opAssoc.LEFT)
])
Expression = pp.OneOrMore(Word ^ Phrase)("Expression")
def test(text):
output = Expression.parseString(text)
print output.asXML()
...because it didn't yield a list at all:
>>> test("Hello world and bob")
<Expression>
<Word>Hello</Word>
<Word>world</Word>
<Word>and</Word>
<Word>bob</Word>
</Expression>
How can I modify my rule definitions so that they will handle nested lists?