使用pyparsing解析嵌套函数调用

Jas*_*uit 9 python parsing pyparsing

我正在尝试使用pyparsing以下形式解析函数调用:

f(x, y)
Run Code Online (Sandbox Code Playgroud)

这很简单.但由于它是一个递归下降的解析器,它也应该很容易解析:

f(g(x), y)
Run Code Online (Sandbox Code Playgroud)

这是我无法得到的.这是一个煮沸的例子:

from pyparsing import Forward, Word, alphas, alphanums, nums, ZeroOrMore, Literal

lparen = Literal("(")
rparen = Literal(")")

identifier = Word(alphas, alphanums + "_")
integer  = Word( nums )

functor = identifier

# allow expression to be used recursively
expression = Forward()

arg = identifier | integer | expression
args = arg + ZeroOrMore("," + arg)

expression << functor + lparen + args + rparen

print expression.parseString("f(x, y)")
print expression.parseString("f(g(x), y)")
Run Code Online (Sandbox Code Playgroud)

这是输出:

['f', '(', 'x', ',', 'y', ')']
Traceback (most recent call last):
  File "tmp.py", line 14, in <module>
    print expression.parseString("f(g(x), y)")
  File "/usr/local/lib/python2.6/dist-packages/pyparsing-1.5.6-py2.6.egg/pyparsing.py", line 1032, in parseString
    raise exc
pyparsing.ParseException: Expected ")" (at char 3), (line:1, col:4)
Run Code Online (Sandbox Code Playgroud)

为什么我的解析器将内部表达式的仿函数解释为独立标识符?

Pau*_*McG 11

很好的抓住了你的定义identifier掩盖expression了你的定义arg.以下是解析器的其他一些提示:

x + ZeroOrMore(',' + x)在pyparsing解析器中是一种非常常见的模式,因此pyparsing包含一个辅助方法delimitedList,允许您用该方法替换该表达式delimitedList(x).实际上,delimitedList还有另外一件事 - 它delim基于分隔符在解析时有用的概念来抑制分隔逗号(或者使用可选参数给出的其他分隔符),但在尝试筛选解析数据时只是杂乱的标记然后.因此,您可以将args重写为args = delimitedList(arg),并且您将获得列表中的args,没有逗号可以"跳过".

您可以使用Group该类在已分析的标记中创建实际结构.这将为您构建您的嵌套层次结构,而不必走这个列表寻找'('和')'来告诉您何时在函数嵌套中降低了一个级别:

 arg = Group(expression) | identifier | integer
 expression << functor + Group(lparen + args + rparen)
Run Code Online (Sandbox Code Playgroud)

由于你的args是Group为你编写的,你可以进一步抑制parens,因为就像分隔逗号一样,它们在解析过程中完成它们的工作,但是通过对你的标记进行分组,它们不再是必需的:

lparen = Literal("(").suppress()
rparen = Literal(")").suppress()
Run Code Online (Sandbox Code Playgroud)

我假设'h()'是一个有效的函数调用,只是没有args.您可以使用Optional以下方法允许args为可选:

expression << functor + Group(lparen + Optional(args) + rparen)
Run Code Online (Sandbox Code Playgroud)

现在你可以解析"f(g(x),y​​,h())".

欢迎来到pyparsing!

  • 感谢所有有用的评论!这个例子实际上是根据pyparsing文档改编的; 我使用您在实际解析器中描述的大多数技术.(并且语言实现现在可以在大约6个小时的工作中使用---使用pyparsing在Python中进行原型设计非常快.) (3认同)

Jas*_*uit 5

的定义arg应与左侧以另一个开头的项排列,因此优先匹配:

arg = expression | identifier | integer
Run Code Online (Sandbox Code Playgroud)