前言
我们都知道,无论使用什么编程语言,都需要它自己的解释器或编译器处理成计算机能够理解的代码或者语言。众多语言的编译都有共同的一个操作,就是将文本代码解析成抽象语法树的数据结构。
什么是抽象语法树?
抽象语法树(Abstract Syntax Tree ,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
以var a = 7 为例,语法树结构如下图:生成工具
接下来我们一层一层的来做分析:
- 首先我们看到,最外层是一个对象包含三个子对象:
type、body、sourceType。
type的value是program,program顾名思义就是"大纲,程序"的意思。
body是一个数组,sourceCode的结构或者代码块都在body这个对象里面。
sourceType, sourceCode的类型是script。
- 我们看函数体,即
body这个对象。body里面包含type、declarations、kind三个对象。
type的value是VariableDeclaration。VariableDeclaration即 变量声明,意思就是说接下来的代码块是一个变量声明的表达式。更多详情请移步AST语法树对象文档。
declarations,是一个数组,数组内的子集是对代码块的描述。
kind,是说变量声明的关键字是var。
- 我们看代码的描述
declarations。
因为只有一行代码,所以数组内只有一个对象。至此,我们终于到了
var a = 7语句。
先声明该语句的类型:
type: VariableDeclarator是说这条语句是一个 变量声明 语句。
这条变量声明语句包含:变量的
id以及 要赋予的value。id的类型type是标识符,用Identifier来表示。value是一个init类型的值,type是Literal是说逐字取值(简单理解按序取值),值得value是7,raw:7是带引号的value。
以上我们就完成了一个简单的语法树的分析过程。
如何生成AST
首先,JavaScript 是一门解释型脚本语言,通过词法分析->语法分析->语法树->字节码->机器码等一系列转化和编译操作,生成的机器码就可以执行了。
我们先说词法分析,词法分析是将字符串通过一定的规则生成一系列的token(即:词法单元),即把字符流转换成记号流,我们仍然拿var a = 7来分析,如下图:
总结分析过程:sourceCode-->token。常用的词法分析器有tokenizer、Lexer等,有兴趣的同学可以自己去研究具体的实现原理。
语法分析
词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树,即 AST,总结其过程为:token->parse->ast。
{
"type": "Program",
"body": [
{
"type": "VariableDeclaration",
"declarations": [
{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "a"
},
"init": {
"type": "Literal",
"value": 7,
"raw": "7"
}
}
],
"kind": "var"
}
],
"sourceType": "script"
}
可以通过AST Explore查看更多语言类型的树结构。
常用的JavaScript Parser有 esprima 和 acron等等。
语法树可以做什么
ast的用途其实请多的,下面简单列举几个
- IDE的错误提示、代码格式化、代码高亮、代码自动补全等
- JSLint、JSHint对代码错误或风格的检查等
- webpack、rollup进行代码打包等
- CoffeeScript、TypeScript、JSX等转化为原生Javascript
- vue模板编译、react模板编译
Nothing Is Impossible