AST抽象语法树


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模块,获得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


也可经过esprima.org/demo/parse.…,输入代码,在线查看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. baike.baidu.com/item/词法分析
  4. blog.csdn.net/feng98ren/a…
  5. https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md#toc-asts
相关文章
相关标签/搜索