解析暗示与显式时间运算符

时间:2013-04-10 02:32:42

标签: python parsing ply lalr

我一直在使用ply编写LALR解析器,并且在尝试解析乘法时遇到了不一致。

由于完整的解析器link有几千行,我不会在这里包含它,但我创建了一个简单的演示:

import ply.lex as lex
import ply.yacc as yacc

tokens = (
    'int',
    'times',
    'plus',
)

precedence = (
    ('left', 'plus'),
    ('left', 'times'),
)

t_ignore = ' \t\n '
t_int = r' \d+ '
t_plus = r' \+ '
t_times = ' \* '

def p_int(args):
    'expr : int'
    args[0] = int(args[1])

def p_times(args):
    '''expr : expr times expr
            | expr expr %prec times'''
    if len(args) == 3:
        args[0] = args[1] * args[2]
    elif len(args) == 4:
        args[0] = args[1] * args[3]

def p_plus(args):
    'expr : expr plus expr'
    args[0] = args[1] + args[3]

lex.lex()
parser = yacc.yacc()

while True:
    s = raw_input('>> ')
    print " = ", parser.parse(s)

没有转移/减少冲突或减少/减少PLY报告的冲突但我得到以下不一致:

    >>  1 + 2 3
     =  9
    >>  1 + 2 * 3
     =  7

这对我来说很奇怪,因为显式和隐式时间规则具有相同的优先级。 但我认为这可能是因为PLY为'times'标记赋予优先权,从而将其转移到堆栈上,以支持使用p_plus规则减少表达式。我该如何解决这个问题?

编辑:更简单的演示。

2 个答案:

答案 0 :(得分:1)

快速入侵:将int标记添加到优先规范(优先级为时间)。然后int标记将被适当地移动到符号堆栈上。那是(根据原始问题),

precedence = (
    ('left', 'plus'),
    ('left', 'times', 'int'),
)

这可行但在处理潜在的大量令牌时很麻烦(开放式括号, 符号,花车等。)。

>>  1 + 2 3
 =  7

我仍然想知道是否有更优雅的解决方案。

答案 1 :(得分:0)

还有一个更合适的解决方案:放弃运算符优先级,并以通常的方式定义非终结符exprtermfactor。原因?隐式乘法没有优先权决策所依据的特征性令牌,您也不想手动恢复非终结符的FIRST集。此外,随着语法的增长,第一组也会随之增长。

在BNF中,请考虑以下类似内容:

expr -> term | expr + term | expr - term
term -> factor | term * factor | term factor | term / factor
factor -> number | variable | ( expr )

顺便说一句,您可能想制作一个额外的非终端层来表示这样一个事实,即隐含的邻接乘法通常被认为比除法具有更高的优先级,而显式乘法通常被解释为具有相同的优先级。

这并非特定于任何特定的解析器生成器框架。