所以我的语法出现了可怕的shift/reduce错误。下面是一个最小的测试用例:
%token PLUS MINUS TIMES DIVIDE NUMBER
%token EQUAL NEQUAL GREATER LESS NOT
%left EQUAL NEQUAL
%left GREATER LESS
%left PLUS MINUS
%left TIMES DIVIDE
%left UMINUS NOT
%%
exp : exp binop exp
| unop exp
| NUMBER
;
binop : MINUS
| PLUS
| TIMES
| DIVIDE
| EQUAL
| NEQUAL
| GREATER
| LESS
;
unop : MINUS %prec UMINUS
| NOT
;
%%
然而,通过实验,我设法使这个问题消失了:
%token PLUS MINUS TIMES DIVIDE NUMBER
%token EQUAL NEQUAL GREATER LESS NOT
%left EQUAL NEQUAL
%left GREATER LESS
%left PLUS MINUS
%left TIMES DIVIDE
%left UMINUS NOT
%%
exp : binops
| unops
| NUMBER
;
unops : MINUS exp %prec UMINUS
| NOT exp
;
binops : exp MINUS exp
| exp PLUS exp
| exp TIMES exp
| exp DIVIDE exp
| exp EQUAL exp
| exp NEQUAL exp
| exp GREATER exp
| exp LESS exp
;
%%
谁能解释为什么我有shift/reduce错误放在首位,为什么这工作?这是一个合适的解决方案吗?如果不是,那是什么?
在第一个语法中,优先级声明完全不做任何事情。优先级仅适用于包含结尾且优先级为;在你的第一个语法中,这将是binop
和unop
的结果。但这些产品的替代方案是完全明确的;不需要优先级来决定将PLUS
降为binop
。
在第二种语法中,优先级关系确实有影响,因为相互竞争的歧义替代(binops
和unops
的结果)直接包含了终端。
换句话说,优先级不会"查看"非终结符。