一、AST

AST  abstract syntax tree (抽象语法结构树),是对java语言的一种抽象,每个节点都能对应到一种java语法,最终一个java文件就是由棵节点树构成

二、Tree

Tree是一个接口,是AST节点的抽象,内部有一个最重要的枚举Kind,定义了java中的每条语句的格式,也是对应着AST的一个节点

以下均为子接口,每个结构都定义了语法节点类型

Tree

  • WildcardTree
  • TypeParameterType
  • StatementTree      (一个完整的语句,比如简单的"int a = 1;",注意最后的“;”)
    • ThrowTree
    • ReturnTree
    • TryTree
    • ContinueTree
    • BreakTree
    • BlockTree
    • DoWhileLoopTree
    • ClassTree
    • VariableTree
    • WhileLoopTree
    • ForLoopTree
    • SwitchTree
    • SynchronizedTree
    • EnhancedForLoopTree
    • LabeedStatementTree
    • AssertTree
    • EmptyStatementTree
    • IfTree
    • ExpressionStatementTree
  • CatchTree
  • MethodTree
  • ArrayTypeTree
  • UnionTypeTree
  • ModifiersTree
  • ParameterizedTypeTree
  • CaseTree
  • ExpressionTree       (一个非完整的语句,比如简单的"a = 1",注意最后没有“;”)
    • MemberReferenceTree
    • LambdaExpressionTree
    • UnaryTree
    • MethodInvocationTree
    • AnnotatedTypeTree
    • CompoundAssignmentTree
    • BinaryTree
    • ErroneousTree
    • MemberSelectTree
    • ArrayAccessTree
    • TypeCastTree
    • NewClassTree
    • ConditionalExpressionTree
    • ParenthesizedTree
    • AnnotationTree
    • NewArrayType
    • InstanceOfTree
    • IdentifierTree
    • AssignmentTree
    • LiteralTree
  • CompilationUnitTree
  • IntersectionTypeTree
  • PrimitiveTypeTree
  • Import

三、Kind

AST 节点类型,对应着java的语法

枚举类型Tree节点(就是上面列出的接口)定义示例
ANNOTATED_TYPEAnnotatedTypeTree

注解类型,可以用在任何类型上

注解的Target为:TYPE_PARAMETER

TYPE_USE

@NotNull String
ANNOTATIONAnnotationTree普通的注解

@Data

@JsonProperties(value="sdf")

TYPE_ANNOTATIONAnnotationTree跟ANNOTATION,待验证有什么区别
ARRAY_ACCESSArrayAccessTree数组访问array[3]
ARRAY_TYPEArrayTypeTree数组类型int[]
ASSIGNMENTAssignmentTree赋值a = 1
BLOCKBlockTree语句块

{}

{ statements }

static { statements }

BREAKBreakTreebreak

break;

break label;

CASECaseTreecase 语句

case expression:statements

default: statements

CATCHCatchTreecatch 语句

catch(parameter)  block

注:这些语句会有嵌套问题

CLASS

INTERFACE

ENUM

ANNOTATION_TYPE

ClassTreeclass 定义modifiers class simpleName typeParameters
       extends extendsClause
       implements implementsClause
{
   <em>members</em>
}
COMPILATION_UNITCompilationUnitTree

一个编译单元

包括源文件和package-info.java

CONDITIONAL_EXPRESSIONConditionalExpressionTree三元运算符a == 1 ? 1 : 0
CONTINUEContinueTreecontinue 语句

continue;

continue label;

DO_WHILE_LOOPDoWhileLoopTreedo...while
ENHANCED_FOR_LOOPEnhancedForLoopTree增强forfor(int i: intlist) { statement }
EXPRESSION_STATEMENTExpressionStatementTree语句
MEMBER_SELECTMemberSelectTree对象.操作aClass.aparams
MEMBER_REFERENCEMemberReferenceTree成员引用表达式
FOR_LOOPForLoopTreefor循环
IDENTIFIERIdentifierTree识别符,与literal区分开

a = 1

a 就是一个identifier

