JVM笔记6 前端编译

前端编译的过程

  • javac编译器由java语言写成
  • 过程
    • 准备过程: 初始化插入式注解处理器
    • 解析与填充符号表过程
      • 词法、 语法分析。 将源代码的字符流转变为标记集合, 构造出抽象语法树
      • 填充符号表。 产生符号地址和符号信息
    • 插入式注解处理器的注解处理过程: 插入式注解处理器的执行阶段
    • 分析与字节码生成过程
      • 标注检查。 对语法的静态信息进行检查
      • 数据流及控制流分析。 对程序动态运行过程进行检查。
      • 解语法糖。 将简化代码编写的语法糖还原为原有的形式。
      • 字节码生成。 将前面各个步骤所生成的信息转化成字节码。
  • 述3个处理过程里, 执行插入式注解时又可能会产生新的符号, 如果有新的符号产生, 就必须转回到之前的解析、 填充符号表的过程中重新处理这些新符号, 从总体来看, 三者之间的关系与交互顺序如下图
    在这里插入图片描述

解析与填充符号表

词法分析

词法分析是将源代码的字符流转变为标记(Token) 集合的过程,类比自然语言,标记对应的就是单词,所以叫词法分析。
关键字、 变量名、 字面量、 运算符都可以作为标记,
如“int a=b+2”这句代码中就包含了6个标记, 分别是int、 a、 =、 b、 +、 2

语法分析

语法分析是根据标记序列构造抽象语法树的过程, 类比自然语言,单词通过特地的组合形式(语法)表述含义。
抽象语法树(Abstract Syntax Tree, AST) 是一种用来描述程序代码语法结构的树形表示方式,
抽象语法树的每一个节点都代表着程序代码中的一个语法结构(Syntax Construct) ,
例如包、 类型、 修饰符、 运算符、 接口、 返回值甚至连代码注释等都可以是一种特定的语法结构。

填充符号表

生成符号表,一组符号地址和符号信息构成的数据结构。

注解处理器

JDK 5中, Java语言提供了对注解(Annotations) 的支持, 注解在设计上原本是与普通的Java代码一样, 都只在运行期间发挥作用的。
JDK 6中可以提前至编译期对代码中的特定注解进行处理。 我们可以把插入式注解处理器看作是一组编译器的插件, 当这些插件工作时, 允许读取、 修改、 添加抽象语法树中的任意元素。 如果这些插件在处理注解期间对语法树进行过修改, 编译器将回到解析及填充符号表的过程重新处理, 直到所有插入式注解处理器都没有再对语法树进行修改为止, 每一次循环过程称为一个轮次(Round) , 这也就对应着途中那个回环过程。
有了编译器注解处理的标准API后, 程序员的代码才有可能干涉编译器的行为, 由于语法树中的任意元素, 甚至包括代码注释都可以在插件中被访问到, 所以通过插入式注解处理器实现的插件在功能上有很大的发挥空间。 只要有足够的创意, 程序员能使用插入式注解处理器来实现许多原本只能在编码中由人工完成的事情。 譬如Java著名的编码效率工具Lombok, 它可以通过注解来实现自动产生getter/setter方法、 进行空置检查、 生成受查异常表、 产生equals()和hashCode()方法, 等等, 帮助开发人员消除Java的冗长代码, 这些都是依赖插入式注解处理器来实现的。

语义分析与字节码生成

经过语法分析之后, 得了程序代码的抽象语法树,抽象语法树能够表示一个结构正确的源程序, 但无法保证源程序的语义是符合逻辑的。
语义分析的主要任务则是对结构上正确的源程序进行上下文相关性质的检查, 譬如进行类型检查、 控制流检查、 数据流检查, 等等。

int a = 1;
boolean b = false;
char c = 2;
int d = a + c;
int d = b + c;
char d = a + c;

这段代码是可以构成抽象语法树,单是第5,第6行赋值代码语义是错误的。
我们编码时经常能在IDE中看到由红线标注的错误提示, 其中绝大部分都是来源于语义分析阶段的检查结果。

标注检查

标注检查步骤要检查的内容包括诸如变量使用前是否已被声明、 变量与赋值之间的数据类型是否能够匹配, 等等。
可以进行常量折叠,int i=1+2,1+2会被替换为3。

数据及控制流分析

它可以检查出诸如程序局部变量在使用前是否有赋值、 方法的每条路径是否都有返回值、 是否所有的受查异常都被正确处理了等问
题。

解语法糖

常见的语法糖包括了前面提到过的泛型 、 变长参数、 自动装箱拆箱, 等等

字节码生成

字节码生成阶段不仅仅是把前面各个步骤所生成的信息(语法树、 符号表) 转化成字节码指令写到磁盘中, 编译器还进行了少量的代码添加和转换工作。
实例构造器()方法和类构造器()方法就是在这个阶段被添加到语法树之中的。
这里的实例构造器并不等同于默认构造函数, 如果用户代码中没有提供任何构造函数, 那编译器将会添加一个没有参数的、 可访问性(public、 protected、 private或) 与当前类型一致的默认构造函数, 这个工作在填充符号表阶段中就已经完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值