日常工作中,我们会碰到 js 代码解析的场景,比如分析代码中 require 了哪些包,有些什么关键 API 调用,大部分情况使用正则表达式来处理,可一旦场景复杂,或者依赖于代码上下文时,正则就很难处理了,这时候就要用到抽象语法树。常见的 uglify、eslint、babel、webpack 等等都是基于抽象语法树来处理的,如此强大,有必要好好了解一下。
抽象语法树即:Abstract Syntax Tree。简称 AST,见下图。
图中树状数据结构即 AST,从这个过程可以看到将代码转成 AST 后,通过操作节点来改变代码。
获得抽象语法树的过程为:代码 => 词法分析 => 语法分析 => AST词法分析:把字符串形式的代码转换为令牌(tokens)流。语法分析:把一个令牌流转换成 AST 的形式。这个阶段会使用令牌中的信息把它们转换成一个 AST 的表述结构,这样更易于后续的操作。
如下图,代码为一个简单的函数声明。词法分析阶段,将代码作为字符串输入获得关键词,图中 function、 square、 (、 )、 {、 }等都被识别为关键词 (稍微回忆下编译原理,字符挨个入栈,符合一定规则即出栈)。语法分析阶段,对关键词的组合形成一个个节点,如 n*n 这 3 个关键词组合成 二元表达式,关键词 return 与二元表达式组合成 return语句。最后组合成一个 函数声明语句。
如何获得 AST 已经简单介绍了,那 AST 最终应该以什么样的数据结构存在呢,先看看上述函数声明的 AST 结构
那解析的依据是什么,为什么要以上图的结构出现,业界已经有了一套成熟的规范。