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语句并做一些审计等等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/17605.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我的心情JSP+Servlet+JDBC+MySQL

系统概述 本系统采用JSPServletJDBCMySQL技术进行开发&#xff0c;包括查看我的心情列表&#xff0c; 编辑我的心情信息、新增我的心情。使用方法 将项目从idea中导入&#xff0c;然后配置项目的结构&#xff0c;包括jdk,库&#xff0c;模块&#xff0c;项目&#xff0c;工件…

QT 自定义协议TCP传输文件

后面附带实例的下载地址 一、将文件看做是由:文件头+文件内容组成,其中文件头包含文件的一些信息:文件名称、文件大小等。 二、文件头单独发送,文件内容切块发送。 三、每次发送信息格式:发送内容大小、发送内容类型(文件头或是文件块内容)、文件块内容。 四、效果展…

基于springboot实现政府管理系统项目【项目源码+论文说明】

基于springboot实现政府管理系统演示 摘要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff…

饲料粉碎混合机组:打造精细化养殖

饲料粉碎混合机组是畜牧业和养殖业中不可或缺的设备。它集饲料粉碎和混合于一体&#xff0c;可以高效地处理各种饲料原料&#xff0c;提高饲料的均匀度和营养价值。 具体来说&#xff0c;饲料粉碎混合机组的主要功能包括将饲料原料进行粉碎&#xff0c;增加其表面积和调质粒度…

Steam游戏搬砖:靠谱吗,详细版说下搬砖中的核心内容!

可能大家也比较关注国外Steam游戏搬砖这个项目&#xff0c;最近单独找我了解的也比较多&#xff0c;其实也正常&#xff0c;因为现在市面上的项目很多都很鸡肋&#xff0c;而且很多都是一片红海&#xff0c;内卷太过严重&#xff0c;所以对于Steam的关注度也高很多&#xff0c;…

CTF-web-WP-攻防世界-1

1、view_source&#xff1a;打开开发者工具F12就能看到flag 2、robots (1)、使用目录扫描工具 工具&#xff1a;dirsearch命令&#xff1a;python dirsearch.py -u http://61.147.171.105:55644/ -e * (2)、看到下面有robots.txt文件&#xff0c;在URL后面输入&#xff0c…

INDICATOR 再c嵌入sql环境中的作用

在C语言嵌入SQL&#xff08;Embedded SQL&#xff09;的环境中&#xff0c;INDICATOR关键字用于处理数据库中的NULL值&#xff0c;以及管理与之相关联的宿主变量&#xff08;host variables&#xff09;。具体来说&#xff0c;它的作用主要体现在以下几个方面&#xff1a; NUL…

LeetCode题练习与总结:有序链表转换二叉搜索树--109

一、题目描述 给定一个单链表的头节点 head &#xff0c;其中的元素 按升序排序 &#xff0c;将其转换为平衡二叉搜索树。 示例 1: 输入: head [-10,-3,0,5,9] 输出: [0,-3,9,-10,null,5] 解释: 一个可能的答案是[0&#xff0c;-3,9&#xff0c;-10,null,5]&#xff0c;它表…

Docker安装Redis的详细教程

以下是一个使用Docker安装Redis的详细教程 1. 拉取Redis镜像 运行以下命令来从Docker Hub上拉取最新的Redis镜像&#xff1a; docker pull redis:latest如果您需要特定版本的Redis&#xff0c;可以指定版本号&#xff1a; docker pull redis:6.2.72. 运行Redis容器 以下命…

分享个自用的 Nginx 加强 WordPress 防护的规则

Nginx WordPress 的组合是目前非常普及的组合了&#xff0c;我们完全可以借助 Nginx 规则来加强 WordPress 的防护&#xff0c;提高 WordPress 的安全性&#xff0c;今天明月就给大家分享个自用的 Nginx 针对 WordPress 的防护规则&#xff0c;部分规则大家只需要根据自己的需要…

基于vuestic-ui实战教程 - 页面篇

