java中的编译-前端编译

7 篇文章 0 订阅

前端编译过程是指将源代码转换为目标代码的过程。在Java中,这个过程主要由Java编译器(javac)完成。

package jvm.clssis;
public class ClassPractice {
    public static void main(String[] args) {
        System.out.println("hello world");
    }
}

1. 词法分析

  • 输入:Java源代码(.java文件)
  • 输出:Token流
  • 任务:源代码分解成token(标记)的过程,其中token代表源代码中的最小语法单元。如关键字、标识符、字面量、操作符和分隔符等。

示例代码ClassPractice生成的tokens :packagejvm.clssis;publicclassClassPractice{publicstaticvoidmain(String[]args){System.out.println("hello world");}}

示例代码ClassPractice分解成token过程:

1,package jvm.clssis;

    • package(关键字)
    • jvm.clssis(标识符)
    • ;(分隔符)

2,public class ClassPractice {

    • public(关键字)
    • class(关键字)
    • ClassPractice(标识符)
    • {(分隔符)

3,public static void main(String[] args) {

    • public(关键字)
    • static(关键字)
    • void(关键字)
    • main(标识符)
    • ((分隔符)
    • String(标识符)
    • [(分隔符)
    • ](分隔符)
    • args(标识符)
    • )(分隔符)
    • {(分隔符)

4,System.out.println("hello world");

    • System(标识符)
    • .(分隔符)
    • out(标识符)
    • .(分隔符)
    • println(标识符)
    • ((分隔符)
    • "hello world"(字符串字面量)
    • )(分隔符)
    • ;(分隔符)

5, }

    • }(分隔符)

6,}

    • }(分隔符)

详细说明

  • 关键字:如packagepublicclassstaticvoid等。这些都是Java语言的保留字,具有特定的含义。
  • 标识符:如jvm.clssisClassPracticemainStringargsSystemoutprintln等。这些是用户定义的名字,用于类、方法、变量等的命名。
  • 分隔符:如{}()[];.等。这些符号用于分隔代码中的各个部分。
  • 字面量:如"hello world"。这是一个字符串字面量,表示具体的字符串值。

2. 语法分析

  • 输入:Token流
  • 输出:AST
  • 任务:将词法分析生成的一系列tokens按照语言的语法规则组织成一个抽象语法树(AST)。
    • 任务1-验证语法:检查源代码是否符合语言的语法规则例如,检查类和方法的声明是否正确,括号是否成对匹配,语句是否以分号结束等。并报告任何语法错误。
    • 任务2-构建AST: 将源代码转化为抽象语法树,提供一种结构化的表示,使得后续的编译步骤能够更容易地进行。AST去除了源代码中的某些冗余信息(如分号、括号等),并以更抽象的形式表示代码的语法结构

示例代码ClassPractice生成的AST过程

1. 输入tokens序列

从词法分析器接收tokens序列: packagejvm.clssis;publicclassClassPractice{publicstaticvoidmain(String[]args){System.out.println("hello world");}}

2. 创建根节点
  • 创建CompilationUnit节点。解析过程从CompilationUnit开始,它是整个源代码文件的根节点。
3. 解析包声明
  • 识别package关键字,接着是包名jvm.clssis,最后是分号;
  • 验证包声明的语法规则,创建PackageDeclaration节点,内容为jvm.clssis
  • PackageDeclaration节点附加到CompilationUnit节点。
4. 解析类声明
  • 识别并处理类的声明部分:public class ClassPractice { ... }
  • 验证类声明的语法规则,创建TypeDeclaration节点,内容为ClassPractice,修饰符为public
  • TypeDeclaration节点附加到CompilationUnit节点。
5. 解析类体
  • 识别类体的起始和结束符号 { ... }
  • 创建ClassBody节点。
  • ClassBody节点附加到TypeDeclaration节点。
6. 解析方法声明
  • 识别并处理方法的声明部分:public static void main ( String [ ] args ) { ... }
  • 验证方法声明的语法规则,创建MethodDeclaration节点,内容为main,修饰符为public static,返回类型为void
  • MethodDeclaration节点附加到ClassBody节点。
  • 创建Parameters节点,包含一个Parameter节点,内容为String[] args
  • Parameters节点附加到MethodDeclaration节点。
