Я хочу создать переводчик компьютерного языка между двумя языками LANG1 и LANG2. Более конкретно, я хочу перевести код, написанный на LANG1, в исходный код на LANG2.
У меня есть грамматика BNF для LANG1 и LANG2.
LANG1 — это небольшой DSL, который я написал сам, и, по сути, «более простая» версия LANG2.
Я хочу иметь возможность генерировать операторы в LANG2 из входных операторов, написанных в LANG1.
Я нахожусь в процессе компиляции для LANG1, но я не знаю, что делать дальше (чтобы преобразовать операторы LANG1 в операторы LANG2).
Я понимаю следующие шаги:
1. BNF for my DSL (LANG1) DONE
2. Reverse engineered the BNF for LANG2 DONE
3. Learning how to generate a compiler for LANG1 TODO
4. Translate LANG1 statements to LANG2 statements ???
Какие шаги предпринимаются для генерации операторов LANG2 из операторов LANG1?
Моя кодовая база находится на C ++, поэтому я могу использовать Parser, сгенерированный либо на C, либо на C ++.
PS: я буду использовать ANTLR3 для генерации компилятора для LANG1
В самом общем случае вам нужно перевести каждый возможный раздел грамматики из LANG1 в нечто подходящее для LANG2, или вам нужно разобраться в простейших возможных примитивах обоих языков, таких как ассемблер или комбинаторы. Это немного отнимает много времени и не очень весело.
Однако, если грамматики эквивалентны или имеют много общего, вы можете просто разобраться с простым разбором в одном и том же дереве для обеих грамматик и иметь функции вывода, которые могут взять ваше стандартизированное дерево и преобразовать его обратно в LANG1 или Источник LANG2 (который в основном такой же, как и в общем случае, но требует гораздо более коротких путей).
РЕДАКТИРОВАТЬ: Так как я только что перечитал ваш вопрос, понял, что вы хотите переводить только одним способом, вам нужно только беспокоиться о том, чтобы форма дерева подходила для LANG1 и просто иметь функцию перевода для LANG2. Но я надеюсь, что мой пример полезен в любом случае.
Вот две разные грамматики ANTLR, которые производят один и тот же чрезвычайно простой AST:
Грамматика 1
Первый — это стандартный способ выражения сложения:
grammar simpleAdd;
options {output=AST;}
tokens {
PLUS = '+';
}
expression : addition EOF!;
addition : NUMBER (PLUS NUMBER)+ -> ^(PLUS NUMBER*);
NUMBER :'0'..'9'+;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n')+ { $channel = HIDDEN; } ;
Это примет два или более целых числа и создаст дерево с узлом PLUS и всеми числами в списке, которые будут добавлены вместе. Например.,
1 + 1 + 2 + 3 + 5
Грамматика 2
Вторая грамматика принимает менее элегантную форму:
grammar horribleAdd;
options {output=AST;}
tokens {
PLUS = '+';
PLUS_FUNC = 'plus';
COMMA = ',';
LEFT_PARENS ='(';
RIGHT_PARENS=')';
}
expression : addition EOF!;
addition : PLUS_FUNC LEFT_PARENS NUMBER (COMMA NUMBER)+ RIGHT_PARENS -> ^(PLUS NUMBER*);
NUMBER :'0'..'9'+;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n')+ { $channel = HIDDEN; } ;
В этой грамматике ожидаются числа, присвоенные функции (да, я знаю, что функции на самом деле не работают так, я просто стараюсь сделать пример как можно более ясным). Например.,
plus(1, 1, 2, 3, 5)
Он создает точно такое же дерево, что и первая грамматика (узел PLUS с числами, как у детей).
Теперь вам не нужно беспокоиться о том, с какого языка пришли ваши инструкции, вы можете выводить их в любой форме. Все, что вам нужно сделать, это написать функцию, которая может конвертировать этот AST обратно на язык по вашему выбору.
Других решений пока нет …