Antlr4语言翻译 - 将模板逻辑与访客类分开?

时间:2015-03-23 01:10:28

标签: antlr antlr4 stringtemplate

我正在努力将大量相对简单的TSQL代码实际转换为Groovy代码。有许多原因可以确定,但驱动的原因只是看它是否可以完成,并在此过程中了解编译器/语法/等等。

Antlr4似乎是解决这个问题的理想工具(Java是一个优势)。

对TSQL进行标记/解析(使用语法文件),并使用生成的Listener / Visitor读取树是非常简单的。

我知道我可以在我继承的访问者中创建Groovy代码的字符串表示,但是将匹配的Groovy令牌值与我的TSQLVisitor耦合似乎不是最干净的解决方案。

这里最好的做法是什么?并且通常用于在Antlr4中将一种语言映射到另一种语言?

我正在考虑的事情:

  1. 使用StringTemplate,并在STG文件中定义我的groovy代码 (我的TSQLVisitor将使用这些模板并返回完整的字符串 Groovy代码的表示)。
  2. 切换到Antlr3 支持将StringTemplate逻辑直接添加到语法文件中。

1 个答案:

答案 0 :(得分:3)

最佳做法取决于您的目标。如果转换不得引入或必须减少任何增加的技术行李或性能或维护费用,那么Ira的评论控制。

但是,如果性能和维护不是必不可少的问题,那么转换在语义上接近1:1,并且您能够在目标环境中添加运行时支持代码,然后就可以进行Antlr4样式转换。当然,源语言和目标语言之间的语义差异越大,它就越难以实现 - 目标运行时支持库的大小和复杂性会适得其反。并且,只需要一个根深蒂固的差异来推动像Ira开发的分析工具的需求。

假设已经开发了足够的Groovy lib,目标代码的生成将减少到访问者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();
    }
}