Search code examples
pythonpython-3.xpyparsing

How to do proper recursion in Pyparsing?


I'm currently parsing a custom programming language, and, when creating the "expression" rule for parsing, I'm struggling to find a way that's not painfully slow with recursion. My problem is that a function call can be in an expression, and an expression can be in a function call (parameters). So what I end up with is a terrible system based on Forward(), that takes seconds on func1(var1+1) + 1 and minutes on func1(func1(var1+1)+1) + 1, which is for sure not acceptable. Here's my current bad approach:

    expression = Forward()
    functionCall = Forward()
    value = literal ^ identifier ^ Group(functionCall)
    expression << Group(infixNotation(value, [
        (memberOP, 2, opAssoc.LEFT),
        ...
    ]))
    arguments = ZeroOrMore(delimitedList(expression))

    ...

    functionCall << identifier + Literal("(").suppress() + Group(arguments) + Literal(")").suppress()

Solution

  • PyParsing can remember previous parse results and re-use them using the Packrat optimisation. This is provides a performance benefit for recursive grammars or generally if an element may apply in different contexts.

    Packrat must be manually enabled, since it might conflict with parsers that have side-effects (e.g. a parse action that modifies global state).

    import pyparsing
    pyparsing.ParserElement.enablePackrat()