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 ";"
考虑以下语法:
%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 ";"