首页 > 编程语言 >JAVAC编译流程

JAVAC编译流程

时间:2023-04-18 12:34:27浏览次数:48  
标签:... JAVAC javac sun 流程 编译 tools null com

目录

Javac编译过程

转变过程

入口

来源:com.sun.tools.javac.main.Main#compile(java.lang.String[])
  public int compile(String[] args) {
        // 创建上下文
        Context context = new Context();
        // 上下文中放入JavacFileManager
        JavacFileManager.preRegister(context); 
  			// 执行编译
        int result = compile(args, context);
        if (fileManager instanceof JavacFileManager) {
            ((JavacFileManager)fileManager).close();
        }
        return result;
    }

java源代码

在符号表填充阶段会对.java文件和.class文件进行查找和加载

com.sun.tools.javac.jvm.ClassReader#fillIn方法会调用

com.sun.tools.javac.file.JavacFileManager#list方法

来源:com.sun.tools.javac.file.JavacFileManager#list
  // loaction 是.java或者.class文件要查找的地址
  // packageName 是要查找文件的包名
  // kinds 指明为是.java文件还是.class文件
    public Iterable<JavaFileObject> list(Location location,
                                         String packageName,
                                         Set<JavaFileObject.Kind> kinds,
                                         boolean recurse)
        throws IOException
    {
  			// 文件迭代器
        Iterable<? extends File> path = getLocation(location);
        if (path == null)
            return List.nil();
        RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName);
        ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();

        for (File directory : path)
          	// 如果directory是目录,将目录下满足要求的文件追加到results列表中
          	// 如果directory是压缩包,最终创建ZipFileIndexArchive对象
          	// 压缩包中满足要求的文件并追加到results列表中
            listContainer(directory, subdirectory, kinds, recurse, results);
        return results.toList();  
}

词法分析 -> token流

com.sun.tools.javac.main.JavaCompiler#compile方法会间接调用com.sun.tools.javac.file.RegularFileObject#getCharContent方法,将java源文件转换了字符流。

获取字符流后,间接调用com.sun.tools.javac.main.JavaCompiler#parse方法,在while循环中将字符流转化为Name流映射为token流

com.sun.tools.javac.parser.Scanner

来源:com.sun.tools.javac.parser.Scanner#nextToken
public void nextToken() {
  	...
      while (true) {
                pos = bp;
                // switch语句会根据首个出现的字符来判断可能生成的Token对象
                switch (ch) { 
                    /*
			        1、特殊字符的处理
			        2、标识符的处理
			        3、数字的处理
			        4、分隔符的处理
			        5、斜线作为首字符的处理
			        6、单引号作为首字符的处理
			        7、双引号作为首字符的处理
			        8、默认的处理
                     */
                }
      }
    ...
}

语法分析 -> 抽象语法树

转换为Token流后,调用com.sun.tools.javac.tree.TreeMaker#TopLevel方法new 一个编译单元

来源:com.sun.tools.javac.tree.TreeMaker#TopLevel
    public JCCompilationUnit TopLevel(List<JCAnnotation> packageAnnotations,
    JCExpression pid,
    List<JCTree> defs) {
        ...
        JCCompilationUnit tree = new JCCompilationUnit(packageAnnotations, pid, defs, null, null, null, null);
        ...
        return tree;
    }

调用com.sun.tools.javac.comp.Enter#complete方法完成对符号的输入

来源:com.sun.tools.javac.comp.Enter#complete
    public void complete(List<JCCompilationUnit> trees, ClassSymbol c) {
        ...
        try {
          	// 将当前编译单元下所有的非本地类的类符号输入到对应owner类的符号表中
            classEnter(trees, null);

            if  (memberEnter.completionEnabled) {
                while (uncompleted.nonEmpty()) {
                    ClassSymbol clazz = uncompleted.next();
                    if (c == null || c == clazz || prevUncompleted == null)
                        // 完成类符号对象或包符号对象中的符号输入
                        clazz.complete();
                    ...
                }
                for (JCCompilationUnit tree : trees) {
                    if (tree.starImportScope.elems == null) {
                        ...
                        Env<AttrContext> topEnv = topLevelEnv(tree);
                        // 符号输入的第二阶段,类中的方法和成员变量进行符号输入
                        memberEnter.memberEnter(tree, topEnv);
                      	...
                    }
                }
            }
        } finally {
            ...
        }
    }

完成符号输入后,抽象语法树就构建完成

注意:在构建抽象语法树之后会处理插入式注解器,比如对lombok下相关注解器对java源代码的注解进行处理,生成对应的Java代码。生成代码后会重复符号输入的过程,并且返回新的JavaCompiler对象。

语义分析 -> 标注语法树

在com.sun.tools.javac.main.JavaCompiler#compile2中进行语义分析

来源:com.sun.tools.javac.main.JavaCompiler#compile2
    private void compile2() {
       ...
         generate(desugar(flow(attribute(todo))));
       ...
    }

