为什么 bison 与无歧义语法有 shift/reduce 冲突?
Why does bison have shift/reduce conflict with unambiguous grammar?
我正在使用 bison,我 运行 陷入了 shift/reduce 冲突。 Bison 发现了一个 shift/reduce 冲突。我找不到这种语言的歧义:
start
: IDENT trailer EQUAL atom trailer SEMICOLON
| atom trailer SEMICOLON
;
atom
: LPAR atom trailer RPAR
| IDENT
;
trailer
: %empty
| LPAR RPAR
;
这个问题在底部附近的python grammar documentation中也有描述。我可以使用本文档描述的解决方案消除歧义(将第 2 行更改为 atom trialer EQUAL atom trailer SEMICOLON
.
现在它已修复,我可以继续前进,但我仍然对这个问题感到好奇。请向我描述上面语法的问题,并用具有两个独特解析树的语言给出例句。
编辑 1
进一步排查,下面有shift/reduce冲突:
start
: IDENT LPAR RPAR EQUAL atom LPAR RPAR SEMICOLON
| atom LPAR RPAR SEMICOLON
;
atom
: IDENT
;
但这没有 shift/reduce 冲突:
start
: IDENT LPAR RPAR EQUAL IDENT LPAR RPAR SEMICOLON
| IDENT LPAR RPAR SEMICOLON
;
这对我来说似乎很可疑,因为在第一个语法原子中被迫产生 IDENT,所以这两个本质上是相同的语法。我还需要一些解释。
Shift/reduce 冲突并不一定意味着你的语法有歧义。所有有歧义的语法都会产生 shift/reduce 或 reduce/reduce 冲突,但反之则不一定正确。
在您的情况下,假设解析器已经启动并且刚刚读取了一个 IDENT 令牌,然后是 LPAR。它有两种选择。首先,您可能正在生成起始非终结符的第一个(较长)分支。在这种情况下,您应该根据稍后减少整个长表达式的计划来转移 LPAR。其次,可能是您正在生成起始非终结符的第二个(较短的)分支,这意味着您应该将 IDENT 缩减回原子。仅仅知道下一个终端是 LPAR 并不能帮助您区分这些情况,因此 shift/reduce 冲突。
另一方面,在有更多上下文可用之前,您的语法的第二个版本不需要决定如何处理前面的 IDENT,因此没有冲突。
我正在使用 bison,我 运行 陷入了 shift/reduce 冲突。 Bison 发现了一个 shift/reduce 冲突。我找不到这种语言的歧义:
start
: IDENT trailer EQUAL atom trailer SEMICOLON
| atom trailer SEMICOLON
;
atom
: LPAR atom trailer RPAR
| IDENT
;
trailer
: %empty
| LPAR RPAR
;
这个问题在底部附近的python grammar documentation中也有描述。我可以使用本文档描述的解决方案消除歧义(将第 2 行更改为 atom trialer EQUAL atom trailer SEMICOLON
.
现在它已修复,我可以继续前进,但我仍然对这个问题感到好奇。请向我描述上面语法的问题,并用具有两个独特解析树的语言给出例句。
编辑 1
进一步排查,下面有shift/reduce冲突:
start
: IDENT LPAR RPAR EQUAL atom LPAR RPAR SEMICOLON
| atom LPAR RPAR SEMICOLON
;
atom
: IDENT
;
但这没有 shift/reduce 冲突:
start
: IDENT LPAR RPAR EQUAL IDENT LPAR RPAR SEMICOLON
| IDENT LPAR RPAR SEMICOLON
;
这对我来说似乎很可疑,因为在第一个语法原子中被迫产生 IDENT,所以这两个本质上是相同的语法。我还需要一些解释。
Shift/reduce 冲突并不一定意味着你的语法有歧义。所有有歧义的语法都会产生 shift/reduce 或 reduce/reduce 冲突,但反之则不一定正确。
在您的情况下,假设解析器已经启动并且刚刚读取了一个 IDENT 令牌,然后是 LPAR。它有两种选择。首先,您可能正在生成起始非终结符的第一个(较长)分支。在这种情况下,您应该根据稍后减少整个长表达式的计划来转移 LPAR。其次,可能是您正在生成起始非终结符的第二个(较短的)分支,这意味着您应该将 IDENT 缩减回原子。仅仅知道下一个终端是 LPAR 并不能帮助您区分这些情况,因此 shift/reduce 冲突。
另一方面,在有更多上下文可用之前,您的语法的第二个版本不需要决定如何处理前面的 IDENT,因此没有冲突。