JavaScript AST抽象语法树常见节点及结构

前言

最近开始接触AST,用于解决JS代码混淆的问题。

在看@渔哥的文章,虽然目前还是有点云里雾里的。

本文总结了JS抽象语法树中常见节点及结构。

推荐使用下方网站,结合例子对照观察。

工具网站:https://astexplorer.net/


Program(程序)

结构:

{
    "type": "Program",
    "body": [], // 多个节点
    "sourceType": "module",
    "range": [] //代码起始位置
}

Identifier(标识符)

可以简单的理解为变量名,函数名,属性名

{
    "type": "Identifier",
    "name": "", //
    "range": [] // 代码起始位置
}

例子:

a
_$0x

Literal(字面量)

可以理解为一个具体的值

结构:

{
    "type": "Literal",
    "value": 1// 真实值
    "raw": "1", // 字符串形式的值
    "range": []
}

例子:

1
'2'
0x10

VariableDeclarator(变量声明符)

属于declarations中的一个元素

var a = 1, b = 2;

其中 a = 1 b = 2属于两个变量声明符

结构:

{
    "type": "VariableDeclarator",
    "id": Identifier, // 变量名
   	"init": null, // 初始化,如果声明并赋值,此处就有值,只声明未赋值则为null
    "range": []
}

例子:

var a, b = 2;

Property(属性)

属于properties的元素

键值对

由于 ES5 语法中有 get/set 的存在,所以有一个 kind 属性,用来表示是普通的初始化,或者是 get/set

结构:

{
    "type": "Property",
    "key": "", // 键
    "computed": "",
    "value": "", // 值
    "kind": "init",
    "method": false,
    "shorthand": false,
    "range": []
}

Declaration(声明)

VariableDeclaration-变量声明

声明变量

结构:

{
    'type': "VariableDeclaration",
	'declarations':  [VariableDeclarator, VariableDeclarator...], // `具体的声明, 这是一个列表,因为可以一次性声明多个变量`
	'kind': "变量修饰符,例如,var、let、const",
	'range': []// 声明代码的起始位置
}

例子:

var a;
var c, b;

FunctionDeclaration-函数声明

函数的声明

结构:

{
    'type': 'FunctionDeclaration',
    'id': '', // 可以简单的理解为函数名
    'params': [], // 参数
    'body': BlockSatement // 函数的主体内容,多为块语句
    'generator': false,
    'expression': false,
    'async': false,
    'range': []
}

例子:

function func(a, b) {}

Statement(语句)

BlockStatement-块语句

代码块,简单点理解就是{}包起来的代码

结构:

{
    "type": "BlockStatement",
    "body": [], // 代码主体
    "range": []
}

例子:

function a () {}
{}

ExpressionStatement-表达式语句

结构:

{
    "type": "ExpressionStatement",
    "expression": // 表达式, 例如赋值表达式
    "range": []
}

IFStatement-如果语句

if 语句

if (a === 1) {}

结构:

{
    'type': 'IFStatement',
    'test': '', // 判断,if语句()中的内容
    'consequent': '', // 结果,就是满足这个条件后,后续要执行的代码块
    'alternate': '', // else 中的内容,如果没有else,则为null
    'range': 
}

举例:

if (a === 1) {
	console.log(1);
} else {
    console.log(2);
}

WhileStatement-While循环语句

结构:

{
    "type": "WhileStatement",
    "test": ,//
    "body": BlockStatement// 循环体内的代码块
    "range": []
}

例子:

while (1) {}

ForStatement-For循环语句

结构:

{
    "type": "ForStatement",
    "init": // 初始化, 多为变量的声明
    "test": BinaryExpression // 判断
    "update": UpdateExpression // 更新表达式
    "range": []
}

例子:

for (var i = 0; i < p.length; i++) {
}

ReturnSatement-返回语句

结构:

{
    "type": "RetuenStatement",
    "argument": // 返回的值, 可以是具体的值,也可以是一个表达式
    "range": []
}

例子:

function func() {
    return 1;
}

Expression(表达式)

如果要执行一个表达式,必定由 语句 携带着。

AssignmentExpression-赋值表达式

给变量赋值

结构:

{
    "type": "AssignmentExpression",
	"operator": "=",
	"left": Identifier, // 操作符左边, 多为Identifier
    "right": // 操作符右边, 可能为,Identifier,Literal, FucntionExpression
	"range": [] // 代码起始位置
}

例子:

a = 1;
a += 1;
a |= 1;
a ^= 2;

FunctionExpression-函数表达式

