Как работает компиляция круговых зависимостей?
Я привел пример на 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 или любые другие компиляторы, которых вы знаете) управляет этой ситуацией, а не как его избежать.
Я спрашиваю, потому что я пишу прекомпилятор, и я хотел бы управлять этой ситуацией.
Ответы
Ответ 1
Вам нужно выполнить двухпроходный или multi-pass:
Языки, такие как Java, требуют многопроходного компилятора, так как определение x не требуется, прежде чем использовать:
public class Example {
public static void main(String [] args) {
assert(x==0);
x++;
assert(x==1);
}
static int x=0;
}
Существуют различные подходы, например, вы можете сделать следующее:
Первый проход может искать все объявления переменных, второй для объявлений методов и т.д., пока последний проход не использует всю эту информацию для компиляции окончательного кода.
Ответ 2
Первый файл не должен ничего знать о XType, кроме того, что это тип, и аналогично для MType во втором файле. Кроме того, на Java все объекты имеют одинаковый размер (потому что к нему обращаются все ссылки), поэтому размер объекта не требуется. Это не так на других языках - ваш код в его нынешнем виде не будет компилироваться в С++, например (синтаксис языка отдельно).