使用Bison编写解析器遇移进/归约冲突问题求助
嘿,我来帮你搞定Bison里的移进/归约冲突问题~
一、如何定位冲突的具体位置
Bison其实提供了非常详细的调试信息,只要生成状态报告就能精准找到冲突点:
- 编译你的解析器时加上
-v参数,比如执行:
这会生成一个名为bison -v your_parser.yyour_parser.output的文件,里面包含了所有状态的项目集、冲突详情。 - 打开这个output文件,直接搜索
shift/reduce conflict,你会看到类似这样的内容:
同时会列出冲突涉及的归约规则和移进动作,结合对应的状态项目集,你就能清楚看到Bison在解析到某个token时,不知道该选择移进(继续读下一个token)还是归约(匹配某个语法规则)。state 23: shift/reduce conflict on token COM
二、为什么合并规则后冲突数量没变化?
从你给出的语法规则来看,冲突的根源不是规则重复,而是语法歧义没有被解决,常见的问题有这几个:
运算符优先级/结合性未定义
你的表达式规则E : E Op E {}里,Op包含AND/OR/RLP/BNP这些运算符,但你没有告诉Bison它们的优先级和结合性。比如解析a AND b OR c时,Bison不知道是先归约a AND b还是移进OR,自然会产生冲突。合并规则根本碰不到这个问题,冲突当然不会减少。空规则与递归结构的歧义
比如你的参数列表规则:Fr : {}; Fr : Fl {}; Fl : Fd COM Fl1 {}; Fl1 : | Fl1 Fd COM {};当解析到
Fd COM后,Bison不知道是应该归约Fl1为空(认为参数列表到这里结束),还是继续移进下一个Fd(认为还有更多参数),这种模糊性直接导致冲突。你合并规则可能只是把Fr的两个规则合并,但没改变Fl1的递归逻辑,冲突自然还在。可选结构的模糊定义
像BM : B | {};这种可选规则,结合到Fd1 : LB NUM BM RB{};里,会让Bison在解析LB NUM RB时,不确定是归约BM为空还是等待Btoken,也会引发冲突。
给你的具体修复建议
声明运算符优先级和结合性
在你的Bison文件开头(%%之前)加上类似这样的声明(优先级从低到高排列,%left表示左结合):%left OR %left AND %left NOT %left RLP BNP重构歧义的递归规则
把参数列表的规则改成更清晰的左递归结构,避免空规则的歧义:Fr : /* 空参数列表 */ | FdList ; FdList : Fd | FdList COM Fd ;同样,语句列表
Ss其实已经是左递归了,但如果有嵌套语句块的歧义,也可以检查下是否能简化。明确可选结构
把BM : B | {};和Fd1的规则合并,写成更明确的形式:Fd1 : LB NUM RB | LB NUM B RB ;去掉多余的空规则,减少Bison的选择困惑。
先按照这个思路,用-v生成output文件找到具体冲突点,再针对性修复,应该就能解决大部分问题啦~
内容的提问来源于stack exchange,提问作者SuzLy