{
	"type": "FunctionExpression"
	"id": null
	"params": [Identifier, ] // 函数的参数
 	"body": BlockStatement// 函数体, 就是大括号里面的代码  
	"generator": false,
	"expression": false,
	"async": false,
	"range": []
}

BinaryExpression-二元表达式

结构:

{
    'type': 'BinaryExpression',
    'operator': '===' // 二元操作符,比较操作符, < , > , ===,+,- ...
    'left': '' // 操作符的左边
    'right': '' // 操作符的右边
}

MemberExpression-成员表达式

简言之,就是访问对象的某个属性,这个属性就是成员

结构:

{
    'type': 'MemberExpression',
    'computed': true// 计算, a['a']为true, a.a为false
    'object': '', // 对象
    'property': ''// 成员名
    'range': // 代码起始位置
}

例子:

a.a
a['a']

两者对比

image-20210606110152169

CallExpression-调用表达式

用于函数的调用,

结构:

{
    'type': 'CallExpression',
    'callee': '', // 被调用者,可以理解为被调用的方法
    'arguments': [], // 传递的参数
    'range': []
}

举例:

console.log(1);

此时的callee,就是console.log,则类型为MemberExpression

atob('a')

此时的calledd,就是atob,则类型为Identifier

ObjectExpression-对象表达式

结构:

{
    "type": "ObjectExpression",
    "properties": [Property, Property], // 属性
    "range": []
}

ArrayExpression-数组表达式

结构:

{
    "type": "ArrayExpression",
    "elements": [], // 元素
    "range": []
}

例子:

a = [1, 2]

UpdateExpression-更新运算表达式

update 运算表达式节点,即 ++/--,和一元运算符类似,只是 operator 指向的节点对象类型不同,这里是 update 运算符。

结构:

{
    "type": "UpdateExpression",
    "operator": "++", // 或者--
    "argument": ,
    "prefix": false, // 运算符,是否在前面,++i则为true, i++为false
    "range": []
}

例子:

i++
++i

SequenceExpression-序列表达式

结构:

{
    "type": "SequenceExpression",
    "expressions": [], // 包含的序列节点
    "range": []
}

例子:

function func () {
	var a = 1;
  return a = 2, 2
}

a = 2, 2就是序列表达式

参考文章

[1] 13 个示例快速入门 JS 抽象语法树

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: JavaScript 语法分析器的设计流程通常包括以下步骤: 1. 读入输入代码:首先,语法分析器会读入待分析的 JavaScript 代码。 2. 分词(Tokenization):将代码字符串分解为一个个词法单元(Token)。 3. 语法分析(Parsing):利用词法单元流和语法规则,生成抽象语法树AST)。 4. 代码生成:利用 AST 生成机器码,供解释器或编译器使用。 语法分析器在设计时,通常会使用 LL 或 LR 分析器生成器(如 ANTLR)来构建。这些工具能够利用语法规则生成能够执行分析的代码。 希望这些信息能够帮到您! ### 回答2: JavaScript语法分析是指将JavaScript代码解析成一系列字符组成的语法树的过程。设计流程通常包括以下几个步骤: 1. 分词(Tokenization):首先将输入的JavaScript代码按照特定的规则(如空格、括号、运算符等)进行分词,将代码分割成一个个的词法单元(token),如变量名、关键字、运算符等。 2. 生成词法(Lexing):将分词得到的词法单元进行词法分析,对每个词法单元进行分类,为后续的语法分析做准备。词法分析器会将词法单元转换成一个个的Token对象。 3. 语法分析(Parsing):利用生成的Token对象进行语法分析。语法分析器根据JavaScript语法规则,构建语法树(Abstract Syntax Tree,AST)。语法树是一个以根节点为起点,每个子节点表示代码中的一个表达式、语句、变量等的抽象表示,形成一个层次性结构。 4. 语义分析(Semantic Analysis):在语法树的基础上进行语义分析,检查代码中的语法错误和语义错误,并进行错误处理。语义分析器会检查变量使用是否正确、函数调用是否合法等,确保代码在语义上是正确的。 5. 生成中间表示(Intermediate Representation):根据语法树生成一个中间表示,可以是抽象语法树、字节码、优化的中间表达等,这个中间表示方便后续进行代码生成、优化等操作。 6. 代码生成(Code Generation):根据中间表示生成目标代码,例如生成机器码或者其他可执行的代码。代码生成器将中间表示转换为最终可执行的机器代码或其他目标代码。 以上基本步骤是JavaScript语法分析的设计流程,流程中每一步都起着至关重要的作用,保证了JavaScript代码能够在执行前经过正确的解析分析。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值