1

免责声明:上个月之前我从未使用过 Java,在此之前我也从未听说过 ANTLR 或 StringTemplate。在今年夏天的实习中,我得到了一个使用公司其他人从未使用过的工具的项目。每个人都“相信我”,我会“弄清楚”。因此,我的理解存在巨大差距。我喜欢这个项目,我学到了很多,所以不要把这当成抱怨。我只是想让它工作。

现在,我正在为旧的特定领域语言开发一个漂亮的打印机概念证明。我的 ANTLR 语法生成了很好的解析树,并且我能够输出简单的 StringTemplate 示例,就像介绍中的示例一样。

假设我的.stg文件中有一个简单的模板:

module(type, name, content) ::= "<type> MODULE <name>; <content>; END MODULE."

在 Java 中,我可以用来add()设置每个模板参数的值:

STGroup g = new STGroupFile("example.stg");
ST st = g.getInstanceOf("module");
st.add("type", "MAIN");
st.add("name", "test");
st.add("content", "abc");
System.out.println(st.render()); 
// prints "MAIN MODULE test; abc; END MODULE."

如何让 ANTLR 和 ST 读取文本文件并生成漂亮的打印输出?

MAIN MODULE test;
abc;
END MODULE.

应该成为

MAIN MODULE test; abc; END MODULE.

例如。(这不是我打算格式化所有输出的方式,别担心。它会打印得比这更漂亮。)

这个答案中,我了解到 ANTLR 4 会自动生成步行者。假设我的 ANTLR 语法正确/写得很好,我如何将 ANTLR 规则/标记与我的模板参数匹配以从输入文本文件生成输出?

如果我在某处的文档中错过了它,请告诉我。ANTLR 4 和 ST 4 的示例比以前的版本少得多。

4

1 回答 1

3

给定一个解析器规则

r : a b c ;

对于输入流中匹配规则的每个实例,生成的解析树将包含一个rContext带有子节点aContext, bContext,的节点,每个子节点都可能有更多的子节点。cContex

walk 将产生一系列监听器(或访问者)调用

enterR
enterA
....
exitA
enterB
....
exitB
enterC
....
exitC
exitR

每个调用都包含对解析树中实例上下文的引用,从而可以访问可以相对于干预子节点以前缀/后缀顺序传递给 ST 的实际值。

如果仅简单的前缀/后缀访问排序是不够的(或不希望的复杂),请使用一个或多个先前的分析树遍历来分析更复杂的节点并使用分析产品注释节点实例。在最终输出遍历中,参考分析产品以获取要传递给 ST 的值。

根据实际情况,对节点的分析通常会从其子节点中收集值,将批次传递给模板进行详细扩展、格式化等,并将结果存储为节点注释字符串等待输出中最终输出步行。

更新

要注释解析树节点,您可以使用ParseTreeProperty

在注释集变得不仅仅是“琐碎”的情况下,一个典型的选择是将节点类型特定的“装饰器”类实例与解析树节点/上下文实例关联起来,主要作为更好的数据容器。当然,节点类型特定的方法可以嵌入到它们相应的装饰器类中,以很好地分离关注点。

侦听器方法变成这样:

public void exitNodeB(NodeBContext ctx) {
    super.exitNodeB(ctx);
    NodeBDescriptor descriptor = (NodeBDescriptor) getDescriptor(ctx);
    if (analysisPhase) {
        descriptor.process(); // node-type specific analysis
    } else {
        descriptor.output();  // node-type specific output generation
    }
}

何时分析(进入、退出或两者)以及何时输出的细节将取决于特定的应用程序。实施以适合您的目的。

于 2015-07-23T18:40:56.023 回答