# AST解析

1、在线网站ast生成网站 (opens new window)

2、ast标准:开源项目estree (opens new window)

3、词法分析工具scanner (opens new window)

# 1、简介

抽象语法树(Abstract Syntax Tree,AST),是源代码语法结构的一种抽象表示,它以树状的形式表示编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。AST运用广泛,比如:

  • 高级语言的编译、机器码的生成
  • 一些高级编辑器的错误提示、代码高亮、代码自动补全;
  • 前端工具,例如eslint、pretiier,对代码错误或风格的检查,babel、typescript对代码的编译处理等。

# 2、AST转换流程

# 1、ast生成流程

  • 词法分析:也叫扫描(scanner),将整个代码字符串转换为令牌(tokens)流,令牌(tokens)看作是一个扁平的语法片段数组
  • 语法分析:把一个令牌流转换为AST,使用令牌中的信息把它们转换成一个 AST 的表述结构,这样更易于后续的操作
//代码:const ast = "this is tree";
//tokens:扁平化数组
[
    {
        "type": "Keyword",
        "value": "const"
    },
    {
        "type": "Identifier",
        "value": "ast"
    },
    {
        "type": "Punctuator",
        "value": "="
    },
    {
        "type": "String",
        "value": "\"this is tree\""
    },
    {
        "type": "Punctuator",
        "value": ";"
    }
]

//ast:acorn解析器
//type为节点类型,每一种类型的节点定义了一些附加属性来进一步描述该节点类型,eg:start、end
{
  "type": "Program",
  "start": 0,
  "end": 27,
  "body": [
    {
      "type": "VariableDeclaration",
      "start": 0,
      "end": 27,
      "declarations": [
        {
          "type": "VariableDeclarator",
          "start": 6,
          "end": 26,
          "id": {
            "type": "Identifier",
            "start": 6,
            "end": 9,
            "name": "ast"
          },
          "init": {
            "type": "Literal",
            "start": 12,
            "end": 26,
            "value": "this is tree",
            "raw": "\"this is tree\""
          }
        }
      ],
      "kind": "const"
    }
  ],
  "sourceType": "module"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

# 2、ast的主要type类型

Ast常用的类型如下:

  • Program:程序主体,整段代码的主体
  • VariableDeclaration:变量声明,例如var、let、const
  • FunctionDeclaration:函数声明,例如function
  • Identifier:标识符,例如申明变量时var i = 5 中的i
  • Literal:字面量,通常指字符串型的字面量
  • BinaryExpression:二进制表达式,例如1+1
  • BlockStatement:块语句,包裹在{}块内的代码
  • ReturnStatement:返回语句,通常指return
  • CallExpression:调用表达式,通常指调用一个函数
  • MemberExpression:成员表达式,通常指调用对象的成员,例如console对象到的log成员

# 3、ast使用流程

代码转换的三个步骤:parse、traverse、generator,ast的生成、遍历和代码转换

  • 使用scanner解析器对源代码进行解析,生成令牌流tokens
  • 使用parser将tokens生成ast树
  • traverse对ast树进行深度优先遍历,进行增删改查,生成新的ast树
  • 使用generator对新的ast树转换为代码

# 3、解析器

解析器将js转换为ast,目前的js解析器都遵循ESTree规范,常见的js解析器:

  • esprima:解析器始祖,第一个用JavaScript编写的符合EsTree规范的JavaScript的解析器
  • acorn:webpack解析器
  • espree:eslint解析器
  • babel-parser:babel解析器,基于babylon实现
  • uglify-js:单独的解析器
const acorn = require("acorn")             //js解析器
const estraverse = require("estraverse")   //ast遍历器
const escodegen = require("escodegen")     //代码生成器generator

const str = "const ast = 'this is tree';"
const tokens = [...acorn.tokenizer(str)]
const ast = acorn.parse(str)

console.log(JSON.stringify(tokens))
console.log(JSON.stringify(ast))

estraverse.traverse(ast,{
    enter(node){
        console.log('悄悄的我来了'+node.type)
        if(node.type === 'Literal')
        node.value = "this is newTree"
    },
    leave(node){
        console.log('悄悄的我又走了'+node.type)
    }
})

const result = escodegen.generate(ast)
console.log(result) //const ast = 'this is newTree';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Last Updated: 9/27/2021, 8:41:48 AM