以bison -v
运行会生成扩展名为.output
的文件.这可以帮助您找到冲突的原因.就您的情况而言,它以:
State 7 conflicts: 7 shift/reduce
State 8 conflicts: 7 shift/reduce
稍后,对于状态7(类似于状态8):
State 7
8 Lexpr: "head" • Expr
14 UnaryOperator: "head" •
NUMBER shift, and go to state 4
IDENTIFIER shift, and go to state 19
"head" shift, and go to state 20
"tail" shift, and go to state 21
"not" shift, and go to state 9
"islist" shift, and go to state 10
"(" shift, and go to state 11
NUMBER [reduce using rule 14 (UnaryOperator)]
IDENTIFIER [reduce using rule 14 (UnaryOperator)]
"head" [reduce using rule 14 (UnaryOperator)]
"tail" [reduce using rule 14 (UnaryOperator)]
"not" [reduce using rule 14 (UnaryOperator)]
"islist" [reduce using rule 14 (UnaryOperator)]
"(" [reduce using rule 14 (UnaryOperator)]
Expr go to state 22
UnaryOperatorChain go to state 15
UnaryOperator go to state 16
Term go to state 17
状态7对应于由前两行中的两个项目组成的项目集.在这两个项目中,您刚刚阅读了令牌"head"
.以下几行表明Bison不知道在以下情况下该做什么,例如,随后是令牌NUMBER
,或者令牌IDENTIFIER
,等等.
- 它可以转移并进入状态4,其中包含项
19 Term: NUMBER •
,从而继续执行规则8中head
之后的表达;或
- 它可以通过规则14来减少,该规则规定
head
是一元运算符.
这是在告诉你你的表达语言是模棱两可的.有了经验,您应该已经能够找到歧义的原因.如果没有,再次运行bison -Wcounterexamples
也可以帮助您:
First example: Stats "head" • "head" Term ":=" Expr ";" $end
Shift derivation
$accept
↳ 0: Stats $end
↳ 2: Stats Stat ";"
↳ 5: Lexpr ":=" Expr
↳ 8: "head" Expr
↳ 11: UnaryOperatorChain Term
↳ 13: UnaryOperator
↳ 14: • "head"
Second example: Stats "head" • "head" Term ";" $end
Reduce derivation
$accept
↳ 0: Program $end
↳ 1: Stats
↳ 2: Stats Stat ";"
↳ 6: Expr
↳ 11: UnaryOperatorChain Term
↳ 12: UnaryOperatorChain UnaryOperator
↳ 13: UnaryOperator ↳ 14: "head"
↳ 14: "head" •
这告诉您Bison无法决定如何解析字符串前置(例如head head id
).(事实上,作为反例,即使是head id
也适用.)请记住,Bison只能解析LALR(1)语法,即带有一个前瞻符号.当第一个head
被读取并且第二个head
是先行符号时,Bison需要确定这是Lexpr
的一部分(后面会跟着:=
)还是Expr
的一部分(后面会跟着;
).当稍后找到(或没有)标记:=
时,两者之间的差异将变得明显.但是,为了看到这个标记,我们需要任意数量的前瞻符号,因为Lexpr
中head
后面的Expr
的大小可以任意大.
因此,这里的问题是Lexpr
和Expr
生成的语言的公共子集,在Stat
的两个替代规则中.
恐怕这个问题没有简单的解决方案.您必须重新构建语法并消除歧义.我认为你应该try 一下,所以我不会给任何剧透.提示:只要看到像head tail head head ...
这样的开头,尽量避免决定你有哪种表情.