Java — создание байт-кода JVM из реализации посетителя ANTLR 4

Я разрабатываю язык, который был реализован на Java с помощью ANTLR 4 и его шаблона посетителя. Теперь то, что я хотел бы сделать, это из реализованного кода в шаблоне посетителя сгенерировать байт-код JVM, который впоследствии может быть выполнен на виртуальной машине Java.

Так, например, учитывая следующий код (допустим, это язык, который я создаю):

int a = 1;
int b = 2;
int c = 3;
int d = 4;
if (a == b && c == d && a == d) {
    System.out.println("b = c");
} else {
    System.out.println("No!");
}

И у меня есть следующие функции, реализованные в шаблоне посетителя ANTLR 4, который обрабатывает различные инструкции моего языка (назначение, если, логическое и реляционное сравнение и т. д.):

// ...
void ifStatement(...) {
    // ...
}
// &&, ||, !
void logicalComparison(...) {
    // ...
}
// ==, !=, <=, >=, <, >
void relationalComparison(...) {
    // ...
}
//...

Проблема, с которой я сталкиваюсь, заключается в том, что когда я генерирую код для оператора if, мне нужен способ запомнить позицию сравнений, чтобы я мог вернуться после создания оператора else, чтобы разместить его позицию, чтобы прыжок был возможен если условия не выполняются.

Как лучше всего сгенерировать байт-код?


person Omari Celestine    schedule 02.04.2020    source источник
comment
ASM позволяет создавать и использовать объекты Label еще до того, как вы определите их фактическое местоположение с помощью visitLabel(…). Я не знаю подробностей, но API посетителя парсера должен поддерживать передачу контекстной информации родительской конструкции в подвыражение. Больше не должно быть необходимо.   -  person Holger    schedule 02.04.2020
comment
@Holger Проблема в том, как узнать, когда нужно перейти при обработке оператора логического сравнения (&&, ||, !, ...)? Мне нужен какой-то способ узнать, что я нахожусь внутри условия if, и каким-то образом сохранить метки для разных частей оператора if.   -  person Omari Celestine    schedule 09.04.2020
comment
Как уже было сказано, я не знаю, какие варианты ANTLR предлагает для передачи контекстной информации вверх или вниз, но они должны быть. Обычно компиляторы сначала создают представление, см. Абстрактное синтаксическое дерево, которое затем обрабатывается для создания код.   -  person Holger    schedule 09.04.2020


Ответы (1)


Вы можете использовать метки вместе с байт-кодом goto. В зависимости от того, какой инструмент генерации кода вы используете, это может быть что-то вроде

// Visit your condition so its result is pushed on the stack

// Create three new labels
int iflab   = ++labels; // Label to jump to if the condition was true
int elselab = ++labels; // Label to jump to if the condition was false
int donelab = ++labels; // Label to jump to once done executing either branches

generate("ifne label" + iflab);
generate("goto label" + elselab);

generate("label" + iflab + ":");
// visit the statement needing to be executed if the condition was true
generate("goto label" + donelab);

generate("label" + elselab + ":");
// visit the statement needing to be executed if the condition was false (if there is one)
generate("goto label" + donelab);

println("label" + donelab + ":");
// You are done with this statement, keep visiting the following statements.

Это неоптимизировано (создано слишком много ярлыков и переходов), но это должно быть понятно. Метод генерации просто записывает байт-код в файл, при написании которого я использовал Jasmin. Это должно быть похоже на использование ASM или любого другого инструмента байт-кода JVM.

person oranji    schedule 02.04.2020
comment
Проблема в том, как мне узнать, когда нужно перейти при обработке оператора логического сравнения (&&, ||,!,...)? Мне нужен какой-то способ узнать, что я нахожусь внутри условия if, и каким-то образом сохранить метки для разных частей оператора if. А что, если у меня есть вложенные операторы if? - person Omari Celestine; 09.04.2020