在使用 Menhir 编写解析器代码时,我不断遇到这种设计模式,这变得非常令人沮丧。我正在尝试构建一个接受“a*ba”或“bb”的解析器。为此,我使用以下语法(注意A*
与 相同list(A)
):
exp:
| A*; B; A; {1}
| B; B; {2}
但是,此代码无法解析字符串“ba”。menhir 编译器还指出解析器中存在 shift-reduce 冲突,具体如下:
** In state 0, looking ahead at B, shifting is permitted
** because of the following sub-derivation:
. B B
** In state 0, looking ahead at B, reducing production
** list(A) ->
** is permitted because of the following sub-derivation:
list(A) B A // lookahead token appears
所以| B A
需要一个转变,而| A* B A
当第一个标记是时需要一个减少B
。我可以手动解决这种歧义,并通过将表达式更改为如下所示来获得预期的行为(注意A+
与 相同nonempty_list(A)
):
exp2:
| B; A; {1}
| A+; B; A; {1}
| B; B; {2}
在我的印象中,exp
和exp2
读法一样,但显然区别对待。有没有办法在exp
没有代码重复的情况下编写我想要的东西(这可能会导致其他问题)?这是我应该完全避免的设计模式吗?