Go Yacc解析:区分=的赋值与比较并实现左结合
解决
=同时作为赋值与比较运算符的语法区分问题 要区分同一符号在不同上下文的语义,核心是通过语法规则的上下文约束实现,同时保留左结合特性。以下是具体修改方案:
核心思路
- 拆分语法结构:将赋值操作归为语句分支,比较操作归为表达式分支
- 利用左递归规则配合
%left声明实现左结合 - 通过语法上下文限制
=的语义:仅在语句顶层(左侧为标识符)时解析为赋值,在表达式(如if条件、逻辑表达式)中解析为比较
修改后的语法规则示例
%{ import "fmt" // 导入必要包,定义AST节点结构等 %} %token IDENTIFIER NUMBER %token IF AND SEMICOLON // 左结合声明,同时作用于赋值和比较的左结合需求 %left AND %left EQUAL %% // 程序入口:多个语句组成 program: | program statement ; // 语句类型:赋值语句或if判断语句 statement: assignment SEMICOLON | if_statement ; // 赋值语句:左递归实现左结合,满足a = ((b = c) = d) = w的解析要求 assignment: IDENTIFIER EQUAL assignment // 左结合嵌套:a = b = c → a = (b = c) | IDENTIFIER EQUAL expr ; // if判断语句:条件部分为表达式(其中的=是比较) if_statement: IF expr ; // 表达式层级:从逻辑表达式到相等比较 expr: logical_expr ; logical_expr: equality_expr | logical_expr AND equality_expr ; // 比较表达式:左递归实现左结合,满足(foo = bar) = baz的解析要求 equality_expr: primary_expr | equality_expr EQUAL primary_expr ; // 基础表达式:标识符或数字 primary_expr: IDENTIFIER | NUMBER ; %% // 词法分析器实现(略):将=识别为EQUAL token即可,无需区分语义 func yylex() int { // 实现词法逻辑,返回对应token类型 return 0 } func yyerror(s string) { fmt.Printf("parse error: %s\n", s) }
关键细节说明
- 上下文区分语义
- 当
=出现在assignment规则中(左侧为标识符,作为顶层语句),被解析为赋值操作 - 当
=出现在equality_expr规则中(作为表达式的一部分,比如if条件里),被解析为比较操作
- 当
- 左结合实现
- 赋值规则采用左递归写法
IDENTIFIER EQUAL assignment,配合%left EQUAL确保嵌套顺序为左结合 - 比较规则同样用左递归
equality_expr EQUAL primary_expr,实现多=条件的左结合解析
- 赋值规则采用左递归写法
- AST语义区分
在语法规则的语义动作中,分别生成赋值节点和比较节点,比如:
后续语义分析阶段即可通过不同节点类型区分两种操作。assignment: IDENTIFIER EQUAL assignment { $$ = &AssignNode{Left: $1, Right: $3} } | IDENTIFIER EQUAL expr { $$ = &AssignNode{Left: $1, Right: $3} } ; equality_expr: primary_expr { $$ = $1 } | equality_expr EQUAL primary_expr { $$ = &CompareNode{Left: $1, Right: $3} } ;
内容的提问来源于stack exchange,提问作者Artem
相关产品推荐
相关产品推荐

