Как работает компиляция циклических зависимостей?

Я сделал пример на 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;}
}

Ok это плохое программирование, но если вы запустите javac XType он компилирует: компилирует даже MType, потому что XType в ней нуждается. Но... MType должен XType ... как это работает? Как компилятор знает, что такое происходит?

Я хотел бы знать, как компилятор (javac или любые другие компиляторы, которые вы знаете) управляет этой ситуацией, а не как ее избежать.

Я спрашиваю, потому что я пишу прекомпилятор, и я хотел бы управлять этой ситуацией.

2 ответов


вам нужно взять 2-пасс, или multi-pass подход:

языки, такие как Java, требуют многопроходного компилятора, так как определение x не требуется перед использованием:

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

существуют различные подходы, например, вы можете сделать следующее:

первый проход может искать все объявления переменных, второй-объявления методов и т. д. пока последний проход не использует всю эту информацию для скомпилируйте окончательный код.


первый файл не должен ничего знать о XType, кроме того, что это тип, и аналогично для MType во втором файле. Кроме того, в Java все объекты фактически имеют одинаковый размер (потому что все доступно через ссылки), поэтому размер объекта не нужен. Это не так на других языках - ваш код, как он стоит, не будет компилироваться на C++, например (синтаксис языка отдельно).