一、AST基础概念与入门必备
1.1 什么是AST(Abstract Syntax Tree)?
根据维基百科的介绍:在计算机科学中,抽象语法树(AST),或者仅仅是语法树,是用编程语言编写的源代码的抽象语法结构的树状表示。树的每个节点都表示源代码中出现的一个构造。
大多数编译器和解释器都使用AST作为源代码的内部表示,AST通常会省略语法树中的分号、换行字符、白空格、大括号、方括号和圆括号等。
1.2 生成AST的步骤?
下面我们来看看计算机是如何将一份代码文件转换成AST的。

词法分析器(Lexer)词法分析解析器ASTlexerparser
Lexer-又名词法分析器:词法分析器用来将字符序列转换为单词(Token)。词法分析主要是完成:
- 对源程序的代码进行从左到右的逐行扫描,识别出各个单词,从而确定单词的类型;
- 将识别出的单词转换为统一的机内表示——词法单元(Token)形式。
token是一种类型Map的key/value形式,它由<种别码,属性值>组成,种别码就是类型、属性值就是值。例如下述代码中:
转换为token之后:
=\n
Parser-语法分析器:语法分析器的作用是进行语法检查、并构建由输入的单词(Token)组成的数据结构(一般是语法分析树、抽象语法树等层次化的数据结构)。
语法分析的分析方法一般分为自顶向下和自底向上两种:
(这里的内容相对比较复杂,这里不做介绍)
通过上述的叙述中,我们知道通过“词法分析”和“语法分析”我们便可以得到AST,例如:
上述代码的AST为:
我们看到,即使非常简单的代码生成AST也非常复杂。那么我们得到了抽象语法树可以做什么呢?
1.3 AST的常见的几个用途
常见的几种用途:
- 代码语法的检查、代码风格的检查、代码的格式化、代码的高亮、代码错误提示、代码自动补全等等
- 如使用语言的Lint工具对代码错误或风格的检查,发现一些潜在的错误
- IDE的错误提示、格式化、高亮、自动补全等
- 代码混淆压缩
- UglifyJS2等
- 优化变更代码,改变代码结构使达到想要的结构
- 代码打包工具webpack、rollup等等
- CommonJS、AMD、CMD、UMD等代码规范之间的转化
- CoffeeScript、TypeScript、JSX等转化为原生Javascript
二、Golang中的AST
2.1 Golang中的AST
golang官方提供的几个包,可以帮助我们进行AST分析:
通过上述的四个库,我们就可以实现golang代码的语法树分析。
go/ast/ast.go表达式和类型节点(Expressions and type nodes)语句节点(statement nodes)声明节点(declaration nodes)
ast.Node
ast.Node
- ast.Expr - 代表表达式和类型的节点
- ast.Stmt - 代表报表节点
- ast.Decl - 代表声明节点

ast.Node
2.2 Golang的AST分析示例
我们将以下面这段代码为例子来介绍Golang的抽象语法树。
代码清单2-1:
- 代码清单2-2:
go run main.go
2.2 Golang的AST分析
一棵树
代码清单2-3:
go/astInspect
代码清单2-4:
执行上述代码我们可以得到AST的全部节点,由于原生的AST太长,这里省略,给出AST的大体结构图:

*ast.File
*ast.Fileast.Node
ast.File包名导入声明函数声明
*ast.Ident-包名
hello
*ast.GenDecl-导入声明

ast.GenDeclimportconstvartype
Tok
import
ast.GenDecl*ast.ImportSpec
*ast.FuncDecl-函数声明

ast.FuncDeclast.Nodeast.FuncDecl*ast.Ident*ast.Object
如此多的类型我们不可能全部记住,因为官方文件已经帮我们全部记住了,我们只需按需查询即可:
下面这张表总结了AST常见的节点表,和源码做对比可快速使用。

总结
本文首先介绍了ast的一些基础概念以及生成步骤,以golang为例介绍了AST的详细实践。利用AST我们可以做很多的事情,例如语法检查、单测框架生成(gotests框架就是基于ast做的)等等。
博主在工作中正在使用ast对开源的单元测试框架进行修改,以便提供编写单元测试的效率,有什么问题欢迎交流~