Java编译相关的JCTree和TreeMaker的API介绍

关于编译原理

在文章深入理解JVM3-1-程序编译与代码优化-前端编译与优化中,其中介绍了javac的编译原理。其中简要流程如下:

  1. 准备过程:初始化插入式注解处理器。
  2. 解析与填充符号表过程
    1. 词法、语法分析:将源代码的字符流转变为标记集合,构造出抽象语法树
    2. 填充符号表:产生符号地址和符号信息。
  3. 插入式注解处理器的注解处理过程:插入式注解处理器的执行阶段。
  4. 分析与字节码生成过程
    1. 标注检查:对语法的静态信息进行检查。
    2. 数据流及控制流分析:对程序动态运行过程进行检查。
    3. 解语法糖:将简化代码编写的语法糖还原为原有的形式。
    4. 字节码生成:将前面各个步骤所生成的信息转化成字节码。

而下面的两个API就是关于抽象语法树,javac给出了注释处理器(processAnnotations)可以让我们读取生成的语法树节点,也干预抽象语法树的生成,我们可以在其中进行更改。

但是首先值得注意的是:下面的两个系类API都是Java私有。并不对外公开,也就是说要使用这些API,必须自行引入。并且要承担其随时改变的风险。

JCTree

JCTree是语法树元素的基类。其解析出的所有抽象语法树节点都继承自该节点。但是我们在自定义节点时,值得注意的说,我们并不能直接newJCTree节点。因为树节点总是在一个语境中,有其对应的结构。其中的pos属性就用于代表该节点在该父节点中的位置。所以JCTree的逻辑是,必须用另一组TreeMakerAPI并依赖父级节点才能进行新建。

下面介绍JCTree的子类,其包含了所有Java的构成元素。

常用节点

AnnotatedTypeTree

指被注释修饰的类型

如下面的s和d:

1
2
@annotationType String s
@annotationType ( arguments ) Date d

其可以用在变量申明中,也可以用在方法参数中。

如:

1
2
3
4
5
6
public class A{
@annotationType private String s;
@annotationType ( arguments ) private Date d;

public void setS(@annotationType String s){};
}

AnnotationTree

注释树节点。

如:

1
2
@annotationType
@annotationType(arguments)

ArrayAccessTree

数组访问表达式的树节点。

如:

1
array[0]

ArrayTypeTree

数组类型的树节点。

例如:

1
int[]

AssignmentTree

赋值表达式的树节点。

例如:

1
2
variable = expression
var = 123

BinaryTree

二元表达式的树节点。

例如:

1
2
3
leftOperand operator rightOperand
1 + 2
3 * 5

BlockTree

语句块的树节点(一般指被花括号包围的语句块)。

例如:

1
2
3
4
5
{ }

{ statements }

static { statements }

BreakTree

break语句的树节点。

例如:

1
2
3
break;

break label ;

CaseTree

switch语句或表达式中一个case的树节点。

例如:

1
2
3
4
5
case expression :
statements

default :
statements

CatchTree

try语句中catch块的树节点。

例如:

1
2
catch ( parameter )
block

ClassTree

类、接口、枚举、记录或注释类型声明的树节点。

例如:

1
2
3
4
5
6
modifiers class simpleName typeParameters
extends extendsClause
implements implementsClause
{
members
}

CompoundAssignmentTree

用于复合赋值操作符的树节点。使用getKind确定操作符的类型。

例如:

1
variable operator expression

注意与简单赋值操作符区别在于操作符不仅仅是=

ConditionalExpressionTree

三目运算符?:的树节点。

例如:

1
condition ? trueExpression : falseExpression

ContinueTree

continue语句的树节点。

例如:

1
2
continue;
continue label ;

DoWhileLoopTree

do...while语句的树节点。

例如:

1
2
3
do
statement
while ( expression );

EnhancedForLoopTree

增强for循环语句的树节点。

例如:

1
2
for ( variable : expression )
statement

ExpressionStatementTree

表达式语句的树节点。

例如:

1
expression ;

ForLoopTree

基本的for循环语句的树节点。

例如:

1
2
for ( initializer ; condition ; update )
statement

IdentifierTree

标识符表达式的树节点。比较基本的树节点。比如用来在二元表达式中作为操作符左右的变量表示。

例如:

1
name

IfTree

