Bison规则间归约/归约冲突解决求助:%prec尝试无效
解决YACC/Bison中的归约-归约冲突(类型与表达式歧义)
我试过所有可能的%prec组合都无效,清楚这里存在冲突,但不知道怎么解决——核心矛盾在于后续是类型后跟标识符还是分号。
最小复现语法
%require "3.0" %defines %define api.pure full %define parse.trace %left TYPE_UNIT %% example : statement ; statement : type identifier '=' expression ';' | identifier '=' expression ';' | expression ';' ; expression : expression '.' identifier | identifier ; type : fqtypename %prec TYPE_UNIT ; fqtypename : identifier | fqtypename '.' identifier ; identifier: "blah" ; %%
冲突错误信息
State 7 3 statement: identifier • '=' expression ';' 6 expression: identifier • 8 fqtypename: identifier • '=' shift, and go to state 13 '.' reduce using rule 6 (expression) '.' [reduce using rule 8 (fqtypename)] "blah" reduce using rule 8 (fqtypename) $default reduce using rule 6 (expression) reduce/reduce conflict on token '.': 6 expression: identifier • 8 fqtypename: identifier • First example: identifier • '.' identifier ';' $end First reduce derivation $accept ↳ 0: example $end ↳ 1: statement ↳ 4: expression ';' ↳ 5: expression '.' identifier ↳ 6: identifier • Second example: identifier • '.' identifier identifier '=' expression ';' $end Second reduce derivation $accept ↳ 0: example $end ↳ 1: statement ↳ 2: type identifier '=' expression ';' ↳ 7: fqtypename ↳ 9: fqtypename '.' identifier ↳ 8: identifier •
冲突原因与解决方法
冲突根源
当解析器读到identifier • '.'时,无法判断当前的identifier应该归约为expression还是fqtypename:
- 如果后续是
identifier ';',它是expression的一部分(比如blah.blah;) - 如果后续是
identifier '=' ... ';',它是type的一部分(比如blah.blah blah = ...;)
%prec在这里无效,因为优先级声明只处理移进-归约冲突,而归约-归约冲突是解析器无法从后续token中明确选择归约路径导致的。
解决方案:重构语法消除歧义
拆分statement规则,让解析器通过语法结构直接区分不同场景:
%require "3.0" %defines %define api.pure full %define parse.trace %% example : statement ; statement : declaration_stmt | assignment_stmt | expression_stmt ; // 专门处理类型+标识符的声明语句 declaration_stmt : fqtypename identifier '=' expression ';' ; // 处理标识符赋值语句 assignment_stmt : identifier '=' expression ';' ; // 处理表达式语句 expression_stmt : expression ';' ; expression : expression '.' identifier | identifier ; fqtypename : identifier | fqtypename '.' identifier ; identifier: "blah" ; %%
方案说明
去掉冗余的type中间规则,直接将fqtypename绑定到声明语句中。这样解析器遇到identifier后:
- 若下一个token是
identifier,会优先归约为fqtypename匹配声明规则 - 若下一个token是
=,会归约为identifier匹配赋值规则 - 若下一个token是
.,会归约为expression匹配表达式规则
通过语法结构明确分支,从根源消除了归约-归约冲突,无需依赖优先级声明。
内容的提问来源于stack exchange,提问作者Enerccio
相关产品推荐
相关产品推荐

