我拿了一个虚拟语言,例如: 它只接受一个或多个'!'。 它的词法和规则是:
grammar Ns;
options {
output=AST;
ASTLabelType=CommonTree;
}
tokens {
NOTS;
}
@header {
package test;
}
@lexer::header {
package test;
}
ns : NOT+ EOF -> ^(NOTS NOT+);
NOT : '!';
好的,正如您所看到的,这代表了一种接受'!'的语言。要么 '!!!'或'!!!!!'......
我定义了一些有意义的类来构建AST:
public class Not {
public static final Not SINGLETON = new Not();
private Not() {
}
}
public class Ns {
private List<Not> nots;
public Ns(String nots) {
this.nots = new ArrayList<Not>();
for (int i = 0; i < nots.length(); i++) {
this.nots.add(Not.SINGLETON);
}
}
public String toString() {
String ret = "";
for (int i = 0; i < this.nots.size(); i++) {
ret += "!";
}
return ret;
}
}
这是树语法:
tree grammar NsTreeWalker;
options {
output = AST;
tokenVocab = Ns;
ASTLabelType = CommonTree;
}
@header {
package test;
}
ns returns [Ns ret] : ^(NOTS n=NOT+) {$ret = new Ns($n.text);};
以及包含一些示例数据的主类代码来测试生成的类:
public class Test {
public static void main(String[] args) throws Exception {
ANTLRInputStream input = new ANTLRInputStream(new ByteArrayInputStream("!!!".getBytes("utf-8")));
NsLexer lexer = new NsLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
NsParser parser = new NsParser(tokens);
CommonTree root = (CommonTree) parser.ns().getTree();
NsTreeWalker walker = new NsTreeWalker(new CommonTreeNodeStream(root));
try {
NsTreeWalker.ns_return r = walker.ns();
System.out.println(r.ret);
} catch (RecognitionException e) {
e.printStackTrace();
}
}
}
但打印的最终输出是'!',而不是期待的'!!!'。 这主要是因为这行代码:
ns returns [Ns ret] : ^(NOTS n=NOT+) {$ret = new Ns($n.text);};
上面的$ n只捕获了一个'!',我不知道如何捕获'!'的所有三个标记,换句话说,一个'!'列表$ n。 有人可以帮忙吗?谢谢!
答案 0 :(得分:4)
只有一个!
被打印的事实是因为你的规则:
ns returns [Ns ret]
: ^(NOTS n=NOT+) {$ret = new Ns($n.text);}
;
或多或少被翻译为:
Token n = null
LOOP
n = match NOT_token
END
return new Ns(n.text)
因此,n.text
将始终只是一个!
。
您需要做的是在列表中收集这些NOT
令牌。在ANTLR中,您可以使用+=
运算符而不是“单一标记”运算符=
创建标记列表。因此,请将ns
规则更改为:
ns returns [Ns ret]
: ^(NOTS n+=NOT+) {$ret = new Ns($n);}
;
被翻译为:
List n = null
LOOP
n.add(match NOT_token)
END
return new Ns(n)
请务必更改Ns
课程的构造函数,以取代List
:
public Ns(List nots) {
this.nots = new ArrayList<Not>();
for (Object o : nots) {
this.nots.add(Not.SINGLETON);
}
}
之后,您的测试类的输出将是:
!!!
祝你好运!