在YACC中实现自增(++)运算符时出现shift/reduce conflicts的原因咨询
在YACC中实现自增(++)运算符时出现shift/reduce conflicts的原因咨询
嘿,我来帮你拆解一下为啥会出现这些移进/归约冲突~
首先看你的YACC代码,核心冲突主要来自这几个点:
1. 取模运算符%的优先级未声明
你在语法规则里实现了取模运算expr '%' expr,但完全没在优先级声明里给它指定位置!YACC对未声明优先级的运算符,会默认用它在语法规则里出现的顺序来判断优先级,这就会和同层级的*、/产生歧义。比如解析a * b % c时,YACC根本不知道该先归约a*b还是移进%,直接就触发冲突了。
2. 后缀自增与二元加号的潜在歧义
虽然你的lex代码已经处理了单个+和++的区分(遇到+时预读下一个字符,是+就返回INC,否则放回字符返回+),但YACC在语法分析阶段,当看到表达式后面跟着+这个token时,还是会陷入两难:它没法提前知道下一个token是INC的一部分还是二元+的右操作数。不过这个问题本身被lex的预读缓解了,但结合其他歧义,会让冲突数量变多。
3. 列表规则和换行的多路径归约
你的list规则允许空行(list '\n')和表达式行(list expr '\n'),当YACC遇到换行符时,有时候会有多种归约选择:比如既可以归约前面的表达式组成完整行,也可以直接归约空列表加换行。这种多路径的选择也是冲突的来源之一。
解决建议
- 先给
%补全优先级,把它和*、/放在同一组(左结合,优先级相同):%left '*' '/' '%' - 把一元减的结合性改成
%right(虽然当前左结合结果没问题,但符合一元运算符的常规习惯,避免潜在歧义):%right UNARYMINUS - 可以顺便加个一元加号的规则,避免输入
+5这类表达式时的语法错误,也能减少潜在冲突:
在expr规则里加一行:| '+' expr %prec UNARYMINUS { $$ = $2; }
改完后重新用yacc生成代码,应该就能解决大部分冲突了~
备注:内容来源于stack exchange,提问作者M.E.
相关产品推荐
相关产品推荐