if语句的树节点。

例如:

1
2
3
4
5
6
7
if ( condition )
thenStatement

if ( condition )
thenStatement
else
elseStatement

ImportTree

用于导入声明的树节点。(包括静态import)

例如:

1
2
3
import qualifiedIdentifier ;

static import qualifiedIdentifier ;

InstanceOfTree

instanceof表达式的树节点。

例如:

1
expression instanceof type

LambdaExpressionTree

lambda表达式的树节点。

例如:

1
2
3
()->{}
(List<String> ls)->ls.size()
(x,y)-> { return x + y; }

LambdaExpressionTree.BodyKind

lambda表达式的的body类型。

Lambda表达式有两种形式:

  • expression lambda:主体是一个表达式。
  • statement lambdas:主题是一个块。

LiteralTree

字面表达式的树节点。

例如:

1
2
value
int a = 123; //中的123

MemberReferenceTree

成员引用表达式的树节点。

一般用在函数式接口的位置,可与lambda表达式混用。

例如:

1
2
expression # [ identifier | new ]
String#hashCode

注意这里的#::一致,都可以表示方法引用。

如:

1
2
String::hashCode
String#hashCode

都表示String类的hashcode方法引用。其可以像lambda表达式一样传递。

MemberReferenceTree.ReferenceMode

有两种成员引用:

  • 方法引用。
  • 构造器引用。

MemberSelectTree

成员访问表达式的树节点。

例如:

1
2
expression . identifier
obj.prop

MethodInvocationTree

方法调用表达式的树节点。

例如:

1
2
identifier ( arguments )
this . typeArguments identifier ( arguments )

MethodTree

方法或注释类型元素声明的树节点。

例如:

1
2
3
4
5
modifiers typeParameters type name
( parameters )
body

modifiers type name () default defaultValue

ModifiersTree

用于修饰符(包括声明的注释)的树节点。

例如:

1
2
3
4
5
6
flags

flags annotations

public
final

NewArrayTree

用于创建数组新实例的表达式的树节点。

例如:

1
2
3
4
5
6
new type dimensions initializers

new type dimensions [ ] initializers

new int[] a
new int a[]

NewClassTree

声明类的新实例的树节点。

例如:

1
2
3
4
5
6
7
8
new identifier ( )

new identifier ( arguments )

new typeArguments identifier ( arguments )
classBody

enclosingExpression.new identifier ( arguments )

ParameterizedTypeTree

类型参数的类型表达式的树节点。

例如:

1
type < typeArguments >

PrimitiveTypeTree

基本类型的树节点。

例如:

1
2
primitiveTypeKind
int a = 1; //中的int

ReturnTree

return语句的树节点。

例如:

1
2
return;
return expression;

StatementTree

用作不同类型语句的基类的树节点。

SwitchExpressionTree

switch表达式的树节点。

例如:

1
2
3
switch ( expression ) {
cases
}

SwitchTree

switch语句的树节点。

例如:

1
2
3
switch ( expression ) {
cases
}

SynchronizedTree

synchronized语句的树节点。

例如:

1
2
synchronized ( expression )
block

ThrowTree

抛出语句的树节点。

例如:

1
throw expression;

TryTree

try语句的树节点。

例如:

1
2
3
4
5
try
block
catches
finally
finallyBlock

TypeCastTree

类型转换表达式的树节点。

例如:

1
( type ) expression

TypeParameterTree

类型参数的树节点。

例如:

1
2
3
4
5
name

name extends bounds

annotations name

VariableTree

用于变量声明的树节点。

例如:

1
2
3
modifiers type name initializer ;
modifiers type qualified-name.this
private int a = 1;

WhileLoopTree

一个while循环语句的树节点。

例如:

1
2
while ( condition )
statement

其他节点

AssertTree

断言树节点。

例如:

1
2
assert condition ;
assert condition : detail ;

BindingPatternTree

预览特性,可能不稳定。

CaseLabelTree

预览特性,可能不稳定。

CompoundAssignmentTree

表示普通编译单元和模块编译单元的抽象语法树。

DefaultCaseLabelTree

预览特性,可能不稳定。

一个case标号,在case中标记default (null, default)。

DirectiveTree

模块树中所有指令的超类型。该指令一般指在module-info.java中的指令。

EmptyStatementTree

一个空(跳过)语句的树节点。

