Parsing 减少/减少语法冲突

Parsing 减少/减少语法冲突,parsing,grammar,bison,yacc,Parsing,Grammar,Bison,Yacc,让我们想象一下,我希望能够像这样解析值(每一行都是一个单独的示例): 我写了以下YACC语法: %% Line: Binding | Expr Binding: Pattern '=' Expr Expr: Id | '(' Expr ')' Pattern: Id | '(' Pattern ')' Id: 'x' 但是我得到了一个reduce/reduce冲突: $ bison example.y example.y: warning: 1 reduce/reduce conflict [

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

我写了以下YACC语法:

%%
Line: Binding | Expr
Binding: Pattern '=' Expr
Expr: Id | '(' Expr ')'
Pattern: Id | '(' Pattern ')'
Id: 'x'
但是我得到了一个reduce/reduce冲突:

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

有没有关于如何解决这个问题的提示?我正在使用GNU bison 3.0.2

Reduce/Reduce冲突通常意味着语法中存在一个基本问题

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

冲突是显而易见的;语法读取
x
(并将其减少为
Id
)和
后,它不知道是将表达式减少为
Expr
还是减少为
模式。这带来了一个问题

我认为你应该重写语法,不要使用
Expr
Pattern

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

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

假设输入以以下内容开始:

(((((((((((((x
到目前为止,没有问题,因为每个字符都已转移到解析器堆栈上

但是现在呢?在下一步中,
x
必须减少,并且向前看是
。如果将来某个地方有一个
=
x
是一个
模式
。否则,它是一个
Expr

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

  • 摆脱
    模式
    并将
    绑定
    更改为
    Expr | Expr'='Expr

  • 去掉
    Expr
    的所有定义,并将其替换为
    Expr:Pattern

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


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

谢谢!这确实解决了冲突,但我应该在问题中注意到,实际语法中的模式和表达式是相似的,但不完全相同。谢谢,现在已经很清楚了。在实际语法中,模式和表达式相似但不完全相同(它们在AST中生成不同的节点)。在bison中启用GLR解析器确实解决了这个问题(我想性能不会那么好,但我并不在乎这是否简化了语法)。
%%
Line: Binding | Expr
Binding: Expr '=' Expr
Expr: Id | '(' Expr ')'
Id: 'x'
(((((((((((((x