17370845950

如何使用Golang实现解释器语法解析_使用Interpreter Pattern分析表达式
Go用Interpreter模式实现表达式解释器:先Lexer将字符串转为Token流,再Parser按优先级递归下降构建AST,最后通过Expr接口的Eval方法递归求值,支持扩展运算符且无需修改现有逻辑。

用 Go 实现解释器模式解析表达式,核心是把字符串形式的算术表达式(如 "3 + 5 * 2")拆解成树结构,再递归求值。不依赖第三方 parser,纯手工构建词法分析(Lexer)+ 语法分析(Parser),符合 Interpreter Pattern 的经典四要素:抽象表达式、终结符、非终结符、上下文。

词法分析:把输入切分成 Token

先定义基础 Token 类型:

type TokenType string
const (
  TOKEN_NUMBER TokenType = "NUMBER"
  TOKEN_PLUS              = "PLUS"
  TOKEN_STAR             = "STAR"
  TOKEN_LPAREN         = "LPAREN"
  TOKEN_RPAREN         = "RPAREN"
)
type Token struct { Type TokenType; Value string }

Lexer 遍历字符串,跳过空格,识别数字(支持多位)、运算符和括号。关键点:

  • 数字要连续读取直到非数字字符
  • 区分 - 是减号还是负号——简单场景可暂不支持负数,或结合 Parser 处理
  • 返回 []Token,末尾加一个 TOKEN_EOF 方便 Parser 终止

语法分析:构造抽象语法树(AST)

按优先级自顶向下递归下降(Recursive Descent)。推荐实现三个层级函数:

  • ParseExpression():处理 +-(最低优先级),调用 ParseTerm
  • ParseTerm():处理 */(中等优先级),调用 ParseFactor
  • ParseFactor():处理数字、括号(最高优先级),遇到 ( 就递归调用 ParseExpression

每个函数返回一个实现了 Expr 接口的 AST 节点。例如:

type Expr interface { Eval() int }
type NumberExpr struct { Value int }
func (n NumberExpr) Eval() int { return n.Value }
type BinaryExpr struct { Left, Right Expr; Op string }
func (b BinaryExpr) Eval() int {
  switch b.Op {
  case "+": return b.Left.Eval() + b.Right.Eval()
  case "*": return b.Left.Eval() * b.Right.Eval()
  default: panic("unknown op")
  }
}

解释执行:调用 Eval() 递归求值

AST 构建完成后,只需对根节点调用 .Eval()。所有运算逻辑封装在各 Expr 实现里,完全符合 Interpreter Pattern 的“让语言的语法结构由多个类分别表示,每个类负责解释对应部分”的思想。

  • 无需 switch 判断节点类型,靠接口多态自动分发
  • 扩展新运算符(如 -/)只需新增 Expr 实现,不修改现有逻辑
  • 若需变量支持,可在 Eval() 方法中传入 map[string]int 环境参数

完整流程串起来

入口函数示例:

func Evaluate(input string) int {
  tokens := Lexer(input)
  parser := &Parser{Tokens: tokens, Pos: 0}
  expr := parser.ParseExpression()
  return expr.Eval()
}

注意 Parser 中维护当前 token 下标 Pos,每次 consume 后递增;遇到错误(如括号不匹配、意外 token)应 panic 或返回 error。

基本上就这些。Go 的接口和结构体组合让 Interpreter Pattern 写起来干净利落,没有冗余抽象,也不用反射或代码生成。重点是把 Token 流稳稳转成树,剩下的就是自然的递归计算。