如何正确解决Bison语法中的移进/归约冲突?
Bison移进/归约冲突的优化解决方法
你遇到的冲突本质是:当解析到WORD = NUM后遇到下一个NUM时,Bison面临两个选择——要么把栈顶的NUM归约为VALUES,再把WORD = VALUES归约成PARAM;要么先移进新的NUM,再和栈里的NUM归约成更长的VALUES。默认移进符合预期,除了用%expect 1隐藏警告,还有两种更优的实践方式:
方法一:通过优先级声明强制移进优先
可以给相关产生式设置不同优先级,让Bison明确选择移进操作:
- 在token声明后添加优先级标记(用虚拟层级区分高低):
%token EQUAL "=" NUM "NUM" WORD "WORD" ; %left LOW_PREC %right HIGH_PREC
- 给
VALUES的多元素产生式设置高优先级,给PARAM的WORD = VALUES产生式设置低优先级:
VALUES: NUM | VALUES NUM %prec HIGH_PREC // 标记该产生式优先级更高 ; PARAM: NUM | WORD EQUAL VALUES %prec LOW_PREC // 标记该产生式优先级更低 ;
这样Bison会优先选择移进新的NUM(移进优先级对应NUM的默认优先级,而归约PARAM的优先级更低),从而消除冲突和警告。
方法二:改写语法结构消除歧义
调整语法,让WORD =后的VALUES只能在完整接收所有NUM后才归约为PARAM,避免中间归约的可能:
VALUES: NUM | VALUES NUM ; // 拆分为两种明确的PARAM类型,从根源避免歧义 PARAM: NUM | WORD_EQUAL_VALUES ; WORD_EQUAL_VALUES: WORD EQUAL NUM | WORD_EQUAL_VALUES NUM ;
这种写法让WORD =后的NUM必须逐个移进,直到遇到非NUM的token才会归约为WORD_EQUAL_VALUES(即原语法中的PARAM),彻底消除了歧义场景,不需要依赖优先级声明。
两种方法都能避免使用%expect 1,其中方法一更贴近原语法结构,方法二则通过明确的语法定义从根源解决问题。
内容的提问来源于stack exchange,提问作者Дмитрий Глущенко
相关产品推荐
相关产品推荐

