Parsing yacc-没有运算符的规则的优先级?

Parsing yacc-没有运算符的规则的优先级?,parsing,yacc,ply,Parsing,Yacc,Ply,考虑到使用yacc解析正则表达式(实际上我正在使用PLY),其中一些规则如下: expr : expr expr expr : expr '|' expr expr : expr '*' 问题是,第一条规则(串联)必须优先于第二条规则,而不是第三条规则 但是,连接规则中没有运算符 在这种情况下,如何正确指定优先级 谢谢大家! 编辑: 我修改了规则以避免这个问题,但我仍然很好奇问题出在哪里 以下是源代码: tokens = ['PLEFT', 'PRIGHT', 'BAR', 'ASTERISK

考虑到使用yacc解析正则表达式(实际上我正在使用PLY),其中一些规则如下:

expr : expr expr
expr : expr '|' expr
expr : expr '*'
问题是,第一条规则(串联)必须优先于第二条规则,而不是第三条规则

但是,连接规则中没有运算符

在这种情况下,如何正确指定优先级

谢谢大家!

编辑:

我修改了规则以避免这个问题,但我仍然很好奇问题出在哪里

以下是源代码:

tokens = ['PLEFT', 'PRIGHT', 'BAR', 'ASTERISK', 'NORMAL']

t_PLEFT = r'\('
t_PRIGHT = r'\)'
t_BAR = r'\|'
t_ASTERISK = '\*'
t_NORMAL = r'[a-zA-Z0-9]'

lex.lex()

precedence = (
  ('left', 'BAR'),
  ('left', 'CONCAT'),
  ('left', 'ASTERISK'),
)

def p_normal(p):
    '''expr : NORMAL'''
    p[0] = p[1]

def p_par(p):
    '''expr : PLEFT expr PRIGHT'''
    p[0] = p[2]

def p_or(p):
    '''expr : expr BAR expr'''
    p[0] = ('|', p[1], p[3])

def p_concat(p):
    '''expr : expr expr %prec CONCAT'''
    p[0] = ('CONCAT', p[1], p[2])

def p_repeat(p):
    '''expr : expr ASTERISK'''
    p[0] = ('*', p[1])

yacc.yacc()

它对ab | cd*’的解析结果是
('CONCAT'、('|'、('CONCAT'、'a'、'b')、'c')、('*'、'd'))

您没有义务使用优先级来消除歧义;您可以简单地编写明确的语法:

term : CHAR | '(' expr ')'
rept : term | term '*' | term '+' | term '?'
conc : rept | conc rept
expr : conc | expr '|' conc
如果确实要使用优先级,可以使用带有
%prec
注释的“虚构”标记。有关详细信息,请参阅。(此功能来自yacc,因此您也可以在任何yacc/bison文档中阅读。)

请记住,优先级始终是生产(位于解析器堆栈顶部)和先行标记之间的比较。通常情况下,产品的优先级取自产品中最后一个终端的优先级(通常每个适用产品中只有一个终端),因此它似乎是终端之间的比较。但是为了使优先使用“隐形”操作符,需要分别考虑生产优先权和先行令牌优先权。 如上所述,可以使用“虚构”标记设置生产的优先级。但不存在对应于不可见操作符的先行令牌;前瞻标记将是以下操作数中的第一个标记。换句话说,它可以是第一组
expr
中的任何标记,在这种情况下,它是
{NORMAL,PRIGHT}
;必须将此集合添加到优先级声明中,就像它们是串联运算符一样:


一旦这样做,您就可以节省虚构的
CONCAT
令牌,因为您可以使用任何
FIRST(expr)
令牌作为代理,但这可能会被认为不太可读。

谢谢您的回答!我尝试了%prec,我不知道为什么,但在这个例子中,“ab|cd”的工作原理类似于“((ab)| c)d”,而不是“(ab)|(cd)”。没有shift/reduce冲突警告。@noname获得正确的优先级可能很棘手;除非你把你的实际语法贴出来,否则我说不出哪里错了。PLU/YACC将不会报告冲突,如果它是通过优先级来解决的,即使它以一种你认为不正确的方式解决(因为它假设你写下了你的意思)。但是我认为明确的语法是清晰的,没有问题的。。我不得不修改语法,但我仍然很好奇,所以我发布了原始代码。你能告诉我哪里出了问题吗?@noname:对我的答案进行了必要的修改和解释。我认为我对ply关于班次/减少冲突的报告是错误的。Yacc(和野牛)报告冲突,如我所述。很抱歉
precedence = (
  ('left', 'BAR'),
  ('left', 'CONCAT', 'NORMAL', 'PLEFT'),
  ('left', 'ASTERISK'),
)