You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 03:48:35