IFIfTree
IMPORTImportTree
INSTANCE_OFInstanceOfTreeinstanceof 表达式
LABELED_STATEMENTLabeledStatementTreelabel语法label : statement
METHODMethodTree方法定义方法
modifiers typeParameters type name (parameters )
   body
 
注解
modifiers type name () default defaultValue
METHOD_INVOCATIONMethodInvocationTreemethod invoke语法
MODIFIERSModifiersTree

修饰符(Modifier)

包括注解

NEW_ARRAYNewArrayTree
NEW_CLASSNewClassTree
LAMBDA_EXPRESSIONLambdaExpressionTreelambda表达式
PRIMITIVE_TYPEPrimitiveTypeTree基础类型
RETURNReturnTreereturn
EMPTY_STATEMENTEmptyStatementTree空的";"
SWITCHSwitchTree
SYNCHRONIZEDSynchronizedTree
THROWThrowTree
TRYTryTree
PARAMETERIZED_TYPEParameterizedTypeTree泛型List<Integer>
UNION_TYPEUnionTypeTree多变量声明

try {

}catch(Exception e1 | Exception e2){

}

INTERSECTION_TYPEIntersectionTypeTreeT extends MyA & MyB
TYPE_CASTTypeCastTree强转语句(int)a
TYPE_PARAMETERTypeParameterTree
VARIABLEVariableTree变量

modifiers type name initializer ;

modifiers type qualified-name.this

WHILE_LOOPWhileLoopTree

POSTFIX_INCREMENT

POSTFIX_DECREMENT

PREFIX_INCREMENT

PREFIX_DECREMENT

UNARY_PLUS

UNARY_MINUS

BITWISE_COMPLEMENT

LOGICAL_COMPLEMENT

UnaryTree运算符

++、--、+、-、~、!、*、/、%

MULTIPLY

DIVIDE

REMAINDER

PLUS

MINUS

LEFT_SHIFT

RIGHT_SHIFT

UNSIGNED_RIGHT_SHIFT

LESS_THAN

GREATER_THAN

LESS_THAN_EQUAL

GREATER_THAN_EQUAL

EQUAL_TO

NOT_EQUAL_TO

AND

XOR

OR

CONDITIONAL_AND

CONDITIONAL_OR

BinaryTree两元运算

MULTIPLY_ASSIGNMENT

DIVIDE_ASSIGNMENT

REMAINDER_ASSIGNMENT

PLUS_ASSIGNMENT

MINUS_ASSIGNMENT

LEFT_SHIFT_ASSIGNMENT

RIGHT_SHIFT_ASSIGNMENT

UNSIGNED_RIGHT_SHIFT_ASSIGNMENT

AND_ASSIGNMENT

XOR_ASSIGNMENT

OR_ASSIGNMENT

CompoundAssignmentTree赋值运算符+=、-=、*=

INT_LITERAL

LONG_LITERAL

FLOAT_LITERAL

DOUBLE_LITERAL

BOOLEAN_LITERAL

CHAR_LITERAL

STRING_LITERAL

NULL_LITERAL

LiteralTree字面值a =  1  (1就是)
OTHERnull

 四、JCTree

com.sun.tools.javac.tree.JCTree 是Tree的一个抽象实现类,有各种实现类,代表着一个个的AST节点

JC具体类实现TreeTagKind备注
LetExprLETEXPR不支持
JCErroneousErroneousTreeERRONEOUSERRONEOUS
JCAnnotatedTypeAnnotatedTypeTreeANNOTATED_TYPEANNOTATED_TYPE
JCModifiersModifiersTreeMODIFIERSMODIFIERS
JCAnnotationAnnotationTree
JCTypeParameterTypeParameterTreeTYPEPARAMETERTYPE_PARAMETER
JCTypeIntersectionIntersectionTypeTreeTYPEINTERSECTIONINTERSECTION_TYPE
JCTypeUnionUnionTypeTreeTYPEUNIONUNION_TYPE
JCTypeApplyParameterizedTypeTreeTYPEAPPLYPARAMETERIZED_TYPE
JCArrayTypeTreeArrayTypeTreeTYPEARRAYARRAY_TYPE
JCPrimitiveTypeTreePrimitiveTypeTreeTYPEIDENTPRIMITIVE_TYPE
JCLiteralLiteralTreeLITERAL

