JAVA编译期一般被分为两大部分:编译前期 和 编译后期
编译早期是指把符合JLS的*.java的文件转变成符合JVMS的*.class文件的过程,这一过程由前端编译器完成(如Sun/Oracle的javac,Eclipse JDT中的增量编译器ECJ);
编译晚期则主要指JIT编译器(把字节码转变成机器码的过程)或AOT编译器(直接把*.java文件编译成本地代码)。
===============================================
Javac(java complier),是一种以自举方式实现的编译器,通过自举实现了从.java源文件到.class字节码文件的编译。但是确切来说,只是完成了java部分的编译(Bootstrap),
所以不能完全认为是完成了java自举编译,除非结合纯java编写的后端编译器/JVM。
Javac的编译过程大致如下图所示:
Javac的编译动作入口即为com.sun.tools.javac.main.JavaComplier类,以下是官方注释:
/**This class could be the main entry point for GJC when GJC is used as a
* component in a larger software system. It provides operations to
* construct a new compiler, and to run a new compiler on a set of source
* files.
* ......*/
整个前端编译任务(即上图Javac编译的三个步骤)主要通过该类中的compiler()和compiler2()实现。
具体有如下几个步骤:
准备过程:初始化插入式注解处理器;
initProcessAnnotations(processors);
一、词法分析、语法分析(Parse);
parseFiles(sourceFileObjects)
二、输入至符号(Enter);
enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects)))
三、注解处理(Annotation Processing);
processAnnotations(
enterTrees(stopIfError(CompileState.PARSE, parseFiles(sourceFileObjects))),
classnames);
四、进行属性标注与检查(Attr or Check)-数据流分析(Flow)-将泛型类型转换为裸类型(TransTypes)-解语法糖(Lower) 操作,并最终生成字节码文件(Gen)。
while (!todo.isEmpty())
generate(desugar(flow(attribute(todo.remove()))));
======================================================
详细说明各个步骤:
词法、语法分析:
这部分分为两个阶段。在词法分析阶段,通过com.sun.tools.javac.parser.Scanner类相关方法将源文件从字符流转化为Token集合。随后
由com.sun.tools.javac.parser.Parser类相关方法将Token序列构造JCTree类型的抽象语法树(AST),随后的操作将建立在此抽象语法树基础上。
其中com.sun.tools.javac.tree.JCTree类是com.sun.source.Tree类的实现。
输入至符号表:
符号表是由一组符号地址和符号信息构成的表格,可以是有序符号表、树状符号表、栈结构符号表等。
(未完待续)