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入队,…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...
内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献
Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译: ### 胃肠道癌症的发病率呈上升趋势,且有年轻化倾向(Bray等人,2018&#x…...
