使用Forward进行Pyparsing解析递归表达式

时间:2017-05-02 19:29:26

标签: python pyparsing

我试图以递归方式解析表达式。我按照了几个教程,看起来像Forward()是我需要的类。然而,看似简单的事情给我带来了麻烦。

这是我写的代码

from pyparsing import *
exp = Forward()
integer = Word(nums)
exp << (integer | (exp + '+' + exp))
input = "1+1"
print exp.parseString(input)

我希望它返回['1','+','1']但它只返回['1']

非常感谢帮助。

1 个答案:

答案 0 :(得分:0)

这里有几个问题。按重要性递增顺序:

    如果在解析的内容之后有额外的文本,
  1. parseString不会引发异常。使用exp.parseString(input, parseAll=True)
  2. &#39; |&#39;是MatchFirst,而不是MatchLongest。由于您的整数是第一个,因此它将首先匹配。然后解析器失败了&#39; +&#39;一个人。如果您希望匹配时间最长,请使用&#39; ^&#39;操作者。
  3. The Biggie:一旦你转换为&#39; ^&#39; (或者重新排序表达式以使exp + exp首先放在整数之前),你会发现自己炸掉了最大的递归深度。那是因为这个解析器具有exp的左递归定义。也就是说,要解析exp,它必须解析exp,它必须解析exp等。通常,许多已发布的BNF使用递归来描述这种类型重复结构,但pyparsing没有做必要的前瞻/回溯工作。试试exp <<= integer + ZeroOrMore('+' + integer) | '(' + exp + ')' - 这个表达式是左递归的,因为在解析嵌套的exp之前你必须经过一个左括号。
  4. 编辑: 对不起,我之前的建议有点太快了,这是进行递归表达式解析的正确方法:

    from pyparsing import *
    
    exp = Forward()
    LPAR, RPAR = map(Suppress, "()")
    integer = Word(nums)
    term = integer | Group(LPAR + exp + RPAR)
    exp << term + ZeroOrMore('+' + term)
    
    input = "(1+1) + 1"
    print(exp.parseString(input))
    

    打印

    [['1', '+', '1'], '+', '1']
    

    如果您浏览代码,则会看到递归:exp使用term定义,term使用exp定义。 fourFn.py示例最接近此样式;自写这篇文章以来,我已经将infixNotation方法添加到pyparsing中,这将允许你写:

    exp = infixNotation(integer, [
                        ('+', 2, opAssoc.LEFT),
                        ])
    

    infixNotation在内部处理递归定义,隐式定义'(' + exp + ')'表达式,并且可以轻松实现具有操作优先级的运算符系统。