JAVAC 编译原理
程序员文章站
2022-05-23 10:11:04
...
含义
- javac是一种编译器,将一种语言规范转化为另一种语言规范。javac将java源代码转化为JVM能够是被的一种语言。然后JVM将JVM的语言进行转化为机器能够识别的语言。
基本机构
- 如图所示,java源代码转化为java字节码,有四个过程:
- 词法分析
- 语法分析
- 语义分析
- 代码生成
- 词法分析是将源代码进行转化为Token流。
- 语法分析是将Token流转化为语法树。
- 语义分析是把一些难懂的,复杂的语法转化为简单的语法。
词法分析
- 词法分析是在java的tools.jar的JavaParser类中进行的。
- java自身有自己的规范,JavaParser通过java语言的规范进行解析对应的Token流。
- 例如,package com.hjh.cn.Myclass; 这个语句,词法分析会解析到package对应的方法中,通过找 “.”这个token进行遍历,最后以“;”结束 。这样就可以解析到package这个语句了。
语法分析
- 语法分析是将token流转化为更加具体的语法树。
语义分析
- 将语法分析解析成的语法树,在进行一些处理。
- 添加默认的构造方法(编译时候)
- 处理annotation
- 检查语义的合法性进行逻辑判断(com.sun.tools.comp.Attr)
- 变量类型是否匹配(com.sun.tools.comp.Check)
- 变量在使用前是否进行的初始化(com.sun.tools.comp.Resovle)
- 推导泛型的类型
- 字符串常量的合并 (com.sun.tools.comp.ConstFeild)
- 字符串常量的合并 比如说 String s = “hjh” + “lovelc”; 语义分析会给你优化成 String s = “hjhlovelc”;
- 数据流的分析(com.sun.tools.comp.Flow)
- 变量在使用是否被正确的赋值
- final 不能重新赋值
- 确定返回类型
- 异常错误的判断
- 所有的语句都要被执行到
- 进一步进行语义的分析(com.sun.tools.comp.Flow)
- 去掉无用的代码,只有永假的代码块(稍后分析)
- 变量的自动转换(拆装和加装)(稍后分析)
- 去除语法糖(稍后分析)
- 枚举类(其实并没有Enum 这个类,还是变成class继承了Enum这个类,变量变成final)
- 内部类 重新生成了一个class文件,然后持有外部类的句柄
去掉无用代码
- 去掉一些永真的代码
- 例子:
public static void main(String[] args) {
if (true) {
System.out.print(1);
} else {
System.out.print(2);
}
}
通过语义转化为:
public static void main(String[] args) {
{
System.out.print(1);
}
}
会去掉没有走的if分支,但是代码块还是进行保留。
拆装和加装
- 像int,Integer 这些内容都是需要加装拆装的,比如说 int 变成 Integer,是Integer.valueOf(),
- 例子
public static void main(String[] args) {
Integer i = 10;
int a = i;
}
转化为:
public static void main(String[] args) {
Integer i = Integer.valueOf(10);
int a = i.intValue();
}
去除语法糖
数组的转化
public static void main(String[] args) {
int [] arry = {1,2,3};
for (int i : arry) {
System.out.println(i);
}
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
for (Integer integer : list) {
System.out.println(integer);
}
}
转化为
public static void main(String[] args) {
int[] arr$ = arry;
int len$ = arr$.length;
for(int i$ =0; i$ < len$;i$++){
int i = arr$[i$];
{
System.out.println(i);
}
}
List list = new ArrayList();
list.add(Integer.valueOf(1));
list.add(Integer.valueOf(2));
for(Iterator iterator =list.iterator();iterator.hasNext();){
Integer i = (Integer) iterator.next();
{
System.out.println(i);
}
}
}
数组是重新生成了三个变量;
而List集合则是使用了迭代器的模式;
这个里面还有就是泛型的擦除 比如List<Integer>
变成了List
代码生成器
- 经过语义分析之后,语法树已经很完善了,javac在使用com.sun.tools.javac.jvm.Gen 进行遍历,生成最终的java字节码。