Перевод языка Antlr4 - отделение логики шаблона от класса посетителя?
Я смотрю на прагматический перевод огромного количества относительно простого кода TSQL в код Groovy. Есть ряд причин, конечно, но движущая причина - просто посмотреть, можно ли это сделать, и в процессе узнать о компиляторах / грамматиках / и т. Д.
Antlr4 кажется идеальным инструментом для решения этой проблемы (Java является плюсом).
Токенизация / анализ TSQL (с использованием файла грамматики) и чтение дерева с использованием сгенерированного Listener/Visitor довольно просты.
Я знаю, что мог бы просто создать строковое представление кода Groovy внутри моего унаследованного посетителя, но связывание соответствующих значений токенов Groovy с моим TSQLVisitor не кажется самым чистым решением.
Что будет считаться лучшей практикой здесь? и вообще для отображения одного языка на другой в Antlr4?
Вещи, которые я рассматриваю:
- Используя StringTemplate и определяя мой Groovy-код в файле STG (мой TSQLVisitor будет использовать эти шаблоны и возвращать полное строковое представление Groovy-кода).
- Переключитесь на Antlr3, который поддерживает добавление логики StringTemplate непосредственно в файл грамматики.
1 ответ
Лучшие практики зависят от вашей цели. Если конверсия не должна вводить или сводить к минимуму любые дополнительные расходы, связанные с багажом, производительностью или техническим обслуживанием, тогда комментарии Иры контролируются.
Однако, если производительность и обслуживание не являются существенными проблемами, семантическое преобразование близко к 1:1, и у вас есть возможность добавить код поддержки времени выполнения в целевую среду, тогда становится возможным преобразование стиля Antlr4. Конечно, чем больше семантические различия между исходным и целевым языками, тем сложнее это становится - размер и сложность целевой библиотеки поддержки во время выполнения становится контрпродуктивной. И требуется только одно глубокое различие, чтобы определить требования к инструменту анализа, подобному Ире.
Предполагая, что была разработана адекватная библиотека Groovy, производство целевого кода сокращено до уровня, близкого к одному, запрашиваемого из процедур onEntry и onExit посетителя. Связь может быть несколько уменьшена путем абстрагирования рендеринга:
public class Render {
private static final String templateDir = "some/path/to/templates";
private STGroupFile blocksGroup;
private STGroupFile stmtGroup;
public Render() {
blocksGroup = new STGroupFile(Strings.concatAsClassPath(templateDir, "Blocks.stg"));
stmtGroup = new STGroupFile(Strings.concatAsClassPath(templateDir, "Statements.stg"));
}
public String gen(GenType type, String name) {
return gen(type, name, null);
}
/**
* type is an enum, identifying the group template
* name is the template name within the group
* varMap contains the named values to be passed to the template
*/
public String gen(GenType type, String name, Map<String, Object> varMap) {
Log.debug(this, name);
STGroupFile stf = null;
switch (type) {
case BLOCK:
stf = blocksGroup;
break;
case STMT:
stf = stmtGroup;
break;
}
ST st = stf.getInstanceOf(name);
if (varMap != null) {
for (String varName : varMap.keySet()) {
try {
st.add(varName, varMap.get(varName));
} catch (NullPointerException e) {
Log.error(this, "Error adding attribute: " + name + ":" + varName + " [" + e.getMessage() + "]");
}
}
}
return st.render();
}
}