I'm building a recursive grammar using pyparsing, to express a series of possible operations, but I've hit an issue with how to express functions. I wish to describe an operator that has a name, followed by a comma delimited set of arguments:
import pyparsing as pp
test_string = "f(x, g(h(i,j)))"
expr = pp.Forward()
variable = pp.Word(pp.alphas)
term = pp.infixNotation(
variable, ... # Insert operators here
)
expr <<= term
expr.parse_string(test_string)
I originally came up with a version where I added a comma operator, but this unfortunately also recognises: x,y,z without being in a function.
In the solution below functions are not operators, but an alternative to variables. It still works recursively, parsing the sample expression, and allows you to add other operators (I've added Times as an example). I've also added a couple of parse actions to make the result clearer:
import pyparsing as pp
class Function:
def __init__(self ,t) -> None:
self.name = t[0]
self.args = t[1:]
def __repr__(self) -> str:
args = ','.join([str(i) for i in self.args])
return f"{self.name}({args})"
class Times:
def __init__(self, t) -> None:
self.left = t[0][0]
self.right = t[0][1]
def __repr__(self) -> str:
return f"{self.left} * {self.right}"
test_string = "f(x*y, g(z, y))"
expr = pp.Forward()
variable = pp.Word(pp.alphas)
function = (pp.Word(pp.alphas) + pp.Suppress('(') + pp.delimitedList(expr) + pp.Suppress(')')).setParseAction(Function)
term = pp.infixNotation(
function | variable,
[(pp.Suppress(pp.oneOf('*')), 2, pp.opAssoc.LEFT, Times),],
)
expr <<= term
result = expr.parseString(test_string)
print(result.asList())