Loading...
墨滴

屈霸霸

2021/07/02  阅读:307  主题:橙心

盘一盘AST

前端技术发展日新月异,各种技术框架让人烟花缭乱,大多数时间我们只需要关注业务,如何使用是我们的主要任务,但是如果我们深入学习,就会发现永远绕不开一个专业名词抽象语法树(Abstract Syntax Tree),简称AST,那么我们今天就来盘一盘它。

一、AST何许东西也

在计算机科学中,抽象语法树,或简称语法树(Syntax tree),是源代码 语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。 ----维基百科

根据以上我们可以看到AST其实就是计算机语言语法结构的描述,那也就是说你所熟知的语言JavaScript、Java、python、Html甚至Css都需要到AST这里走一遭,所以足以看出AST的重要性。讲这么多只是让大家对AST的重要性有个足够的认识,那它具体是什么东西我们还需要来看一哈。

AST其实是对我们来讲只是一个对象,它无关乎语法结构,不会记录源语言真实语法中的每个细节(比如省略分隔符),这也是名字中抽象一词的由来,与之相对应的其实还有另一种树,具 象语法树(Concret Syntax Tree),简称CST,它有代码直接翻译解析而来,因而保留了原语法的所有信息,也被称之为解析树。

为什么要去解析源代码成一个通用对象呢?各种语言语法种类繁多,但是计算机是无法识别我们写的代码的,所以就需要一种通用的数据结构来描述,那AST其实就是那个东西。同时,因为AST是真实存在且存在一定逻辑的,那我们也就可以在AST上做点文章,搞点花活:)

二、AST如何产生

我们来了解一下Javascript解析流程,先整个图see see:

0686CD87-5BCA-4C32-855D-08200500EA7E.png
0686CD87-5BCA-4C32-855D-08200500EA7E.png

首先 ’张三’ 在运用毕生所学在vscode中写了以下代码

const name = '张三';
function getTitle(){
  return '法外狂徒' ;
};

这时候为了弄明白张三表达的是什么思想,就需要通过解析器(parse)对这行代码进行解析。parse分两步进行。

词法分析:词法解析是一个将字符流(char stream)转换成记号流(token stream)的过程,会将code中每个词都拆分开来,比如const name = '张三’ 就会被拆分成const、name、=、’张三‘,大家可以通过这个网站Esprima: Parser具体看一下。

语法分析:通过词法分析我们拿到了token流,接下来我们就可以通过对token进行语法分析生成AST,比如const是一个声明参数,就会被标记为Declaration,以此类推,逐步转换成一棵AST。AST可以通过AST explorer这个网站在线查看。

7CE80182-C358-49AA-86ED-FEB0579A8225.png
7CE80182-C358-49AA-86ED-FEB0579A8225.png

这里提到了解析器parse的概念,解析器就是用来解析源码到AST的工具,许多的解析器比如babel parser、eslint parser、typescript parser等,他们都基于estree标准,只不过是另外做了扩展,随后acorn出现,解析速度更快,同时支持插件扩展,所以各家就开始基于acorn进行重构。所以现在babel、eslint都可以通过编写插件进行自定义扩展。

三、AST结构

知道了AST的解析过程,我们来具体看一下AST的结构,以 babel解析为例:

04C0F7A6-3456-4BDE-BCED-513A492FC329.png
04C0F7A6-3456-4BDE-BCED-513A492FC329.png

这是一个const name = ‘张三’ 的AST结构,从上面可以看到整个对象包裹在Program中,Program表示整个程序的节点,它有一个body参数用来存放程序子内容主要看一下body中的内容

VariableDeclaration: 声明语句类型,还有FunctionDeclaration、ExpressionStatement等等。
start、end:表示当前内容在整个文档流中存在的位置。
loc:展示当前内容所在行号和列号
range:表示位置,同上
leadingComments:注释列表,注释信息会展示在这里
declarations:声明语句特有的展示声明信息的参数,
kind:声明类型
......

AST既然是对源码的抽象,那么源码中包含标识符、字面量、表达式、语句等,对应AST就都会有相应的映射,比如标识符—>Identifier、字面量—>Literal等等,具体的可以通过上面的网站去看看。

四、AST有何用

要问AST有何用?你一定天天都在用,比如Eslint,比如Babel,再比如Typescript,Eslint中集成了大量的插件用于规范化代码,这些插件就是通过对AST进行修改实现的各种功能。OK,那如何修改AST呢。拿捏。

来人,放图

44ABEDF4-7E73-4445-B34F-0EE1C44530E3.png
44ABEDF4-7E73-4445-B34F-0EE1C44530E3.png

没错,还是这张图,只不过我们现在来关注中间的部分,transform很亮眼,这就是我们修改AST的地方,也是各种Eslint、babel插件搞活的地方。既然源码能够解析成AST,那么AST同样也就能生成源码,所以我们在AST上按着规范进行修改,那么一定就能拿到预期的效果,至于如何修改本次就不做具体阐述了,如果有兴趣后面我可以写写Eslint和Babel插件的编写。

五、总结一下

AST非常重要,是我们走向原理的必经之路,不是很难,但是各种定义比较多,多看多查就能了解,了解以及学会使用AST后,就会发现很多正在使用的工具原理就显而易见了,甚至我们也可以自己编写插件,甚至解析器,祝大家学的愉快~

等一下,我还有最后一句话

Time is fair, because it gives everyone 24 hours.

屈霸霸

2021/07/02  阅读:307  主题:橙心

作者介绍

屈霸霸