今天遇見一個很奇怪的歸約/歸約衝突,大概類似這樣:
...
%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
;
(如有錯漏,還望指摘)