在上文中,我们介绍了antlr4的2中遍历方式。下面,我们将对着2中遍历方式进行更为实际的例子,以确定他们各自的使用场合。
使用Parse-Tree Listeners
为了构建一个不混淆应用代码和语法的应用,关键点是解析器创建一个解析树然后遍历它,在遍历的过程中触发应用代码。我们可以使用我们最喜爱的技术或者antlr生成的树遍历机制来遍历。在这一小节中,我们将用antlr内置的ParseTreeWalker构建一个基于监听版本的属性文件应用。
//语法
grammar PropertyFile;
file : prop+ ;
prop : ID '=' STRING '\n' ;
ID : [a-z]+ ;
STRING : '"' .*? '"' ;
//文件
user="parrt"
machine="maniac"
public static class PropertyFileLoader extends PropertyFileBaseListener {
Map<String,String> props = new HashMap<String, String>();
public void exitProp(PropertyFileParser.PropContext ctx) {
String id = ctx.ID().getText(); // prop : ID '=' STRING '\n' ;
String value = ctx.STRING().getText();
props.put(id, value);
}
}
下面的类的依赖图,我就不解释了:
最后直接看结果吧,so easy:
public static void main(String[] args) throws Exception {
String inputFile = "E:\\code\\antlr\\antlr4-example\\part2\\listeners\\src\\main\\resources\\t.properties";
InputStream is = new FileInputStream(inputFile);
ANTLRInputStream input = new ANTLRInputStream(is);
PropertyFileLexer lexer = new PropertyFileLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
PropertyFileParser parser = new PropertyFileParser(tokens);
ParseTree tree = parser.file();
// create a standard ANTLR parse tree walker
ParseTreeWalker walker = new ParseTreeWalker();
// create listener then feed to walker
PropertyFileLoader loader = new PropertyFileLoader();
walker.walk(loader, tree); // walk parse tree
System.out.println(loader.props); // print results
//print {machine="maniac", user="parrt"}
}
使用Parse-Tree Visitors
当使用访问器时,我们仅仅是实现Visitor的代码即可。所以,无图无真相,无代码无…直接上代码了…
public static class PropertyFileVisitor extends
PropertyFileBaseVisitor<Void>
{
Map<String,String> props = new HashMap<String, String>();
public Void visitProp(PropertyFileParser.PropContext ctx) {
String id = ctx.ID().getText(); // prop : ID '=' STRING '\n' ;
String value = ctx.STRING().getText();
props.put(id, value);
return null; // Java says must return something even when Void
}
}
在这个例子中,prop节点没有子节点,所以,visitProp()方法不需要调用visit()方法,在下一节中我们将查看更通用一点的例子。