例如:

1
;

ErroneousTree

用来代替一个畸形的表达式的树节点。

ExportsTree

模块声明中’exports’指令的树节点。

如:

1
2
exports package-name;
exports package-name to module-name;

ExpressionTree

预览特性,可能不稳定。

用作不同类型表达式的基类的树节点。

GuardedPatternTree

预览特性,可能不稳定。

守护模式树。

IntersectionTypeTree

转换表达式中交集类型的树节点。

LabeledStatementTree

带label的表达式的树节点。一般和带label的break语句一起使用。

LineMap

提供在编译单元的字符位置和行号之间进行转换的方法。

其包含以下方法:

  • getColumnNumber:查找字符位置的列。
  • getLineNumber:查找包含位置的行;行终止字符在它终止的行上。
  • getPosition:找到对应于(行,列)的位置。
  • getStartPosition:查找一行的起始位置。

ModuleTree

模块声明的树节点。

例如:

1
2
3
4
annotations
[open] module module-name {
directives
}

ModuleTree.ModuleKind

模块的类型。

OpensTree

模块声明中’open ‘指令的树节点。

例如:

1
2
opens   package-name;
opens package-name to module-name;

PackageTree

表示包声明的树节点。

ParenthesizedPatternTree

预览特性,可能不稳定。

圆括号模式的树节点。

ParenthesizedTree

用于圆括号表达式的树节点。注意:解析器不会保留圆括号。

例如:

1
( expression )

PatternTree

预览特性,可能不稳定。

用作不同类型模式的基类的树节点。

ProvidesTree

‘ providers ‘指令在模块声明中的树节点。

例如:

1
provides service-name with implementation-name;

RequiresTree

‘require ‘指令在模块声明中的树节点。

例如:

1
2
3
requires module-name;
requires static module-name;
requires transitive module-name;

Scope(作用域)

用于决定本地可以用程序元素的接口,这些元素可能是本地变量或者import。在创建元素时,Scope与给定的程序位置相关联;例如,树节点。这个位置可以用来推断一个封闭的方法和/或类。

Scope本身不包含与包含其位置的方法和类的参数、方法和字段相对应的元素的详细信息。但是,这些元素可以从外围元素中确定。

Scope可以包含在封闭作用域中。最外层Scope包含那些通过”star import”声明可用的元素;其中的作用域包含编译单元的顶级元素,包括任何命名导入。

UnionTypeTree

多包变量声明中用于union类型表达式的树节点。

UsesTree

在模块声明中用于’uses’指令的树节点。

例如:

1
uses service-name;

WildcardTree

通配符类型参数的树节点。

例如:

1
2
3
4
5
?

? extends bound

? super bound

YieldTree

yield语句的树节点。

例如:

1
yield expression ;

Blocks, Statements

  • Blocks是一个Statements序列、局部变量声明语句、局部类和大括号内的接口声明。

  • Statements也是Statements的序列。其由多种类型,比如

    • 空语句:空语句什么也不做。

      1
      2
      EmptyStatement:
      ;
    • 标签语句:语句可以有标签前缀。

      1
      2
      3
      4
      LabeledStatement:
      Identifier : Statement
      LabeledStatementNoShortIf:
      Identifier : StatementNoShortIf
    • 表达式语句:某些类型的表达式可以通过后跟分号作为语句来使用。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      ExpressionStatement:
      StatementExpression ;
      StatementExpression:
      Assignment
      PreIncrementExpression
      PreDecrementExpression
      PostIncrementExpression
      PostDecrementExpression
      MethodInvocation
      ClassInstanceCreationExpression
    • if语句:

      1
      2
      3
      4
      5
      6
      IfThenStatement:
      if ( Expression ) Statement
      IfThenElseStatement:
      if ( Expression ) StatementNoShortIf else Statement
      IfThenElseStatementNoShortIf:
      if ( Expression ) StatementNoShortIf else StatementNoShortIf
    • if - then - else语句

    • 断言语句

    • switch语句

    • while语句

    • do语句

    • for语句

    • 增强for循环语句

    • break语句

    • continue语句

    • return语句

    • throw语句

    • synchronized 语句

    • try语句

    • yield语句

    • 无法到达语句(Unreachable Statements):如果语句由于无法访问而无法执行,则为编译时错误。

具体见Java Language Specification

