当我第一次尝试它时,我也面临着同样的困惑。这是一个非常明显的问题/问题,这使得它在教程中似乎没有明确和直接地解决,这使得它变得更加奇怪。
我发现摆脱困惑的方法是“returns”关键字:
token returns [TreeNode value]
: WORD { $value = new TreeNode( "word", $WORD.Text ); }
| INT { $value = new TreeNode( "int", $INT.Text ); }
;
WORD: ('a'..'z'|'A'..'Z')+;
INT : ('0'..'9')+;
TreeNode是我制作的一个类。棘手的地方是如何使用一系列(例如多个标记)来做到这一点。我想出的解决方案是递归:
expr returns [Accumulator value]
: a=token (WS+ b=expr)?
{
if( b != null )
{
$value = new Accumulator( "expr", a.value, b.value );
} else
{
$value = new Accumulator( "expr", a.value );
}
}
;
Accumulator 是我制作的一个类,它有两个不同的构造函数。一个构造函数封装单个令牌,另一个构造函数封装单个令牌和另一个 Accumulator 实例。请注意,规则本身是递归定义的,并且b.value
是一个累加器实例。为什么?因为 b 是一个 expr,并且 expr 的定义有returns [Accumulator value]
.
最终生成的树是一个累加器实例,它对所有令牌进行了分组。要实际使用该树,您需要进行一些设置,然后调用与解析内容的规则同名的方法:
Antlr.Runtime.ANTLRStringStream stringstream = new Antlr.Runtime.ANTLRStringStream( script );
TokenLexer lexer = new TokenLexer( stringstream );
Antlr.Runtime.CommonTokenStream tokenstream = new Antlr.Runtime.CommonTokenStream( lexer );
TokenParser parser = new TokenParser( tokenstream );
Accumulator grandtree = parser.expr().value;
希望这对遇到这种困惑的人有所帮助。
Update
由于系统允许您将目标语言代码散布在看似任意模式的位置,因此有一种更直接的方法可以将项目收集到列表中。成语是:
sequence returns [String k]
: (e=atom { $k = $e.k; })
(e=atom { $k += ", " + $e.k; })*
{ $k = "sequence (" + $k + ")"; } ;
一个字符串k
被初始化为第一个原子的 k 值,后续原子得到+=
to k
。片段$e.k
指的是atom returns [String k]
其他地方定义的规则。如果没有这样的规则,您可以使用text
财产(即$e.text
,哪些代币有。我不确定非代币是否具有此属性。如果没有,你可以这样做:
nonToken returns [String whatever] : e=TOKEN { $whatever = $e.text; } ;
然后您可以在更高的规则中使用它,例如
e=nonToken { System.out.println($e.whatever); }