go ast语义分析实现指标计算器
什么是AST
首先我们要知道AST是什么(Abstract Syntax Tree,AST),简称为语法树,是go语言源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
上demo代码
func main() {expr, _ := parser.ParseExpr("1 + 2 * (3 + 4) + 3 * 4.1")ast.Print(token.NewFileSet(), expr)
}
// 输出结果
0 *ast.BinaryExpr {
1 . X: *ast.BinaryExpr {
2 . . X: *ast.BasicLit {
3 . . . ValuePos: -
4 . . . Kind: INT
5 . . . Value: "1"
6 . . }
7 . . OpPos: -
8 . . Op: +
9 . . Y: *ast.BinaryExpr {
10 . . . X: *ast.BasicLit {
11 . . . . ValuePos: -
12 . . . . Kind: INT
13 . . . . Value: "2"
14 . . . }
15 . . . OpPos: -
16 . . . Op: *
17 . . . Y: *ast.ParenExpr {
18 . . . . Lparen: -
19 . . . . X: *ast.BinaryExpr {
20 . . . . . X: *ast.BasicLit {
21 . . . . . . ValuePos: -
22 . . . . . . Kind: INT
23 . . . . . . Value: "3"
24 . . . . . }
25 . . . . . OpPos: -
26 . . . . . Op: +
27 . . . . . Y: *ast.BasicLit {
28 . . . . . . ValuePos: -
29 . . . . . . Kind: INT
30 . . . . . . Value: "4"
31 . . . . . }
32 . . . . }
33 . . . . Rparen: -
34 . . . }
35 . . }
36 . }
37 . OpPos: -
38 . Op: +
39 . Y: *ast.BinaryExpr {
40 . . X: *ast.BasicLit {
41 . . . ValuePos: -
42 . . . Kind: INT
43 . . . Value: "3"
44 . . }
45 . . OpPos: -
46 . . Op: *
47 . . Y: *ast.BasicLit {
48 . . . ValuePos: -
49 . . . Kind: FLOAT
50 . . . Value: "4.1"
51 . . }
52 . }
53 }
我们通过上面的代码输出了一砣子非常复杂的结构体,那么我们来看看这些都是些上面东西。
我们来看看源码
// A BinaryExpr node represents a binary expression.type BinaryExpr struct {X Expr // left operandOpPos token.Pos // position of OpOp token.Token // operatorY Expr // right operand}
我们通过这个结构体就可以看出来X和Y分别是两个值,Op是存储的我们的操作符号,OpPos 代表操作符在表达式中的偏移,这里的 Op 类型是token.Token,实际上是个枚举值。
// The list of tokens.
const (// Special tokensILLEGAL Token = iotaEOFCOMMENTliteral_beg// Identifiers and basic type literals// (these tokens stand for classes of literals)IDENT // mainINT // 12345FLOAT // 123.45IMAG // 123.45iCHAR // 'a'STRING // "abc"literal_endoperator_beg// Operators and delimitersADD // +SUB // -MUL // *QUO // /REM // %AND // &OR // |XOR // ^SHL // <<SHR // >>AND_NOT // &^ADD_ASSIGN // +=SUB_ASSIGN // -=MUL_ASSIGN // *=QUO_ASSIGN // /=REM_ASSIGN // %=AND_ASSIGN // &=OR_ASSIGN // |=XOR_ASSIGN // ^=SHL_ASSIGN // <<=SHR_ASSIGN // >>=AND_NOT_ASSIGN // &^=LAND // &&LOR // ||ARROW // <-INC // ++DEC // --EQL // ==LSS // <GTR // >ASSIGN // =NOT // !NEQ // !=LEQ // <=GEQ // >=DEFINE // :=ELLIPSIS // ...LPAREN // (LBRACK // [LBRACE // {COMMA // ,PERIOD // .RPAREN // )RBRACK // ]RBRACE // }SEMICOLON // ;COLON // :operator_endkeyword_beg// KeywordsBREAKCASECHANCONSTCONTINUEDEFAULTDEFERELSEFALLTHROUGHFORFUNCGOGOTOIFIMPORTINTERFACEMAPPACKAGERANGERETURNSELECTSTRUCTSWITCHTYPEVARkeyword_endadditional_beg// additional tokens, handled in an ad-hoc mannerTILDEadditional_end
)
那么token 连存储的就是这些, 他会根据我们输入的表达式,给去OpPos解析匹配这些符号。

