一个规则的多个字符模板

时间:2012-12-27 20:30:35

标签: antlr stringtemplate

成为ANTLR的新手我试图找出stringtemplates是如何工作的。我想基于一个非常简单的输入文件生成一段Java代码。由于其灵活的概念,我想使用(字符串)模板。 在Java中,通常必须生成成员声明,​​在其他地方初始化它们,并在其他地方使用它们。标识符名称应匹配,因此重复。这意味着在这里和那里需要很少的模板实例化。当然可以做到,但我似乎无法弄清楚,也许我错过了一些重要的“线索”?

我写了一个测试程序来研究这个概念。它需要一个简单的输入文件:

red = #FF0000
green = #00FF00
blue = #0000FF

并且应该产生类似以下输出的内容:

class MyColors {
  // Class members
  public java.awt.Color red;
  public java.awt.Color green;
  public java.awt.Color blue;

  // Constructor
  /* Question: How to access the right initializer value here?!? The values are not accessible at this level of the grammar*/
  public MyColors() {
    red = java.awt.Color.getColor("#FF0000");
    green = java.awt.Color.getColor("#00FF00");
    blue = java.awt.Color.getColor("#0000FF");
  }
};

...根据输入填写构造函数中变量和初始值设定项的名称。

我定义的语法如下:

grammar Test;

options {
    output=template;
}

colors: (a+=def)+ -> colorClassDef(name={$a});

def: ident '=' name -> colorDef(id={$ident.text}, name={$name.text});

ident: ID;

name: ID;

ID: ('a'..'z'|'A'..'Z'|'#'|'0'..'9')+;
WS: (' '|'\t'|'\r'|'\n')+ { skip(); };

模板定义如下:

group Test;

colorClassDef(name, id) ::= <<
class MyColors {
// Class members
<name:{ v | public java.awt.Color <v>;
}>
// Constructor
/* Question: How to access the initializer value here?!? */
public MyColors() {
<name:{ v | <v> = java.awt.Color.getColor("<id>");
}>
}
};
>>

/* How to return both id and name here seperately, as ID should go into the declaration and name should to into the init? */
colorDef(id, name) ::= <<
<id>
>>

任何人都可以建议我如何获得&lt; id&gt;和&lt; name&gt;超出规则'def'以便将它们包含在生成代码的右侧部分?

我发现了多个有关多个返回值的问题,例如Returning multiple values in ANTLR ruleantlr2 return multiple values,但没有一个包含字符模板。 我甚至买了“书”并按照我的方式编写了java字节码生成器,但没有找到我的答案。所有示例似乎都为一位输入生成一位输出。 (不过没有遗憾,这本书可以很好地读床; - )

有人能指出我错过了什么线索吗?解决这个问题最合适的方法是什么?一些示例代码和指向文档的指针将非常感激。

谢谢,

马腾

1 个答案:

答案 0 :(得分:1)

  

有人可以建议我如何进出规则'def'以便将它们包含在生成代码的右侧部分中吗?

这是一种直接以Java为中心的方法来获得您想要的东西。它并不像我想的那么优雅(我认为还有改进的余地),但我认为它解决了这个问题而没有太多的麻烦。我重命名了一些东西,但我认为我保持了你的方法的精神。

首先是模板。请注意,模板colorClassDef需要由语法确定的每一位信息:每个id,每个名称以及每个id与其对应名称之间的关联。这是从模板访问所有这些内容之一:

group Colors;

colorClassDef(ids, colors) ::= <<
class MyColors {
// Class members
<ids:{ id | public java.awt.Color <id>;
}>

// Constructor
public MyColors() {
<ids:{ id | <id> = java.awt.Color.getColor("<colors.(id)>");
}>
}
};
>>

这里我使用参数ids来存储所有传入ID和参数colors的列表,以存储将id(密钥)与名称(值)相关联的映射。对于构造函数部分,ST使用“间接属性查找”语法colors<colors.(id)>访问id的名称。colors。由于id是地图,因此colorClassDef用作地图的关键字,并将值写入模板。

模板colorDef处理所有内容,因此我删除了模板grammar Colors; options { output=template; } colors @init { java.util.LinkedList<String> ids = new java.util.LinkedList<String>(); java.util.HashMap<String, String> colors = new java.util.HashMap<String, String>(); } : (ident '=' name {ids.add($ident.text); colors.put($ident.text, $name.text);} )+ EOF -> colorClassDef(ids={ids}, colors={colors}) ; ident: ID; name: ID; ID: ('a'..'z'|'A'..'Z'|'#'|'0'..'9')+; WS: (' '|'\t'|'\r'|'\n')+ { skip(); };

第二,语法。它需要提供ID和颜色映射。这是一种方法:

colors

(为了保持语法相对简单,我将规则defcolors合并到ident。)

每个ids都会添加到列表name中,并且每个colors都会添加到映射ident作为相应public class ColorsTest { public static void main(String[] args) throws Exception { final String code = "red = #FF0000\ngreen = #00FF00\nblue = #0000FF"; process(code, "Colors.stg"); } private static void process(final String code, String templateResourceName) throws IOException, RecognitionException, Exception { CharStream input = new ANTLRStringStream(code); ColorsLexer lexer = new ColorsLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); ColorsParser parser = new ColorsParser(tokens); InputStream stream = ColorsTest.class.getResourceAsStream(templateResourceName); Reader reader = new InputStreamReader(stream); parser.setTemplateLib(new StringTemplateGroup(reader)); reader.close(); stream.close(); ColorsParser.colors_return result = parser.colors(); if (parser.getNumberOfSyntaxErrors() > 0){ throw new Exception("Syntax Errors encountered!"); } System.out.println(result.toString()); } } 键的值。然后关闭他们去模板。

这是测试作品的测试类:

red = #FF0000
green = #00FF00
blue = #0000FF

以下是基于您问题中输入的测试用例。

输入

class MyColors {
// Class members
public java.awt.Color red;
public java.awt.Color green;
public java.awt.Color blue;


// Constructor
public MyColors() {
red = java.awt.Color.getColor("#FF0000");
green = java.awt.Color.getColor("#00FF00");
blue = java.awt.Color.getColor("#0000FF");

}
};

输出

{{1}}