1. 简介 前面介绍了基本的内容比如如何获取动态数据&#xff0c;下面就到登录进来后的页面实现了&#xff0c;相信各位读者或多或少都有 element-uijs 的实战经历&#xff0c;那么 vuestic-uits 实现的页面又该如何写呢&#xff1f;带着疑问开启今天的学习&#xff08;声明由于…

Linux系统编程学习笔记

1 前言 1.1 环境 平台&#xff1a;uabntu20.04 工具&#xff1a;vim,gcc,make 1.2 GCC Linux系统下的GCC&#xff08;GNU Compiler Collection&#xff09;是GNU推出的功能强大、性能优越的多平台编译器&#xff0c;是GNU的代表作品之一。gcc是可以在多种硬体平台上编译出可执…

BIGO前端CICD平台

本文首发于&#xff1a;https://github.com/bigo-frontend/blog/ 欢迎关注、转载。 我是谁 BIGO前端CICD平台&#xff0c;是一个服务于前端团队的全研发周期管理平台&#xff0c;已经是我们团队日常都要使用的工具了。 该平台实现了一键创建项目、发布编排、新建迭代、checkl…

uniapp 使用vuex 在app上能获取到state,小程序获取不到

1. 在根目录下新建store目录, 在store目录下创建index.js定义状态值import Vue from vue; import Vuex from Vuex; import Vuex from vuex; Vue.use(Vuex);const store new Vuex.Store({ state: { login: false, token: , avatarUrl: , userName: }, mutations: { lo…

JavaWeb Servelt原理

Servlet简介: Servlet的主要工作&#xff1a;处理客户端请求&#xff0c;生成动态响应&#xff0c;通常用于扩展基于HTTP协议的Web服务器。 Servlet技术是Java EE规范的组成部分&#xff0c;代表了服务器端的Java程序&#xff0c;主要负责处理来自客户端的Web请求&#xff0c;…

国内信创web中间件生态

国内信创web中间件生态 东方通 官网https://www.tongtech.com/pctype/25.html 宝蓝德 官网https://www.bessystem.com/product/0ad9b8c4d6af462b8d15723a5f25a87d/info?p101 金蝶天燕 官网 https://www.apusic.com/list-117.html 中创 官网http://www.inforbus.com…

数据库数据恢复—空间不足导致sqlserver数据库连接失效的数据恢复案例

数据库数据恢复环境&#xff1a; 某品牌r520服务器&#xff0c;服务器中有7块SAS硬盘&#xff0c;这7块硬盘组建了一组2盘raid1阵列和一组5盘raid5阵列&#xff0c;raid1阵列存储空间安装操作系统&#xff0c;raid5阵列存储空间存放数据。服务器上部署sql server数据库&#xf…

野外作战武器操作3D模拟实操仿真训练以便老兵能适应不同的训练需求

强国必须强军&#xff0c;我国在军事方面的投入持续加大&#xff0c;自然在军事武器培训方面不容忽视&#xff0c;在军事领域&#xff0c;3D模拟展示不仅提升了军事训练的效率&#xff0c;还为我们提供了更加直观、真实的武器体验。 首先&#xff0c;3D军事武器模拟展示能够提供…

Nacos 2.x 系列【6】持久化

文章目录 1. 前言2. Derby3. Mysql3.1 初始化脚本3.2 服务端配置3.3 验证 4. 数据源插件 1. 前言 Nacos中的用户、租户、服务配置等信息&#xff0c;需要使用关系型数据库进行存储&#xff0c;在实际开发中&#xff0c;可能还会面临各种数据库适配问题。 2. Derby Derby是Ap…

Android Studio 中gradle的bin和all区别

1.在android studio中设置安装gradle时&#xff0c;真各种版本看到眼花缭乱&#xff0c;还有疑惑gradle-*.*-all.zip与gradle-*.*-bin.zip的区别是什么。下面解压如下: bin&#xff1a; all: 其实&#xff0c;用bin就可以了&#xff0c;all文件就是多了docs(文档)和src(源码)两…