Bison语法reduce/reduce冲突排查求助:歧义点定位疑问
咱们先把问题拆解清楚:你写的Bison语法里,NAME同时是formula和term的合法终结符,这就导致了解析器遇到NAME后跟RIGHT_PARENTHESIS时,不知道该把NAME归约成formula还是term——这就是reduce/reduce冲突的根源。
先看你给出的冲突语法:
%token LEFT_PARENTHESIS %token RIGHT_PARENTHESIS %token NAME %token RELATION_INFIX %% formula: term RELATION_INFIX term | NAME | LEFT_PARENTHESIS formula RIGHT_PARENTHESIS ; term: NAME | LEFT_PARENTHESIS term RIGHT_PARENTHESIS ;
从Bison的verbose输出能看到,State 2里当遇到RIGHT_PARENTHESIS时,解析器既可以用formula: NAME(规则2)归约,也可以用term: NAME(规则4)归约——因为两种归约都能匹配后续的括号结构:比如( NAME )既可以是包裹formula的括号,也可以是包裹term的括号,解析器没法提前预判。
解决方案:指定归约优先级,消除歧义
结合你的实际需求(一阶逻辑公式,NAME后续会展开为对应结构),我们可以通过给规则设置优先级,强制Bison选择符合预期的归约方向。
比如你希望( NAME )被解析为formula,那我们就让formula: NAME的优先级高于term: NAME,这样冲突时解析器会优先归约为formula。修改后的语法如下:
%token LEFT_PARENTHESIS %token RIGHT_PARENTHESIS %token NAME %token RELATION_INFIX // 定义优先级,FORMULA的优先级高于TERM %nonassoc FORMULA %nonassoc TERM %% formula: term RELATION_INFIX term | NAME %prec FORMULA // 给该规则绑定高优先级 | LEFT_PARENTHESIS formula RIGHT_PARENTHESIS ; term: NAME %prec TERM // 给该规则绑定低优先级 | LEFT_PARENTHESIS term RIGHT_PARENTHESIS ;
为什么这个方案有效?
Bison在处理reduce/reduce冲突时,会优先选择优先级更高的规则。通过%prec标记给两个NAME归约规则分别绑定不同优先级,我们就明确告诉了解析器:当遇到RIGHT_PARENTHESIS时,优先把NAME归约成formula,完全符合你的预期。
如果你后续需要调整归约方向(比如某些场景下希望优先归约为term),只需要调换FORMULA和TERM在优先级定义中的顺序即可。
额外说明
这个冲突的核心是语法层面的歧义——NAME同时属于两种非终结符的合法推导。因为你的需求中NAME是作为“别名”后续展开,所以语法解析阶段只需要确定一个默认归约方向,实际的类型判断可以在后续的语义分析阶段(展开NAME时)完成,不会影响最终的逻辑正确性。
内容的提问来源于stack exchange,提问作者V. Semeria

