我在理解我知道没有歧义的语法的移位/减少冲突时遇到问题。该案例是 if else 类型之一,但它不是“悬空 else”问题,因为我有强制 END 子句分隔代码块。
这是 gppg 的语法(它是一个类似于 Bison 的编译器编译器......这不是回声):
%output=program.cs
%start program
%token FOR
%token END
%token THINGS
%token WHILE
%token SET
%token IF
%token ELSEIF
%token ELSE
%%
program : statements
;
statements : /*empty */
| statements stmt
;
stmt : flow
| THINGS
;
flow : '#' IF '(' ')' statements else
;
else : '#' END
| '#' ELSE statements '#' END
| elseifs
;
elseifs : elseifs '#' ELSEIF statements else
| '#' ELSEIF statements else
;
这是冲突输出:
// Parser Conflict Information for grammar file "program.y"
Shift/Reduce conflict on symbol "'#'", parser will shift
Reduce 10: else -> elseifs
Shift "'#'": State-22 -> State-23
Items for From-state State 22
10 else: elseifs .
-lookahead: '#', THINGS, EOF
11 elseifs: elseifs . '#' ELSEIF statements else
Items for Next-state State 23
11 elseifs: elseifs '#' . ELSEIF statements else
// End conflict information for parser
我已经切换了所有内容,并且我确实知道如何解决它,但是该解决方案涉及放弃“elseif”上的左递归以进行右递归。
我已经浏览了我在互联网上找到的关于这个问题的所有稀缺文档(我在最后发布了一些链接),但仍然没有找到一个优雅的解决方案。我知道 ANTLR,我现在不想考虑它。请将您的解决方案限制为 Yacc/Bison 解析器。
我会很欣赏优雅的解决方案,我设法通过消除 /* empty */ 规则和复制所有需要空列表的内容来做到这一点,但在我正在研究的更大的语法中,它最终就像“意大利面条语法综合症”一样。
以下是一些链接:
http://nitsan.org/~maratb/cs164/bison.html