java编译器源码解析-语法分析(1)

java语法解析器的核心类是com.sun.tools.javac.parser.JavacParser,令人惊讶的是java并没有使用antlr这样现成的的工具,而是选择手写。推测可能是为了性能的考虑吧。

接下来,让我们膜拜下大师的代码。

JavacParser.parseCompilationUnit()是java语法分析的入口方法。

parseCompilationUnit()的返回结果是一个JCTree.JCCompilationUnit,说的更直白一点就是一颗抽象语法树AST。

一、抽象语法树

借用一张图来说明JCTree以及子类的构成。

注意:每个Tree节点都有一个对应的sym属性

 

 

当然这还不是全部,但已经可以初步看出AST的基本构成。

 

 

它的子类包括我们耳熟能详的类声明、变量声明和其他if/while/for语句一样继承于JCStatement类。

方法声明节点、标识符声明节点、表达式节点都直接继承JCTree。

一元表达式、二元表达式等继承于表达式节点JCExpression类。

下面是JCTree及其主要子类的类图

 

 

既然是一棵树,那么肯定要进行变量,JCTree中专门实现了一个内部抽象类Visitor来支持对各个节点的访问。这就用到了访问者模式。

Visitor支持的方法如下:

 

 

二、语法分析

继续parseCompilationUnit()的分析,代码很多,但核心的方法是typeDeclaration(),顾名思义是做类型定义的解析。

进入新的方法,发现类型可以分为三种classOrInterfaceOrEnumDeclaration():

类解析、接口解析和枚举类解析。

分别对应三个方法,返回值都是JCClassDecl:

JCClassDecl classDeclaration()

JCClassDecl interfaceDeclaration()

JCClassDecl enumDeclaration()

相对而言,接口和枚举类要比类更简单,因此我们直接去查看类定义解析的内容。

类解析从解析类的泛型参数开始,具体内容在typeParametersOpt()中。

如果有extend或者implement就会去解析父类和接口。这里的逻辑不复杂,我们就不展开了。

类的body是比较复杂的,源码中专门写了一个方法classOrInterfaceBody()实现它。

classOrInterfaceBody具体实现classOrInterfaceBodyDeclaration方法中。

类的定义中可以继续定义类,所以

1.首先判断是不是内部类

2.然后如果是一个“{”,那就进行block的解析

3.最后就是变量的声明variableDeclaratorsRest()和方法的声明methodDeclaratorRest()

三、变量声明

变量声明的解析又分普通变量的声明和array的声明,是区分对待的。

不可避免的,变量声明的右边是一个表达式parseExpression()

四、方法定义

methodDeclaratorRest()

方法定义首先解析方法的参数params,之后今日block()方法。

block()由一系列blockStatements()组成。进而调用blockStatement(),blockStatement()有多种语句,比如:

parseStatement()解析一般的Statement

classOrInterfaceOrEnumDeclaration()解析类

variableDeclarators()解析变量声明

再加上解析表达式的parseExpression()。所有语法解析的核心逻辑就在这几个方法中

posted @ 2022-04-14 16:44  Mars.wang  阅读(1057)  评论(0编辑  收藏  举报