PyParsing简单的语言表达式

时间:2009-09-04 00:46:21

标签: python parsing pyparsing

我正在尝试编写一些可以解析一些代码的东西。我能够成功解析foo(spam)spam+eggs,但foo(spam+eggs)(递归下降?我的编译器术语有点生疏)失败。

我有以下代码:

from pyparsing_py3 import *

myVal = Word(alphas+nums+'_')    
myFunction = myVal + '(' + delimitedList( myVal ) + ')'

myExpr = Forward()
mySubExpr = ( \
    myVal \
    | (Suppress('(') + Group(myExpr) + Suppress(')')) \
    | myFunction \
    )
myExpr << Group( mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) )


# SHOULD return: [blah, [foo, +, bar]]
# but actually returns: [blah]
print(myExpr.parseString('blah(foo+bar)'))

2 个答案:

答案 0 :(得分:4)

几个问题:delimitedList正在寻找逗号分隔的myVal列表,即标识符,作为唯一可接受的参数列表形式,所以当然它不能匹配'foo + bar'(不是逗号分隔的列表) myVal!);修复显示另一个 - myVal和myFunction以相同的方式启动,因此他们在mySubExpr中的顺序很重要;修复揭示了另一个 - 两个级别的嵌套而不是一个。这个版本似乎没问题......:

myVal = Word(alphas+nums+'_')    

myExpr = Forward()
mySubExpr = (
    (Suppress('(') + Group(myExpr) + Suppress(')'))
    | myVal + Suppress('(') + Group(delimitedList(myExpr)) + Suppress(')')
    | myVal
    )
myExpr << mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) 

print(myExpr.parseString('blah(foo+bar)'))

根据需要发出['blah', ['foo', '+', 'bar']]。我还删除了冗余反斜​​杠,因为在括号内无论如何都会发生逻辑行延续;它们无害但却妨碍了可读性。

答案 1 :(得分:4)

我发现使用'&lt;&lt;&lt;'时养成良好的习惯使用Forwards的运算符总是将RHS括在括号中。那就是:

myExpr << mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr )

更好:

myExpr << ( mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) )

这是我不幸选择'&lt;&lt;'的结果作为用于将表达式插入Forward的“插入”运算符。在这种特殊情况下,括号是不必要的,但在这一个中:

integer = Word(nums)
myExpr << mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) | integer

我们明白为什么我说“不幸”。如果我将其简化为“A&lt;&lt;&lt;&lt; B | C”,我们很容易看出操作的优先级导致评估被执行为“(A <&lt;&lt; B)| C”,因为'&lt;&lt;&lt;&lt;优先级高于“|”。结果是,前向A只获得插入其中的表达式B. “| C”部分确实执行了,但是会发生“A | C”,它会创建一个MatchFirst对象,然后立即将其丢弃,因为它没有分配给任何变量名。解决方案是将括号内的语句分组为“A&lt;&lt;(B | C)”。在仅使用“+”操作组成的表达式中,实际上不需要括号,因为“+”的优先级高于“&lt;&lt;”。但这只是幸运的编码,当有人后来使用'|'添加替代表达式时会导致问题并没有意识到优先含义。所以我建议采用“A&lt;&lt;(expression)”这一格式来避免这种混淆。

(总有一天我会编写pyparsing 2.0 - 这将允许我破坏现有代码的兼容性 - 并将其更改为使用'&lt;&lt; ='运算符,它修复了所有这些优先级问题,因为'&lt;&lt; ; ='的优先级低于pyparsing使用的任何其他运算符。)