用Pyparsing解析逻辑表达式

时间:2016-08-22 19:55:32

标签: python-2.7 pyparsing

首先,这不是家庭作业,我试图学习pyparsing而且我被困在这里。

我的问题如下,我试图解析(abc or def) or def)等语句

我的程序去了一个中缀表达式a or b,因为双方都可以是表达式本身,它们也可以是中缀表达式,解析器会递归,直到达到递归深度并且没有工作完成。

以下代码:

# infix operators are automatically created and dealt with
infix_operators  = ['and', '&', 'or', '|', 'implies', '->']

variable  = Word(alphas)
infix_op  = oneOf(infix_operators, caseless=True)

expr         = Forward()
infix_expr   = (expr + infix_op + expr)
complex_expr = nestedExpr('(', ')', content=expr)
expr        << (infix_expr | complex_expr | variable)

print str(expr.parseString("(abc or def) or def)")[0])

我的问题很简单;如何在这种情况下避免无限循环?

1 个答案:

答案 0 :(得分:1)

规范解决方案是实现此BNF的东西:

atom   := variable | 'True' | 'False' | '(' expr ')'
factor := [ 'not' ]... atom
term   := factor [ '&' factor ]...
expr   := term [ '|' term ]...

解决了左递归问题,因为即使expr最终通过term递归 - &gt; factor - &gt; atom,当它到达expr时,它首先必须解析一个前导符号(&#39;所以expr永远不必首先解析更深的expr在首先解析其他一些元素之前。

这个BNF几乎直接翻译为pyparsing:

and_ = Keyword('and')
or_ = Keyword('or')
not_ = Keyword('not')
true_ = Keyword('true')
false_ = Keyword('false')

not_op = not_ | '~'
and_op = and_ | '&'
or_op = or_ | '|'

expr = Forward()

identifier = ~(and_ | or_ | not_ | true_ | false_) + Word(alphas)
atom = identifier | Group('(' + expr + ')')
factor = Group(ZeroOrMore(not_op) + atom)
term = Group(factor + ZeroOrMore(and_op + factor))
expr <<= Group(term + ZeroOrMore(or_op + term))

或者你可以使用pyparsing的infixNotation助手:

expr = infixNotation(true_ | false_ | identifier,
    [
    (not_op, 1, opAssoc.RIGHT),
    (and_op, 2, opAssoc.LEFT),
    (or_op, 2, opAssoc.LEFT),
    ])

infixNotation由一个基本操作数构成(在本例中,是一个alpha变量名或一个布尔文字truefalse),后跟一个{{ 1}}元组,按运算符优先顺序给出。 (operator, arity, associativity)负责所有递归定义,右关联运算符与左关联运算符的解析,并对运算符进行一些预测,以避免在没有运算符的情况下对给定优先级的操作进行额外嵌套

您可以使用pyparsing的infixNotation方法测试此表达式:

runTests

,并提供:

expr.runTests("""
    p and not q
    not p or p
    r and (p or q)
    r and p or q
    not q
    q
    """, fullDump=False)