8

我已经工作Java了 8 年多。

上周,在我公司的一次小型会议上,我的一位同事问我具体是如何Java Compiler工作的?我没有答案。

我试着解释一下,就像 Java 编译器一个接一个地获取语句并将它们转换为不针对任何对象的字节码,OS而是针对JVM.

即使是我,也没有人对这个答案感到满意。

现在的主要问题是 java 编译器究竟是如何工作的。即在编译文件的情况下,编译器将完成多少个步骤或阶段或阶段Java

究竟是什么Java's compiler架构?

如果Java classes同一个 .java 文件中有多个怎么办。那么将编译多少个类。

如果导入指向未编译的 Java 类怎么办?那么未编译的类是编译还是忽略呢?

我用谷歌搜索了半天多,所有人都提供了与我给同事的答案相同的答案。

但最后我在这里找到了一些有用的教程。

但是本教程也涵盖的内容不太深入,我无法想象该教程。

我仍然不满意,并渴望从您那里了解更多有关这方面的信息。

所以如果有人比我和上面的博客更了解一些东西,我可以通过使用它来可视化它的内部架构,Java Compiler请解释一下。

4

2 回答 2

8

一些基本步骤:

  1. parse:读取一组 *.java 源文件并将生成的标记序列映射到 AST(抽象语法树)-节点。
  2. enter:将定义的符号输入到符号表中。
  3. 处理注释:如果请求,处理在指定编译单元中找到的注释。
  4. 属性:属性语法树。此步骤包括名称解析、类型检查和常量折叠。
  5. flow:对上一步中的树执行数据流分析。这包括检查分配和可达性。
  6. desugar:重写 AST 并翻译掉一些语法糖。
  7. generate:生成源文件或类文件。

详细信息:

  1. Lex - 将源文件分解为单个单词或标记。
  2. Parse - 分析程序的短语结构。
  3. 语义动作 - 构建与每个短语对应的抽象语法树。
  4. 语义分析 - 确定每个短语的含义,将变量的使用与其定义联系起来,检查表达式的类型,请求翻译每个短语。
  5. 框架布局 - 以与机器相关的方式将变量、函数参数等放入激活记录(堆栈框架)中。
  6. 翻译 - 生成中间表示树(IR 树),一种不依赖于任何特定源语言或目标机器架构的符号。
  7. Canonicalize - 提升表达式的副作用,并清理条件分支,以方便下一阶段。
  8. 指令选择 - 将 IR 树节点分组为与目标机器指令的操作相对应的块。
  9. 控制流分析 - 将指令序列分析成控制流图,显示程序在执行时可能遵循的所有可能的控制流。

  10. 数据流分析 - 通过程序变量收集有关信息流的信息;例如,活跃度分析计算每个程序变量保存仍然需要的值(是活跃的)的位置。

  11. 寄存器分配 - 选择一个寄存器来保存程序使用的每个变量和临时值;不同时存在的变量可以共享同一个寄存器。

  12. 代码发射 - 用机器寄存器替换每条机器指令中的临时名称。

有一本好书:

Java 中的现代编译器实现

您可能想查看 javac 代码:

Javac 文档

OpenJDK 源代码

javac 黑客指南

不要恐慌!帮助 javac 新手在代码库中导航

JVM JLS

于 2015-09-25T09:42:55.407 回答
6

编译器有不同的步骤,但这里是最重要的:

词法分析 第一步是词法分析。基本上,这些步骤从 java 代码中提取标记(关键字、运算符、分隔符、注释、变量名......)

语法分析(parser) 第二步是语法分析。标记作为词法分析的输入,并组合形成表达式和指令。

优化和转换为字节码 最后一个宏步骤是将上一步转换为字节码。这里的代码可以修改为与原始代码等效但更高效。


注意:这个过程不仅与java有关,而且对所有编译器都是通用的。还有不生成中间字节码而是机器码的编译器(如 C 或 C++ 的编译器)。

通常有一些工具可以创建词法分析器和语法分析器,因为这些步骤在不同语言之间有许多共同点。

一个开源的词法分析器是flex 一个有用的句法分析器是yacc

两者都适用于 C 和 C++,它们是创建编译器最常用的语言(java 和其他语言),但其他编程语言也有类似的替代方案(用另一种语言创建编译器,不是另一种语言)。基本上,编写编译器的语言与编译器编译的语言无关。

于 2015-09-25T09:44:51.440 回答