【问题标题】:Reduce/reduce conflict in grammar减少/减少语法冲突
【发布时间】:2014-09-05 11:51:51
【问题描述】:

假设我希望能够解析这样的值(每一行都是一个单独的示例):

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

【问题讨论】:

    标签: parsing grammar bison yacc


    【解决方案1】:

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

    解析的第一步是获取输出文件(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'
    

    【讨论】:

    • 谢谢!这确实解决了冲突,但我应该在问题中指出,真实语法中的模式和表达式相似但不相同。
    【解决方案2】:

    对于任何k,您的语法都不是LR(k)。所以你要么需要修正语法,要么使用GLR parser

    假设输入以:

    (((((((((((((x
    

    到这里为止,没有问题,因为每个字符都被移到了解析器堆栈上。

    但是现在呢?在下一步中,x 必须被减少并且前瞻是)。如果将来某个地方有=,那么x 就是Pattern。否则为Expr

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

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

    • 去掉Expr的所有定义,用Expr: Pattern替换它们

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

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

    【讨论】:

    • 谢谢,现在很清楚了。在真实的语法模式和表达式中是相似但不相同的(它们在 AST 中生成不同的节点)。在野牛中启用 GLR 解析器确实解决了问题(我猜性能不会那么好,但我并不关心这是否简化了语法)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多