yacc - 规则从未减少并且 shift/reduce 冲突

yacc - rules never reduced and shift/reduce conflicts

我在处理 yaac 时遇到了问题,因为我不断收到这条提示:

1 条规则从未减少。 29 shift/reduce 次冲突。

那么,有人可以帮我解决这个问题吗?

这是我正在研究的语法:

%start P
%token DEF IF THEN ELSE WHILE DO FOR
%token Punctuation_element
%token Operator
%token EQL_EQL GREATER_THAN_OR_EQUALS LESS_THAN_OR_EQUALS NOT_EQUALS 
%token<sval> Identifier
%token<ival> Literal

%left '-' '+'
%left '*' '/' '%'
%right ELSE

%%

P :   D ';' P 
|     D
;

D :  DEF Identifier '(' ARGS ')' '=' E ';'
;

ARGS: Identifier ',' ARGS 
|     Identifier
;

E:    Literal
|     Identifier
|     IF E OP E THEN E ELSE E 
|     FOR E DO E
|     DO E WHILE E
|     E '+' E 
|     E '-' E
|     E '*' E
|     E '/' E
|     E '%' E
|     Identifier '(' E ')'
|     E ',' E
;

/* C:   E ',' C 
|   E  
; */

OP:   EQL_EQL 
|     '>' 
|     '<' 
|     GREATER_THAN_OR_EQUALS 
|     LESS_THAN_OR_EQUALS 
|     NOT_EQUALS 
|     '%'
;

你有两个基本问题:

  1. % 既是比较运算符 (OP) 又是算术运算符 (E '%' E)。这造成了歧义,bison 解决了支持算术运算符的问题,因为 bison 更喜欢 shift 而不是 reduce。该分辨率使得无法减少 OP : '%',这是不减少的规则。

  2. 您使 , 成为算术运算符 (E ',' E),但您没有为其声明优先级。这导致大量移位减少了涉及 , 和另一个运算符的表达式的冲突。我怀疑您是否真的希望 , 成为操作员;我认为您添加了涉及它的产生式是为了允许使用多个参数调用函数。那是行不通的。为参数列表创建一个单独的非终端,并在函数调用的生产中使用它而不是使用 E.

    (其实你有这样一个非终结符,神秘的叫C,但是它被注释掉了,没有被使用,所以取消注释,使用它。并考虑给它起一个更有意义的名字。)

像 bison 这样的 LALR 解析器生成器通常更喜欢左递归而不是右递归。您应该考虑将您的两个列表产生式(CARGS)更改为左递归,除非您有充分的理由不这样做。