我们可以从上图可以看出ast 代码树,因为表达式中有() ,我们发现了一个新的结构体ParenExpr ,我们查看源码,发现这个结构体是专门用于计算时如果有()时使用的。我们通过该树就可以看出来计算的先后顺序,就完美的完成了一个计算器功能。
// A ParenExpr node represents a parenthesized expression.type ParenExpr struct {Lparen token.Pos // position of "("X Expr // parenthesized expressionRparen token.Pos // position of ")"}
我们了解了ast代码树以后,我们就可以借助该解析代码树做很多东西,例如我们可以做一个计算器。
type AstParser struct {ExpStr string
}func NewAstParser(expStr string) *AstParser {return &AstParser{ExpStr: expStr}
}func (a *AstParser) Parse() (float64, error) {expr, err := parser.ParseExpr(a.ExpStr)if err != nil {return 0, err}val, err := a.Eval(expr)if err != nil {return 0, err}return val, nil
}func (a *AstParser) Eval(expr ast.Expr) (float64, error) {switch e := expr.(type) {case *ast.BinaryExpr:return a.EvalBinaryExpr(e)case *ast.ParenExpr:return a.Eval(e.X)case *ast.BasicLit:switch e.Kind {case token.INT, token.FLOAT:i, err := strconv.ParseFloat(e.Value, 64)if err != nil {return 0, err}return i, nil}}return 0, nil
}func (a *AstParser) EvalBinaryExpr(e *ast.BinaryExpr) (float64, error) {left, err := a.Eval(e.X)if err != nil {return 0, err}right, err := a.Eval(e.Y)if err != nil {return 0, err}switch e.Op {case token.ADD:return left + right, nilcase token.SUB:return left - right, nilcase token.MUL:return left * right, nilcase token.QUO:return left / right, nil}return 0.0, nil
}
总结:
我们了解了ast代码树后,利用它可以做成一个非常简单的规则引擎。
其实利用 ast 包还可以做更多有意思的事情。例如将文件转成proto,或者解析sql语句并做一些审计等等
相关文章:
go ast语义分析实现指标计算器
什么是AST 首先我们要知道AST是什么(Abstract Syntax Tree,AST),简称为语法树,是go语言源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。 …...
【Vue】组件间传参与方法调用
【前言】 … 【目标】 1 了解组件间传参 2 组件间自定义事件绑定与解绑 3 组件的事件总线 4 消息订阅与发布 一 组件间传参 1 props 引入并使用组件:传递参数 <template><div id="app"><HelloWorld :msg="msg" :name="name" …...
类和对象2
三、C对象模型和this指针 3.1 成员变量和成员函数分开存储 在C中,类内的成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上 #define _CRT_SECURE_NO_WARNINGS 1 #include <iostream> #include <string.h> using namespace …...
Linux系统命令traceroute详解(语法、选项、原理和实例)
目录 一、traceroute概述 二、语法 1、基本语法 2、命令选项 三、帮助信息 四、示例 1. 使用默认模式(ICMP Echo)追踪到目标主机 2. 使用UDP模式(需要root权限)追踪到目标主机 3. 不解析IP地址为主机名,直接显…...
中兴通讯助力中国移动,推动SPN AI节能技术于23省规模部署
SPN作为中国移动自主创新的新一代综合承载网络,相比PTN设备,SPN的单机容量及性能有大幅提升,整机功耗也相应变大。在当前国家双碳政策的目标下,SPN设备的节能降耗也日益成为中国移动关注的焦点。因此,中国移动选择与中…...
SQL Server--死锁
今天,客户反应打不开xxx页面了。好家伙肯定锁表了。。。。。 只能先吧死锁进程先kill掉,不能耽误客户生产环境运行。。。。。 一定要看看是那张表发生了死锁 1、查询死锁语句 select dbid,* from sys.sysprocesses where 11 and spid >50 and blo…...
中科蓝讯AB32VG1中文寄存器说明GPIO端口操作
1 GPIO管理 1.1 GPIO通用控制寄存器 寄存器 1- 1 GPIOA:端口 A 数据寄存器 位寄存器名模式缺省描述31:8---未使用7:0GPIOA写0x00PAx 数据。当 PAx 用作 GPIO 时有效 0:读取时PAx为输入低电平状态,写入时PAx为输出低电平; 1:PAx…...
如何查看热门GPT应用?
1、登陆chatgpt 2、访问 https://chatgpt.com/gpts 3、在该界面,可以搜索并使用image generator, Write For Me,Language Teature等热门应用。...
C++中的各种定义
文章目录 前言一、1、unsigned2、_countof、sizeof 总结 前言 一、 1、unsigned 在C语言中,"unsigned"是一个数据类型修饰符,用于修饰整数类型,表示该类型的变量只能存储非负整数,即无符号整数。它可以应用于char、s…...
Java面向对象-常用类(日期时间类)
常用类-日期时间类 Date(java.util.Date) – 日期类 SimpleDateFormat – 格式化日期类 Calendar – 日历类 1 Date类 java.util.Date类表示特定的瞬间,精确到毫秒。 package com.qf.datetime;import java.util.Date;public class Test01 {…...
Shell环境变量深入:自定义系统环境变量
Shell环境变量深入:自定义系统环境变量 目标 能够自定义系统级环境变量 全局配置文件/etc/profile应用场景 当前用户进入Shell环境初始化的时候会加载全局配置文件/etc/profile里面的环境变量, 供给所有Shell程序使用 以后只要是所有Shell程序或命令使用的变量…...
【C++课程学习】:命名空间的理解(图文详解)
🎁个人主页:我们的五年 🔍系列专栏:C课程学习 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 📷1.命名冲突 📷2.重定义 📷3.命名空间 🍺命名空间可…...
鸿蒙ArkUI-X平台差异化:【运行态差异化(@ohos.deviceInfo)】
平台差异化 简介 跨平台使用场景是一套ArkTS代码运行在多个终端设备上,如Android、iOS、OpenHarmony(含基于OpenHarmony发行的商业版,如HarmonyOS Next)。当不同平台业务逻辑不同,或使用了不支持跨平台的API…...
蓝牙Mesh模块组网时无线回程影响速率吗?
随着科技的发展,智能家居、智能办公等场景越来越广泛地应用于我们的生活。其中,蓝牙Mesh组网技术作为一种新型的无线通信技术,受到了越来越多用户的关注。那么,蓝牙Mesh模块在组网时无线回程过程中是否会影响速率呢?本…...
将3D检测的box框投影到BEV图片上
前言 点云数据作为一种丰富的三维空间信息表达方式,通常用于自动驾驶、机器人导航和三维建模等领域。然而,点云数据的直观性不如二维图像,这限制了它在一些需要快速视觉反馈的应用场景中的使用。本文将探讨如何将点云数据转换为二维图像&…...
Flutter 中的 ClipOval 小部件:全面指南
Flutter 中的 ClipOval 小部件:全面指南 在Flutter的丰富布局库中,ClipOval是一个用于裁剪子组件的显示区域为椭圆形或圆形的小部件。这种裁剪效果可以用于创建头像、图标或其他图形元素的美观边框。本文将提供ClipOval的全面指南,帮助你了解…...
ubuntu 硬盘转移
我插了两个 文件系统: ubuntu 硬盘转移: sudo dd if/dev/sdX1 of/dev/sdY1 bs128K convnoerror,sync statusprogressdd 的意思是DiskToDisk,if 是输入文件系统,of是输出文件系统。 bs是每次传递的数据大小。 注意:接…...
three.js中使用CameraHelper来可视化调整阴影相机的范围
1. three.js中使用CameraHelper来可视化调整阴影相机的范围 光源 const directionLight new THREE.DirectionalLight(0xffffff, 1); directionLight.position.set(100, 60, 20); directionLight.castShadow true; scene.add(directionLight);设置计算阴影的范围 direction…...
Golang发送GET请求并设置查询参数
服务端 package mainimport ("encoding/json""net/http""zdpgo_chi""zdpgo_chi/middleware" )func main() {r : zdpgo_chi.NewRouter()r.Use(middleware.RequestID)r.Use(middleware.RealIP)r.Use(middleware.Logger)r.Use(middlewar…...
c++笔记3
优先队列 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。优先队列是一种按照优先级决定出队顺序的数据结构,优先队列中的每个元素被赋予级别,队首元素的优先级最高。 例如:4入队,…...
千问3.5-9B领域适配:OpenClaw法律文书处理特化
千问3.5-9B领域适配:OpenClaw法律文书处理特化 1. 为什么需要法律领域的特化模型 去年处理一起商业合同时,我花了整整三天时间逐条核对法条引用是否准确。这种重复性工作让我开始思考:能否用AI辅助完成法律文书的专项处理?通用大…...
Wan2.2-I2V-A14B镜像免配置:内置模型权重42GB,节省下载与校验时间
Wan2.2-I2V-A14B镜像免配置:内置模型权重42GB,节省下载与校验时间 1. 镜像概述与核心优势 Wan2.2-I2V-A14B是一款专为文生视频任务优化的私有部署镜像,针对RTX 4090D 24GB显存显卡进行了深度优化。这个镜像最大的特点是内置了完整的42GB模型…...
高效备战2026年上海初中古诗文大会【多选题】:背熟这份高频考点
今天距离2026年上海初中古诗文大会启动还有2个多月(通常6月底7月初启动,发布比赛方案和流程),正式比赛还有5个多月(通常10月初开始,分为初选、复选、决选三轮)。现在就读五年级到八年级的上海的…...
C# 13主构造函数+Records+With表达式三重组合技(.NET 8.0正式版实测):DTO层代码减少83%,但需绕过这个编译器Bug
第一章:C# 13主构造函数案例C# 13 引入了主构造函数(Primary Constructor)语法,允许在类或结构体声明时直接定义构造参数,并自动将参数提升为类型成员(如只读字段或属性),显著简化了…...
2026年4月OpenClaw(Clawdbot)如何集成?华为云新手攻略:搭建及大模型API、Skill配置指南
2026年4月OpenClaw(Clawdbot)如何集成?华为云新手攻略:搭建及大模型API、Skill配置指南。OpenClaw(Clawdbot)是2026年主流的AI自动化助理平台,能借助阿里云轻量服务器达成724小时稳定运转&#…...
GME-Qwen2-VL-2B-Instruct实操手册:图文匹配工具性能压测与QPS基准报告
GME-Qwen2-VL-2B-Instruct实操手册:图文匹配工具性能压测与QPS基准报告 1. 引言:为什么你需要一个本地图文匹配工具? 想象一下这个场景:你手头有几千张商品图片,需要为每张图片自动生成最贴切的标题,或者…...
【2025最新】基于SpringBoot+Vue的游戏销售平台管理系统源码+MyBatis+MySQL
摘要 随着互联网技术的飞速发展,数字化娱乐产业迎来了前所未有的增长机遇。游戏作为数字娱乐的核心组成部分,其市场规模逐年扩大,用户需求日益多样化。传统的游戏销售模式已无法满足现代消费者的便捷性和个性化需求,亟需一个高效…...
中国婴幼儿肌肤特点分析报告
中国婴幼儿肌肤受基因、气候、生活习惯等多重因素影响,呈现出屏障先天薄弱、结构发育缓慢、耐受力偏低等独特生理特征,再加上国内气候多样、高频清洁习惯、西方育儿理念本土化不足等后天因素,使得中国宝宝更易出现干燥、敏感、热疹、湿疹等问…...
Linux异步IO驱动开发实战与优化
1. Linux异步IO驱动开发实战作为一名在Linux驱动开发领域摸爬滚打多年的工程师,我经常遇到需要处理高并发IO的场景。传统的阻塞式IO会导致线程挂起,而非阻塞轮询又浪费CPU资源。今天要分享的异步IO(AIO)技术,可以说是解…...
CANoe_UDS-bootloader 自动化测试系列(一)搭建CANoe测试框架:XML与CAPL模块的工程化抉择
1. 为什么测试框架的选择如此重要? 第一次接触UDS Bootloader自动化测试时,我完全被各种技术选项搞晕了。特别是当团队讨论该用XML Test Module还是CAPL Test Module时,大家争论得面红耳赤。后来我才明白,这个选择直接影响着整个测…...