INT_LITERAL

LONG_LITERAL

... 以LITERAL结尾的

JCIdentIdentifierTreeIDENTIDENTIFIER
JCMemberReferenceMemberReferenceTreeREFERENCEMEMBER_REFERENCE
JCFieldAccessMemberSelectTreeSELECTMEMBER_SELECT
JCArrayAccessArrayAccessTreeINDEXEDARRAY_ACCESS
JCInstanceOfInstanceOfTreeTYPETESTINSTANCE_OF
JCTypeCastTypeCastTreeTYPE_CASTTYPECAST
JCBinaryBinaryTree根据操作符定根据tag映射
JCAssignOpCompoundAssignmentTree

赋值,根据操作符定

支持的是 “+=”这种

根据tag映射
JCAssignAssignmentTree

ASSIGN

支持的是直接赋值

ASSIGNMENT
JCParensParenthesizedTreePARENSPARENTHESIZED
JCLambdaLambdaExpressionTreeLAMBDALAMBDA_EXPRESSION
JCNewArrayNewArrayTreeNEWARRAYNEW_ARRAY
JCNewClassNewClassTreeNEWCLASSNEW_CLASS
JCMethodInvocationMethodInvocationTreeAPPLYMETHOD_INVOCATION
JCAssertAssertTreeASSERTASSERT
JCThrowThrowTreeTHROWTHROW
JCReturnReturnTreeRETURNRETURN
JCContinueContinueTreeCONTINUECONTINUE
JCBreakBreakTreeBREAKBREAK
JCExpressionStatementExpressionStatementTreeEXECEXPRESSION_STATEMENT
JCIfIfTreeIFIF
JCConditionalConditionalExpressionTreeCONDEXPRCONDITIONAL_EXPRESSION
JCCatchCatchTreeCATCHCATCH
JCTryTryTreeTRYTRY
JCSynchronizedSynchronizedTreeSYNCHRONIZEDSYNCHRONIZED
JCCaseCaseTreeCASECASE
JCSwitchSwitchTreeSWITCHSWITCH
JCLabeledStatementLabeledStatementTreeLABELLEDLABELED_STATEMENT
JCEnhancedForLoopEnhancedForLoopTreeFOREACHLOOPENHANCED_FOR_LOOP
JCForLoopForLoopTreeFORLOOPFOR_LOOP
JCWhileLoopWhileLoopTreeWHILELOOPWHILE_LOOP
JCDoWhileLoopDoWhileLoopTreeDOLOOPDO_WHILE_LOOP
JCBlockBlockTreeBLOCKBLOCK
JCSkipEmptyStatementTreeSKIPEMPTY_STATEMENT
JCVariableDeclVariableTreeVARDEFVARIABLE
JCMethodDeclMethodTreeMETHODDEFMETHOD
JCClassDeclClassTreeCLASSDEF

ANNOTATION_TYPE

INTERFACE

ENUM

CLASS

JCImportImportTreeIMPORTIMPORT
JCCompilationUnitCompilationUnitTreeTOPLEVELCOMPILATION_UNIT

五、JC类的Factory

细心阅读会发现,各种JC类的构造函数都是protected,也就是说,并不能直接进行初始化,所以现在要使用Factory,Factory是各种JC类的工厂定义

六、TreeMaker

TreeMaker实现了Factory接口,所以我们它会是我们经常使用的一个类

还需要关注的一个Names,这个基本是创建一个节点的开始

Names: 用来存储和表示解析后的词法,每个字符集合都会是一个Name对象,所有的对象都存储在Name.Table内部类中。

在学习以下内容时,一定要熟练掌握JCIdent和Names。

Javac编译原理 - wade&luffy - 博客园


 

javac源码笔记与简单的编译原理 | Ren's Time Overflow Skyline ^_^

深入分析 Javac 编译原理 - 知乎

6.1、添加 import