7. 解析方法体
  • 识别方法体的起始和结束符号 { ... }
  • 创建Block节点。
  • Block节点附加到MethodDeclaration节点。
  • 创建ExpressionStatement节点。
  • ExpressionStatement节点附加到Block节点。
  • 识别并处理方法体中的表达式语句 System.out.println("hello world");
  • 验证表达式语句的语法规则,创建MethodInvocation节点,内容为System.out.println
  • MethodInvocation节点附加到ExpressionStatement节点。
  • 创建Expression节点,内容为System.out
  • Expression节点附加到MethodInvocation节点。
  • 创建Arguments节点,包含一个Argument节点,内容为"hello world"
  • Arguments节点附加到MethodInvocation节点。
9. 创建根节点
  • 识别并处理右大括号,标记方法体和类体的结束。

示例代码ClassPractice生成的AST:

CompilationUnit
 ├── PackageDeclaration: jvm.clssis
 └── TypeDeclaration: ClassPractice
     ├── Modifiers: public
     ├── ClassBody
         └── MethodDeclaration: main
             ├── Modifiers: public static
             ├── ReturnType: void
             ├── MethodName: main
             ├── Parameters
             │   └── Parameter: String[] args
             └── Block
                 └── ExpressionStatement
                     └── MethodInvocation: System.out.println
                         ├── Expression: System.out
                         └── Arguments
                             └── Argument: "hello world"

3. 语义分析

  • 输入:抽象语法树(AST)
  • 输出:可能修改后的AST和符号表
  • 任务: 确保代码的语义正确,即不仅仅是结构上正确,还要在逻辑上、类型上正确。
    • 任务1:类型检查
      • 确保每个表达式的类型是合法的。例如,检查变量的类型是否兼容,方法调用的参数类型是否正确,赋值语句中的左右两边类型是否匹配等。例如,检查System.out.println("hello world");中,println方法是否存在并且接受一个字符串参数。
    • 任务2:作用域检查
      • 确保每个变量和方法在使用前已经声明,并且它们在正确的作用域中使用。例如,检查argsmain方法的参数列表中是否已经声明。
    • 任务3: 符号表管理
      • 构建和维护符号表,用于记录变量、方法、类等符号的信息(如名称、类型、作用域等)。
    • 任务4:标识符解析
      • 解析标识符的引用,确保每个标识符引用的是正确的定义。例如,解析System.out.println,确保Systemoutprintln分别指向标准库中的正确定义。
    • 任务5:检查语义规则
      • 检查更多语义规则,如访问控制(private、protected、public)、常量表达式、数组边界、可能的空指针引用等。

示例代码ClassPractice语义分析具体过程:

1. 构建符号表

创建并初始化符号表:

  • 将包名jvm.clssis加入符号表。
  • 将类ClassPractice加入符号表,记录其修饰符public
  • 将方法main加入符号表,记录其修饰符public static、返回类型void、参数列表String[] args
2. 作用域检查

检查标识符的作用域和声明:

  • 确认argsmain方法的参数列表中已经声明。
  • 确认Systemoutprintln在标准库中是合法的。

3. 类型检查

检查表达式和语句的类型:

  • 确认System.out的类型是PrintStream
  • 确认PrintStream类中存在println方法,并且它接受一个String类型的参数。
4. 标识符解析

解析标识符的引用,确保引用的是正确的定义:

  • System解析为java.lang.System类。
  • out解析为System类的out字段。
  • println解析为PrintStream类的println方法。

示例代码ClassPractice逐步语义分析过程

  1. package jvm.clssis;
  • 将包名jvm.clssis加入符号表。
  1. public class ClassPractice {
  • 将类名ClassPractice和修饰符public加入符号表。
  1. public static void main(String[] args) {
  • 将方法main及其修饰符public static、返回类型void、参数String[] args加入符号表。
  1. System.out.println("hello world");
  • 确认System类存在。
  • 确认System类的out字段存在且类型为PrintStream
  • 确认PrintStream类的println方法存在且接受一个String类型参数。

4. 中间代码生成

  • 输入:优化后的抽象语法树(AST)和符号表
  • 输出:中间代码
  • 任务:将AST转换为中间代码。

5. 中间代码优化

  • 输入:中间代码
  • 输出:优化后的中间代码
  • 任务:对中间代码进行优化,以提高目标代码的执行效率。优化可能包括消除无用的代码块、简化计算、重新排列代码等。

6. 目标代码生成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值