一、概述
抽象语法树(abstract syntax code,AST)是源代码的抽象语法结构的树状表示,树上的每个节点都表示源代码中的一种结构。之所以说是抽象的,是因为抽象语法树并不会表示出真实语法中出现的每一个细节,比如说嵌套括号被隐含在树的结构中,并不存在真实节点来表示(相对于具体语法树CST)。
二、如何构建AST
抽象语法树是编译过程的中间产物,经过词法分析、语法分析就会生成AST。
1、词法分析
通过词法分析器分析源文件中的所有字符,将所有的单词或字符逐字转化成符合规范的Token,规范化的token可以分成一下三种类型:
- java关键字:public, static, final, String, int等等;
- 自定义的名称:包名,类名,方法名和变量名;
- 运算符或者逻辑运算符等符号:+、-、*、/、&&,|| 等等。
int i = 1; // 对应的token流为:[int, i, =, 1]
2、语法分析
根据token流进行语法检查,并生成语法树AST,语法树的每一个节点都代表着程序代码中的一个语法结构, 如包、类型、修饰符、运算符、接口、返回值都可以是一个语法结构。
package com.example.adams.astdemo;
public class TestClass {
int x = 0;
int y = 1;
public int testMethod(){
int z = x + y;
return z;
}
}
对应的AST展示为:
三、在IDEA中查看AST
对于AST结构有些不清楚的地方,可以自己写个简单的代码示例,查看对应的AST是如何组织的。
1、工具准备,安装IDEA插件JDT AstView
2、 i + y - z的语法树,是以 + 为根还是以 -为 根?
以4 + 2 * 3 - 1为例,AST如下图,最外层的操作符是 -, 左边的节点是一个加法表达式,右边的节点是 1。
起初认为AST在相同优先级下是从右往左来的构建的,以为这是一个可左可右的选择。后来根据Java操作符优先级相同情况下是从左往右的,那么对于上例中的情况,只有当 - 操作在最外层时,才能把左边加法表达式认为是一个整体,才能满足java语法的要求。
3、/** */、注解与主体(Class、Method)之间的树结构是怎样的?
在直接观察代码,可以看到 /** */、注解是在类之上加的,与类是平行结构,但是他们的作用都是以类为主体的,用来修饰类的。如下图可以看到,在AST中 /** */、注解是类、方法等主体的子节点。
4、java文件的AST是如何组织的
如下图可见,对于一个Java文件来说,AST的最顶层有三个:包声明、import、类声
关注公众号获取更多干货