其继承关系如下:

Tree继承图

TreeMaker

既然上面说到抽象语法树节点必须依赖一个context,则无法直接new。所以就有了TreeMaker,用来在指定下文中来新建抽象语法树节点。

instance(Context context)

该方法用于获取TreeMaker实例。其中context可以通过

1
Context context = ((JavacProcessingEnvironment) processingEnv).getContext();

来获取。

at

这个函数是用来改变当前树节点在context的位置。并不会产生新的树节点。源码如下:

1
2
3
4
5
6
/** Reassign current position.
*/
public TreeMaker at(int pos) {
this.pos = pos;
return this;
}

Modifiers(long flags)

用于新建一个标识符。其中入参flags可以用枚举类型com.sun.tools.javac.code.Flags,且支持拼接(枚举值经过精心设计)。

例如:

1
treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC + Flags.FINAL);

Import(JCTree qualid, boolean importStatic)

用来新建一个Import语句。其中qualid是要引入的类。

ClassDef

用来新建一个类语句,所有参数如下:

1
2
3
4
5
6
JCClassDecl ClassDef(JCModifiers mods,							// 修饰符
Name name, // 类的名字
List<JCTypeParameter> typarams, // 类型参数,如<T>
JCExpression extending, // 继承的类,extends T
List<JCExpression> implementing, // 实现的接口
List<JCTree> defs); // 类中的具体语句,如类型声明或者方法声明,所以是一个List

MethodDef

用来新建一个犯法语句,所有参数如下:

1
2
3
4
5
6
7
8
9
JCMethodDecl MethodDef(JCModifiers mods,						// 修饰符
Name name, // 方法的名字
JCExpression restype, // 返回类型
List<JCTypeParameter> typarams, // 类型参数列表,如<T>
JCVariableDecl recvparam, // receiver type,好像实际上没啥用
List<JCVariableDecl> params, // 参数列表
List<JCExpression> thrown, // 抛出错误的列表
JCBlock body, // 方法体
JCExpression defaultValue); // 默认方法,如interface中的默认实现

VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init)

用来新建一个变量。

参数意义如下:

  • mods:修饰符
  • name:变量名
  • vartype:变量类型
  • init:初始化

Skip

用来新建一个;语句块,没有参数。

Block(long flags, List<JCStatement> stats)

用来新建一个块语句。

参数意义如下:

  • flags:访问标志
  • stats:语句列表

DoLoop(JCStatement body, JCExpression cond)

用来新建一个do...while语句。

参数意义如下:

  • body:循环体的语句
  • cond:循环条件

JCWhileLoop WhileLoop(JCExpression cond, JCStatement body)

用来新建一个while循环。

参数意义如下:

  • cond:循环条件。
  • body:循环体语句。

ForLoop

用来新建一个for循环。

1
2
3
4
JCForLoop ForLoop(List<JCStatement> init,					// 循环初始化
JCExpression cond, // 循环条件
List<JCExpressionStatement> step, // 循环的变化语句
JCStatement body); // 循环体

JCEnhancedForLoop ForeachLoop(JCVariableDecl var, JCExpression expr, JCStatement body)

用来新建一个增强for循环。

其参数意义如下:

  • var:每次循环的单个变量
  • expr:被循环的变量
  • body:循环体

JCLabeledStatement Labelled(Name label, JCStatement body)

用来新建一个标记块。

其参数意义如下:

  • label:标签名
  • body:块体

public JCSwitch Switch(JCExpression selector, List<JCCase> cases)

用来新建一个Switch语句。

其参数意义如下:

  • selector: switch语句中被判断的表达式
  • cases:switch语句的cases

public JCCase Case(JCExpression pat, List<JCStatement> stats)

用来新建一个case语句。

其参数意义如下:

  • pat:case语句的条件表达式
  • stats:符合条件时的语句块

public JCSynchronized Synchronized(JCExpression lock, JCBlock body)

用来新建一个synchronized语句。

其参数意义如下:

  • lock:同步锁的对象
  • body:synchronized的语句块

Try

用来新建一个try语句。

1
2
3
4
public JCTry Try(List<JCTree> resources,				// try-resource语句中的资源列表
JCBlock body, // try的主体语句块
List<JCCatch> catchers, // try对应的catch语句列表
JCBlock finalizer) // finally语句

