Перевод языка Antlr4 - отделение логики шаблона от класса посетителя?

Я смотрю на прагматический перевод огромного количества относительно простого кода TSQL в код Groovy. Есть ряд причин, конечно, но движущая причина - просто посмотреть, можно ли это сделать, и в процессе узнать о компиляторах / грамматиках / и т. Д.

Antlr4 кажется идеальным инструментом для решения этой проблемы (Java является плюсом).

Токенизация / анализ TSQL (с использованием файла грамматики) и чтение дерева с использованием сгенерированного Listener/Visitor довольно просты.

Я знаю, что мог бы просто создать строковое представление кода Groovy внутри моего унаследованного посетителя, но связывание соответствующих значений токенов Groovy с моим TSQLVisitor не кажется самым чистым решением.

Что будет считаться лучшей практикой здесь? и вообще для отображения одного языка на другой в Antlr4?

Вещи, которые я рассматриваю:

  1. Используя StringTemplate и определяя мой Groovy-код в файле STG (мой TSQLVisitor будет использовать эти шаблоны и возвращать полное строковое представление Groovy-кода).
  2. Переключитесь на 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();
    }
}
Другие вопросы по тегам