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()
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()