【问题标题】:How does compiling circular dependencies work?编译循环依赖是如何工作的?
【发布时间】:2020-05-01 19:26:45
【问题描述】:

我已经用 Java 制作了示例,但我认为(未经测试)它适用于其他(所有?)语言。

您有 2 个文件。一、M.java

public class MType {
    XType x;
    MType() {x = null;}
}

第二,另一个文件(在同一目录下),XType.java

public class XType {
   MType m;
   public XType(MType m) {this.m = m;}
}

好吧,这是糟糕的编程,但如果你运行javac XType,它会编译:甚至MType 也会编译,因为XType 需要它。但是... MType 需要XType ... 它是如何工作的?编译器如何知道发生了什么?

我想知道编译器(javac 或您知道的任何其他编译器)如何管理这种情况,而不是如何避免这种情况。

我之所以问是因为我正在编写一个预编译器,并且我想处理这种情况。

【问题讨论】:

    标签: compiler-construction circular-dependency


    【解决方案1】:

    第一个文件不需要知道任何关于 XType 的信息,除了它是一个类型,第二个文件中的 MType 也是如此。此外,在 Java 中,所有对象实际上都具有相同的大小(因为所有内容都是通过引用访问的),因此不需要对象的大小。在其他语言中情况并非如此 - 例如,您的代码不会在 C++ 中编译(语言语法除外)。

    【讨论】:

    • 但是如果使用XType的方法呢?它必须知道 Xtype 的方法.. 不是吗?
    • 另外,我不确定您所说的“所有对象实际上大小相同”是什么意思。
    • 他指的是(例如)m 持有一个引用,并且所有引用都具有相同的大小。但这不是类型所需的唯一信息。还需要了解它的成员以及有关其超类型层次结构的大量信息。
    【解决方案2】:

    您需要采取 2-pass 或multi-pass 方法:

    像 Java 这样的语言需要一个多遍编译器,因为 x 的定义不需要在使用之前出现:

    public class Example {  
    public static void main(String [] args) {
        assert(x==0);           
        x++;
        assert(x==1);
    }
    static int x=0;
    }
    

    有多种方法,例如您可以执行以下操作:

    第一遍可以查找所有变量声明,第二遍查找方法声明等,直到最后一遍使用所有这些信息来编译最终代码。

    【讨论】:

    • 那么当它编译第二个文件时,编译器已经知道第一个是什么了?
    • @Fabio - 编译器的每一轮都会处理所有文件,收集下一轮所需的信息。
    猜你喜欢
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    • 2021-06-20
    • 2019-02-06
    相关资源
    最近更新 更多