Nesting delimited lists in pyparsing without causing infinite recursion?

Viewed 585

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?

1 Answers
Related