如何解决减少冲突的问题:

时间:2012-05-27 03:23:58

标签: bison yacc lalr lr

以下(简化)Bison语法产生减少冲突:

expr
    :    '(' expr ')'
    |    ID
    |    fn
    ;

arg_list
    :    ID
    |    arg_list ID
    ;

fn
    :    '(' ')' fnbody
    |    '(' arg_list ')' fnbody
    ;

fnbody
    :    '{' '}'
    ;

我看到了问题 - 只有一个前瞻标记,无法判断(an_id'(' expr ')'还是fn。但是我该如何解决呢?

1 个答案:

答案 0 :(得分:3)

嗯,最简单的答案就是在解析器中使用更多的前瞻 - 使用btyacc之类的东西,或者使用bison的%glr-parser选项。

第二种选择是在词法分析器中添加前瞻 - 在这种情况下,在返回')'令牌之前,查看下一个令牌是否为'{'并返回一个告诉您的特殊标记这是一个你要结束的arg_list,而不是一个带括号的表达式,或者只是将两个作为单个标记返回并根据需要修改你的语法。

第三种选择是将语法考虑在内。这并不总是容易的,可能会破坏语法的大小。基本思想是识别冲突的规则并将它们组合成一个规则,该规则可以由解析器进行重新规划,并推迟选择最终的构造,直到您看到足够的为止。

对于此示例,您将为冲突案例添加新规则:

expr_or_fnhead:  '(' ID ')'  ;

可能是表达式或fn的开头,然后修改其他规则以使用它。 fn规则变为:

fn :  '(' ')' fnbody               /* 0 arg function */
   |  expr_or_fnhead fnbody        /* 1 arg function */
   |  '(' ID arg_list ')' fnbody   /* 2+ arg function */
   ;

expr规则更复杂:

expr       : ID
           | non_ID_expr
           ;
non_ID_expr: '(' non_ID_expr ')'
           | expr_or_fnhead
           | fn
           ;