AST (Abstract Syntax Tree)

题目内容
ASTAST定义,应用形式,原理
ASTAST例子
ASTAST利用

AST 定义

  • AST(Abstract Syntax Tree)形象语法树,简称AST,它是源代码(也就是说它不仅仅是利用于JavaScript,同时还利用于其余语言,例如: Python,Rust等)语法结构的一种形象示意。
  • 它以树状的模式体现编程语言的语法结构,树上的每个节点都示意源码中的一种构造
  • 语法【形象】: 指的是这里的语法并不会示意出实在语法中呈现的每个细节。

AST应用形式

  • 咱们常见的词法分析器以及语法解析器(它能够将JavaScript源码转换成AST),比方上面实例中的esprima,当然还有其余的,例如: acorn、shift、traceur等

用处

  • AST 形象语法树的用处是十分宽泛的,比方:
  • vscode、atom、sublime中的代码高亮代码格式化谬误提醒代码主动补全
  • eslintprettier对代码谬误或者格调的查看;
  • babel转译ES6ES5
    ...
  • 所以说如果你想优化JavaScript的编译和运行速度,AST的理解是必不可少的。

AST原理

编译流程

  • JavaScript执行的过程首先是读取JavaScript文件中的字符流,其次通过词法分析器生成token,之后再通过语法分析器(Parser)生成AST树,最初转换为机器码执行。
var name = "jackdan";
  • 第一步就先读取下面的字符流'var name = "jackdan"'
  • 第二步分词: 将'var name = "jackdan"'整个代码字符串宰割成最小的语法单元数组;如下:
[  { type: 'Keyword', value: 'var' },  { type: 'Identifier', value: 'name' },  { type: 'Punctuator', value: '=' },  { type: 'String', value: '"jackdan"' }]
  • 第三步语法分析: 在分词的根底上建设剖析语法单元之间的关系;如下:
- Program  type: "Program"  - body: [    - VariableDeclaration {      type: "VariableDeclaration"      - declarations: [        - VariableDeclarator {          type: "VariableDeclarator"          - id: Identifier {            type: "Identifier"            name: "name"          }          - init: Literal {            type: "Literal"            value: "jackdan"            raw: "jackdan"          }        }      ]      kind: "var"    }  ]
  • 咱们重点梳理一下原理中的词法剖析语法分析,接触过这两者的应该不会太过于生疏。

词法剖析

  • 词法剖析:同时也称为扫描(scanner),简略来说就是调用
    next()办法,一个一个字母的来读取字符,而后与定义好的JavaScript要害字符做比拟,生成对应的Token。Token是一个不可分割的最小单元。例如:
var name = "jackdan";// 先读取v,而后持续读取a,最初读取r组成一个var// var这三个字符就辨认为JavaScript中的关键字,作为一个整体,语义上就不能再被合成了,因而咱们也视为一个Token
  • 从下面的代码实例中不难得出,词法分析器里,每个关键字是一个Token,每个标识符是一个Token,每个操作符是一个Token,每个标点符号也都是一个Token。除此之外,还会过滤掉程序中的正文和空白字符(换行符、空格、制表符等)。
  • 最终,咱们看到整个代码都被宰割进了一个tokens列表(或者说一维数组)。
[  { type: 'Keyword', value: 'var' },  { type: 'Identifier', value: 'name' },  { type: 'Punctuator', value: '=' },  { type: 'String', value: '"jackdan"' }]

语法分析

  • 语法分析就是将词法剖析的tokns列表转化成有语法含意的形象语法树结构。同时去验证语法(高亮、主动补全等),语法如果有错的话,抛出语法错误。
- Program  type: "Program"  - body: [    - VariableDeclaration {      type: "VariableDeclaration"      - declarations: [        - VariableDeclarator {          type: "VariableDeclarator"          - id: Identifier {            type: "Identifier"            name: "name"          }          - init: Literal {            type: "Literal"            value: "jackdan"            raw: "jackdan"          }        }      ]      kind: "var"    }  ]

AST 实例

// 源代码var name = "jackdan";
// AST 形象语法树/** *  *      +-----------+ *      | assign(=) | *      +-----------+ *      /            \ *     /              \ * +----+        +---------+ * |name|        |"jackdan"| * +----+        +---------+ * */
// 运行输入的构造代码- Program  type: "Program"  - body: [    - VariableDeclaration {      type: "VariableDeclaration"      - declarations: [        - VariableDeclarator {          type: "VariableDeclarator"          - id: Identifier {            type: "Identifier"            name: "name"          }          - init: Literal {            type: "Literal"            value: "jackdan"            raw: "jackdan"          }        }      ]      kind: "var"    }  ]
> var esprima = require('esprima');> var program = 'var name = "jackdan"';> esprima.tokenize(program);[  { type: 'Keyword', value: 'var' },  { type: 'Identifier', value: 'name' },  { type: 'Punctuator', value: '=' },  { type: 'String', value: '"jackdan"' }]> esprima.parse(program);Script {  type: 'Program',  body: [    VariableDeclaration {      type: 'VariableDeclaration',      declarations: [Array],      kind: 'var'    }  ],  sourceType: 'script'}
Thinking in JackDan