Bison shift/reduce 在 "else" 发生冲突

Bison shift/reduce conflict in "else"

考虑以下语法:

%start stmt;
%right "else";

stmt: "foo"
   | "if" "(" exp ")" stmt
   | "if" "(" exp ")" stmt "else" stmt 

exp: "foo2"

在 运行 bison 上(生成反例)我得到:

parser.yy: warning: 1 shift/reduce conflict [-Wconflicts-sr]
parser.yy: warning: shift/reduce conflict on token "else" [-Wcounterexamples]
  Example: "if" "(" exp ")" "if" "(" exp ")" stmt • "else" stmt
  Shift derivation
    stmt
    ↳ 2: "if" "(" exp ")" stmt
                          ↳ 3: "if" "(" exp ")" stmt • "else" stmt
  Reduce derivation
    stmt
    ↳ 3: "if" "(" exp ")" stmt                         "else" stmt
                          ↳ 2: "if" "(" exp ")" stmt •

这就是野牛手册here中所代表的shift/reduce。但是我在这个语法之后没有“then”。手册说这个问题可以通过定义左右关联性和优先级来解决。在上面,我已经为“else”定义了右结合性,但它对这个移位减少问题没有影响。
我不想通过 shift/reduce 计数来抑制警告,因为它太危险了,因为我的语法太大了。
我能做什么?

在你的反例中,你可以看到野牛不知道它是否应该移动或减少 "if" "(" exp ")",即第一个 ")" 之后的 stmt。 换句话说,如果它应该将您的第一个 if 与 else:

if(exp) (if(exp) stmt) else stmt

或第二个 if 与 else:

if(exp) (if(exp) stmt else stmt)

为了解决这个问题,例如,您还可以为 if 的最后一个终端符号赋予优先级,例如%right "else" ")".
或者,您也可以修改语法以具有 statement-terminator 符号,例如:

stmt: "foo"
   | "if" "(" exp ")" stmt ";"
   | "if" "(" exp ")" stmt "else" stmt ";"