Attr

com.sun.tools.javac.comp.Attr完成语义分析

  • 引用消除
  • 类型检查
  • 常量折叠

Flow

com.sun.tools.javac.comp.Flow完成语法检查

  • 变量赋值检查
  • 语句活跃性分析
  • 异常检查

Lower

com.sun.tools.javac.comp.Lower完成解语法糖

  • 可变长参数
  • 自动拆装箱
  • 条件编译
  • 增强for循环
  • 选择表达式
  • 枚举类
  • 泛型擦除
  • 内部类

代码生成 -> 字节码

  • 字节码指令生成
  • .class文件生成

标签:...,JAVAC,javac,sun,流程,编译,tools,null,com
From: https://www.cnblogs.com/ylc0x01/p/17329143.html

相关文章

  • 多通道振弦传感器无线采集仪工作模式与工作流程
    多通道振弦传感器无线采集仪工作模式与工作流程工作模式VS系列采发仪有两种工作模式,正常工作模式和参数设置模式。正常工作模式:也称“采发模式”,设备启动后自动完成传感器数据采集和发送工作,然后关机,等待下次定时时间。参数设置模式:可对设备工作参数进行访问的工作模式,仅在此......
  • shell 编写脚本的一些细节心得:流程控制
    流程控制用得最多的,无非也就是老三样,if、for、while。if其中if作为判断的函数使用,其中也是有很多小细节的。例如你要判断两个值是否相等的时候,有两种方式,代码如下:test=2if((${test}==2))thenecho"yes"fiif[${test}-eq2]thenecho"yes"fi其实两段代码的......
  • 4. python 流程控制
    一、顺序结构代码从上到下一行行执行,没有任何判断和跳转二、if分支结构python中流程控制须格外注意缩进,否则可能遇到各种奇奇怪怪的错误elseif的写法是elif注意if,else,elif后面加冒号:False、0、各种表示空的值(None,"",'',(),[],{}),在if判断时都为假;但注意"",''(一个空格)为真pas......
  • UNIX环境高级编程 第三版 源代码编译及使用
    UNIX环境高级编程(第3版)中的代码示例多次包含了一下头文件:#include"apue.h"搜索发现原来这个头文件是作者自定义的一个文件,并在官网提供了源代码供下载。下载之后解压该文件:tar-zxfsrc.3e.tar.gz进入文件夹并编译:cdapue.3emake等待结束,如果没有报错就成功了。(如......
  • graphhopper-ios 编译过程详解
    一、写在前面GraphHopper是一个快速且高效的路径规划引擎,它默认使用OpenStreetMap和GTFS数据,也可以导入其他数据源。它可以用作java库或独立的web服务器,去计算两个或多个点之间的线路的距离,时间,转弯指令和许多道路属性。除了“A-to-B”的路径规划能力之外,它还支持“snaptoro......
  • 每天打卡一小时 第八天 编译四部曲
     第一部曲自然语言 建立结构体存储身高性别定义结构体变量游历结构体选择输出 第二部曲流程图  第三部曲代码#include<iostream>#include<iomanip>usingnamespacestd;structREN{charsex;doublehight;};intmain(){i......
  • Java语言特点?编译与解释并存?
    Java语言特点:·面向对象(封装,继承,多态);·平台无关性(Java虚拟机实现平台无关性);·支持多线程(C++语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而Java语言却提供了多线程支持);·支持网络编程并且很方便(Java语言诞生本身就是为简化网络......
  • 百鸡百钱流程图与代码
    问题描述:我国古代数学家张丘建在《算经》一书中曾提出过著名的“百钱买百鸡”问题,该问题叙述如下:鸡翁一,值钱五;鸡母一,值钱三;鸡雏三,值钱一;百钱买百鸡,则翁、母、雏各几何?翻译过来,意思是公鸡一个五块钱,母鸡一个三块钱,小鸡三个一块钱,现在要用一百块钱买一百只鸡,问公鸡、母鸡、小鸡各......
  • c编译器五个没有参数的宏
    _LINE_十进制整数常量,表示当前源程序代码的行号_FILE_字符串常量,表示当前源文件名_DATE_字符串常员,表示当前日期,格式为:"mmmddyyyy"_TIMESTAMP字符串常量,表示最后一次修改源文件的日期和时间,格式为:DddMmmhh:mm:ssyyyy_STDC_如果编译器与ANSIC兼......
  • 自编译玩客云docker版OpenWrt R22.1.1(2022年2月13日更新)
    openwrt本地直接导入玩客云的步骤做了介绍,本篇适合于没有条件编译的朋友。2月13日更新内容:添加插件ttyd、netdata。拉取地址:dockerpulljyhking/onecloud:1.22月11日更新内容:增加s905系列docker版openwrt拉取地址:dockerpulljyhking/onecloud:s905_11月29日优化更新内容:1、简化......