public JCCatch Catch(JCVariableDecl param, JCBlock body)

用来新建一个catch语句。

其参数意义如下:

  • param:catch语句的参数
  • body:catch语句的主体语句块

Conditional

用来新建一个三目表达式。

1
2
3
public JCConditional Conditional(JCExpression cond,				// 条件判断
JCExpression thenpart, // 结果为真的语句
JCExpression elsepart) // 结果为假的语句

public JCIf If(JCExpression cond, JCStatement thenpart, JCStatement elsepart)

用来新建一个if语句。

其参数意义如下:

  • cond:if条件语句
  • thenpart:if的语句块
  • elsepart:else的语句块

JCExpressionStatement Exec(JCExpression expr)

用来创建一个可执行语句。

其参数意义如下:

  • expr:要执行的语句。

例如,TreeMaker.Apply以及TreeMaker.Assign就需要外面包一层TreeMaker.Exec来获得一个JCExpressionStatement

public JCBreak Break(?Name label)

用来创建一个break语句,可以是带标签的。

public JCContinue Continue(?Name label)

用来创建一个continue语句,可以是带标签的。

public JCReturn Return(JCExpression expr)

用来创建一个return语句,expr是要返回的表达式。

public JCThrow Throw(JCExpression expr)

用来新建一个throw语句,expr是要抛出的错误表达式。

NewClass

用来新建一个新的类实例化,如new A()

1
2
3
4
5
public JCNewClass NewClass(JCExpression encl,					// 作用域,一般是在顶层,可以通getEnclosingExpression函数来获取
List<JCExpression> typeargs, // 类型参数列表
JCExpression clazz, //
List<JCExpression> args, // 实例化时需要的构造器参数
JCClassDecl def) // 要实例化的类的定义

NewArray

用来创建一个数组。例如,new int[10][10]{1,2,3}

1
2
3
public JCNewArray NewArray(JCExpression elemtype,		// 数组对的类型
List<JCExpression> dims, // 数组的维度列表
List<JCExpression> elems) // 数组的元素列表

public JCLambda Lambda(List<JCVariableDecl> params,JCTree body)

用来创建一个lambda表达式。

其参数意义如下:

  • params:参数
  • body:lambda表达式的方法体

public JCAssign Assign(JCExpression lhs, JCExpression rhs)

用来创建一个赋值表达式,如例a = b

其参数意义如下:

  • lhs:左侧的表示
  • rhs:右侧的表示

public JCAssignOp Assignop(JCTree.Tag opcode, JCTree lhs, JCTree rhs)

用来创建一个复合赋值运算符。例如:a += bc-= d等操作。

其参数意义如下:

  • opcode:操作符
  • lhs:左侧表达式
  • rhs:右侧表达式

public JCBinary Binary(JCTree.Tag opcode, JCExpression lhs, JCExpression rhs)

创建一个二元操作符。如a - bc + d

其参数意义如下:

  • opcode:操作符
  • lhs:左侧表达式
  • rhs:右侧表达式

public JCTypeCast TypeCast(JCTree clazz, JCExpression expr)

创建一个类型强转。如(int)c

其参数意义如下:

  • clazz:要转换的类型
  • expr:要转换的变量

public JCArrayAccess Indexed(JCExpression indexed, JCExpression index)

创建一个根据数组下标获取语句,如arr[0]

其参数意义如下:

  • indexed:被获取的数组表达式
  • index:数组下标

public JCFieldAccess Select(JCExpression selected, Name selector)

创建一个对象获取语句,如obj.prop

其参数意义如下:

  • selected:被选择的对象
  • selector:要选择的对象属性

public JCIdent Ident(Name name)

创建一个标识符语句。例如:a = 10中的a。

public JCLiteral Literal(TypeTag tag, Object value)

创建一个字面量表达式。如String a = '10'中的'10'

其参数意义如下:

  • tag:字面量表达式的类型
  • value:字面量表达式的值

Apply

创建一个方法调用。如method1(10)

1
2
3
public JCMethodInvocation Apply(List<JCExpression> typeargs,	// 类型参数列表
JCExpression fn, // 函数
List<JCExpression> args) // 函数的参数

Powered by Hexo and Hexo-theme-hiker

Copyright © 2019 - 2024 My Wonderland All Rights Reserved.

UV : | PV :