减少/减少语法冲突

时间:2014-09-05 11:51:51

标签: parsing grammar bison yacc

让我们想象一下,我希望能够解析这样的值(每一行都是一个单独的例子):

x
(x)
((((x))))
x = x
(((x))) = x
(x) = ((x))

我写过这个YACC语法:

%%
Line: Binding | Expr
Binding: Pattern '=' Expr
Expr: Id | '(' Expr ')'
Pattern: Id | '(' Pattern ')'
Id: 'x'

但我得到减少/减少冲突:

$ bison example.y
example.y: warning: 1 reduce/reduce conflict [-Wconflicts-rr]

有关如何解决的任何提示?我正在使用GNU bison 3.0.2

2 个答案:

答案 0 :(得分:2)

减少/减少冲突通常意味着语法存在根本问题。

解析的第一步是获取输出文件(bison -v example.y生成example.output)。 Bison 2.3说(部分):

state 7

    4 Expr: Id .
    6 Pattern: Id .

    '='       reduce using rule 6 (Pattern)
    ')'       reduce using rule 4 (Expr)
    ')'       [reduce using rule 6 (Pattern)]
    $default  reduce using rule 4 (Expr)

冲突很明显;在语法读取x(并将其缩减为Id)和)后,它不知道是否将表达式缩减为Expr或作为Pattern。这是一个问题。

我认为你应该在没有ExprPattern的情况下重写语法:

%%
Line: Binding | Expr
Binding: Expr '=' Expr
Expr: Id | '(' Expr ')'
Id: 'x'

答案 1 :(得分:1)

对于任何LR(k),您的语法都不是k。因此,您需要修复语法或使用GLR parser

假设输入以:

开头
(((((((((((((x

到此为止,没有问题,因为每个字符都已移到解析器堆栈上。

但现在呢?在下一步中,必须减少x,前瞻为)。如果将来某个地方有=,则xPattern。否则,它是Expr

您可以通过以下方式修复语法:

  • 摆脱Pattern并将Binding更改为Expr | Expr '=' Expr;

  • 删除Expr的所有定义并将其替换为Expr: Pattern

从长远来看,第二种选择可能更好,因为很可能在你想象(或开发)的完整语法中,PatternExpr的一个子集,而不是与Expr相同。将Expr分解为Pattern的单位生成和非模式替代将允许您使用LALR(1)解析器解析语法(如果语法的其余部分符合)。

或者您可以使用GLR语法,如上所述。