让我们想象一下,我希望能够解析这样的值(每一行都是一个单独的例子):
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
答案 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
。这是一个问题。
我认为你应该在没有Expr
和Pattern
的情况下重写语法:
%%
Line: Binding | Expr
Binding: Expr '=' Expr
Expr: Id | '(' Expr ')'
Id: 'x'
答案 1 :(得分:1)
对于任何LR(k)
,您的语法都不是k
。因此,您需要修复语法或使用GLR
parser。
假设输入以:
开头(((((((((((((x
到此为止,没有问题,因为每个字符都已移到解析器堆栈上。
但现在呢?在下一步中,必须减少x
,前瞻为)
。如果将来某个地方有=
,则x
为Pattern
。否则,它是Expr
。
您可以通过以下方式修复语法:
摆脱Pattern
并将Binding
更改为Expr | Expr '=' Expr;
删除Expr
的所有定义并将其替换为Expr: Pattern
从长远来看,第二种选择可能更好,因为很可能在你想象(或开发)的完整语法中,Pattern
是Expr
的一个子集,而不是与Expr
相同。将Expr
分解为Pattern
的单位生成和非模式替代将允许您使用LALR(1)
解析器解析语法(如果语法的其余部分符合)。
或者您可以使用GLR语法,如上所述。