// import com.leisure.lombok.thrift.AstTreeClass
// 获取标识符
JCTree.JCIdent jcIdent = treeMaker.Ident(names.fromString("com.leisure.lombok.thrift"));
// 获取标识符
Name className = names.fromString("AstTreeClass");
// 定义访问
JCTree.JCFieldAccess jcFieldAccess = treeMaker.Select(jcIdent, className);
// 添加import节点
JCTree.JCImport anImport = treeMaker.Import(jcFieldAccess, false);
// 加入AST树种
jcCompilationUnit.defs = jcCompilationUnit.defs.append(anImport);

6.2、定义属性

默认构造函数

//private AstTreeClass variable = new AstTreeClass()
        // new AstTreeClass()
        JCTree.JCNewClass newClass = treeMaker.NewClass(null, null, treeMaker.Ident(names.fromString("AstTreeClass")), List.nil(), null);

        // private AstTreeClass variable = ...
        JCTree.JCVariableDecl variableDecl = treeMaker.VarDef(treeMaker.Modifiers(Modifier.PRIVATE.ordinal()),
                names.fromString("variable"), treeMaker.Ident(names.fromString("AstTreeClass")), newClass);

带参数的构造函数

使用这个我们就可以实现@Slf4j了(当然了,还需要有插件,才能真正像@Slf4j一样使用)

//public static final AstTreeClass staticVariable = new AstTreeClass(1)
        JCTree.JCLiteral constantOne = treeMaker.Literal(1);
        JCTree.JCNewClass newClass1 = treeMaker.NewClass(null, null, treeMaker.Ident(names.fromString("AstTreeClass")), List.of(constantOne), null);

        JCTree.JCVariableDecl staticVariableDecl = treeMaker.VarDef(
                treeMaker.Modifiers(Flags.PUBLIC + Flags.STATIC + Flags.FINAL),
                names.fromString("staticVariable"),
                treeMaker.Ident(names.fromString("AstTreeClass")),
                newClass1
        );

6.4、添加方法

            String name = variableDecl.name.toString();
            JCTree.JCExpression varType = variableDecl.vartype;
            // getter,假设name长度大于1
            String getterMethodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
            // this.name
            JCTree.JCExpression thisName = treeMaker.Select(treeMaker.This(classDecl.sym.type), names.fromString(name));
            JCTree.JCReturn jcReturn = treeMaker.Return(thisName);
            // public type getName() {return this.name;}
            JCTree.JCMethodDecl getter = treeMaker.MethodDef(
                    treeMaker.Modifiers(Flags.PUBLIC), // 访问标识
                    names.fromString(getterMethodName), // 方法名字
                    varType,                            // 返回类型
                    List.nil(),                          // 泛型形参列表
                    List.nil(),                        // 参数列表
                    List.nil(),                        // 异常列表
                    treeMaker.Block(0, List.of(jcReturn)), // block
                    null                   // 默认方法
            );
            // setter
            // public void setName(nameType name) {this.name = name;}
            String setterMethodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
            // 这里只是生成了this.name = name表达式
            JCTree.JCAssign assign = treeMaker.Assign(thisName, treeMaker.Ident(names.fromString(name)));
            // 生成一条语句 this.name = name;
            JCTree.JCExpressionStatement assignStat = treeMaker.Exec(assign);
            JCTree.JCMethodDecl setterMethodDecl = treeMaker.MethodDef(
                    treeMaker.Modifiers(Flags.PUBLIC),     // 访问标识
                    names.fromString(setterMethodName),    // 方法名
                    treeMaker.TypeIdent(TypeTag.VOID),                     // 返回类型
                    List.nil(),                    // 泛型形参列表
                    List.of(treeMaker.VarDef(
                            treeMaker.Modifiers(Flags.PARAMETER),   // 普通参数
                            variableDecl.name,
                            varType,
                            null   // 初始化为空,方法入参时为空即可
                            )
                    ), // 参数列表
                    List.nil(), // 异常列表
                    treeMaker.Block(0, List.of(assignStat)), // 方法体
                    null //默认方法
            );

解决TreeMaker AssertionError: Value of x -1_你倒是跑啊的博客-CSDN博客

TreeMaker  -> JCTree -> Tree ,接下来的一系列就是应用了

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