今天遇见一个很奇怪的归约/归约冲突,大概类似这样:
...
%left NOT AND
...
expr:
NUM
| expr opt AND expr
;
opt: NOT
| /* empty */
;
...
一直在报归约/归约冲突,我就懵了,哪里冲突了???
直到我仔细研读了一波output文件才弄明白:
当栈里已经有expr
opt
AND
expr
的时候,本来应该按照左结合规则直接进行归约,但是bison却必须读到下一个字符才进行归约。
而如果下一个字符是AND
,那么就出现了问题:
因为此时首先已有的四个token可以归约为expr,与此同时,AND
前还可以归约出一个为空的opt。
然后就出现了问题!(?)
那就是一次归约只能出一个token(就不能归约两次么……),所以出现了归约/归约冲突。
不过这些都是根据output文件推出来的,至于bison为什么会生成这么诡异的规则……emmmmmm……我也不到啊!
但是总而言之,那就是:
在左结合的操作符的左边,不能有可以归约为空的token! 不然会导致归约/归约冲突。
另外,似乎在可以嵌套的括号右侧,也不能有可以归约为空的token(但是我自己还没有测试)
所以如上代码应该改成:
expr:
NUM
| expr opt AND expr
| expr AND expr
;
opt: NOT
;
(如有错漏,还望指摘)