1.概念html
抽象语法树(abstract syntax code,AST)是源代码的抽象语法结构的树状表示
。这里特指编程语言的源代码。前端
树上的每一个节点都表示源代码中的一种结构,之因此说是抽象的,是由于抽象语法树并不会表示出真实语法出现的每个细节
,好比说,嵌套括号被隐含在树的结构中,并无以节点的形式呈现。node
抽象语法树
并不依赖于源语言的语法,也就是说语法分析
阶段所采用的上下文无关文法,由于在写文法时,常常会对文法进行等价的转换(消除左递归,回溯,二义性等),这样会给文法分析引入一些多余的成分,对后续阶段形成不利影响,甚至会使各个阶段变得混乱。所以,不少编译器常常要独立地构造语法分析树,为前端,后端创建一个清晰的接口。git
抽象语法树在不少领域有普遍的应用,好比浏览器,智能编辑器,编译器等。github
2.为什么须要抽象语法树(抽象语法树做用)typescript
编程语言太多,须要一个统一的结构让计算机识别。npm
做用:好比typescript
的类型检查,IDE的语法高亮,代码检查,转译等等,都是须要先将代码转化成AST在进行后续的操做。编程
3.抽象语法树的生成过程(编译)segmentfault
js为例:后端
词法分析(lexical analysis)
:进行词法分析的程序或者函数叫做词法分析器(Lexical analyzer,简称Lexer),也叫扫描器(Scanner,例如typescript
源码中的scanner.ts
),字符流
转换成对应的Token流
。
tokenize:
tokenize就是按照必定的规则,例如token令牌(一般表明关键字,变量名,语法符号等),将代码分割为一个个的“串”,也就是语法单元)。涉及到词法解析的时候,常会用到tokennize。
语法分析(parse analysis)
:是编译过程的一个逻辑阶段。语法分析的任务是在词法分析的基础上将单词序列组合成语法树,如“程序”,“语句”,“表达式”等等.语法分析程序判断源程序在结构上是否正确。源程序的结构由上下文无关文法描述。
例如:对
const a = 1;
const b = a + 1;
复制代码
的编译过程。
图片地址:www.processon.com/view/link/5…
词法解析过程
:一边扫描源代码一边进行分类,例如扫描到第一行const a = 1
,首先扫描到const
,会生成一个语法单元说这是关键字const
,接着扫描到a
,这是变量名a
,接着操做符=
,接着常量1
,等等,构成一个个token流。
语法分析过程
:将token流转化为一个有元素层级嵌套所组成的表明程序语法结构的树,这个树被叫作抽象语法树AST。
4.扩展测试:如何将const a = 1
转化成var a = 1
1. 新建一个testAst
的工程
mkdir testAst复制代码
testAst
下新建test.js
文件
touch test.js复制代码
testAst
下安装esprima
的npm模块,获得ASTnpm i esprima --save复制代码
test.js
写入代码
const esprima = require('esprima'); let code = 'const a = 1'; const ast = esprima.parseScript(code); console.log(ast); 复制代码
2.运行test.js
node test.js复制代码
3.获得生成的AST
也可经过esprima.org/demo/parse.…,输入代码,在线查看AST
testAst
下安装estraverse
的npm模块,遍历更新ASTnpm i estraverse --save
复制代码
4.修改代码以下:
const esprima = require('esprima'); const estraverse = require('estraverse'); let code = 'const a = 1'; const ast = esprima.parseScript(code); estraverse.traverse(ast, { enter: function (node) { node.kind = "var"; } }); console.log(ast);复制代码
5.运行test.js
,获得更新事后的AST
testAst
下安装escodegen
的npm模块,获得转译后的代码npm i escodegen --save复制代码
6.修改代码以下:
const esprima = require('esprima'); const estraverse = require('estraverse'); const escodegen = require('escodegen'); let code = 'const a = 1'; const ast = esprima.parseScript(code); estraverse.traverse(ast, { enter: function (node) { node.kind = "var"; } }); const transformCode = escodegen.generate(ast); console.log(transformCode); 复制代码
7.运行test.js
,获得转译后的代码
参考文档:
https://segmentfault.com/a/1190000012943992