AST抽象语法树

1.概念

抽象语法树(abstract syntax code,AST)是源代码的抽象语法结构的树状表示。这里特指编程语言的源代码。

树上的每个节点都表示源代码中的一种结构,之所以说是抽象的,是因为抽象语法树并不会表示出真实语法出现的每一个细节,比如说,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现。

抽象语法树并不依赖于源语言的语法,也就是说语法分析阶段所采用的上下文无文文法,因为在写文法时,经常会对文法进行等价的转换(消除左递归,回溯,二义性等),这样会给文法分析引入一些多余的成分,对后续阶段造成不利影响,甚至会使合个阶段变得混乱。因些,很多编译器经常要独立地构造语法分析树,为前端,后端建立一个清晰的接口。

 

抽象语法树在很多领域有广泛的应用,比如浏览器,智能编辑器,编译器等。

 

2.为何需要抽象语法树(抽象语法树作用)

编程语言太多,需要一个统一的结构让计算机识别。

作用:比如typescript的类型检查,IDE的语法高亮,代码检查,转译等等,都是需要先将代码转化成AST在进行后续的操作。

 

3.抽象语法树的生成过程(编译)

js为例:

词法分析(lexical analysis):进行词法分析的程序或者函数叫作词法分析器(Lexical analyzer,简称Lexer),也叫扫描器(Scanner,例如typescript源码中的scanner.ts),字符流转换成对应的Token流

tokenize:tokenize就是按照一定的规则,例如token令牌(通常代表关键字,变量名,语法符号等),将代码分割为一个个的“串”,也就是语法单元)。涉及到词法解析的时候,常会用到tokennize。

 

语法分析(parse analysis)是编译过程的一个逻辑阶段。语法分析的任务是在词法分析的基础上将单词序列组合成语法树,如“程序”,“语句”,“表达式”等等.语法分析程序判断源程序在结构上是否正确。源程序的结构由上下文无关文法描述。

例如:对

const a = 1;
const b = a + 1;

的编译过程。

图片地址:https://www.processon.com/view/link/5bf53fb0e4b0342397f9c0a4

词法解析过程:一边扫描源代码一边进行分类,例如扫描到第一行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模块,得到AST
  npm 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

也可通过http://esprima.org/demo/parse.html,输入代码,在线查看AST

  • testAst下安装estraverse的npm模块,遍历更新AST
npm 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,得到转译后的代码

 

参考文档:

  1. https://segmentfault.com/a/1190000012943992
  2. https://baike.baidu.com/item/语法分析/8853407?fr=aladdin
  3. https://baike.baidu.com/item/词法分析
  4. https://blog.csdn.net/feng98ren/article/details/80856530
  5. https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md#toc-asts

 

 

 

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值