AST解析
1、在线网站ast生成网站(opens new window)
2、ast标准:开源项目estree(opens new window)
3、词法分析工具scanner
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:扁平化数组
const 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:strat、end
const acorn = {
"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"
}
2、ast的主要type类型
Ast常用的类型如下:
- Program:程序主题,整段代码的主体
- VariableDeclaration:变量声明,例如var、let、const
- FunctionDeclaration:函数声明,例如function
- Identifier:标识符,例如申明变量时 var i = 5 中的 i
- Literal:字面量,通常指字符串型的字面量
- BinaryExpression:二进制表达式,例如1+1
- BockStatement:块语句,包裹在{}块内的代码
- ReturnStatement:返回语句,通常指return
- CallExpression:调用表达式,通常指调用一个函数
- MemberExpression:成员表达式,通常指调用对象的成员,例如console对象到的log成员
3、ast使用流程
代码转换的三个步骤:parse、traverse、genertor,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';

浙公网安备 33010602011771号