ANTLR4中的规则变量
我正在尝试将我的语法从v3转换为v4并遇到一些麻烦。
在第3节我有这样的规则:
dataspec[DataLayout layout] returns [DataExtractor extractor] @init { DataExtractorBuilder builder = new DataExtractorBuilder(layout); } @after { extractor = builder.create(); } : first=expr { builder.addAll(first); } (COMMA next=expr { builder.addAll(next); })* ; expr returns [List ext] ...
但是,随着v4中的规则返回这些自定义上下文对象而不是我明确告诉他们返回的内容,事情都搞砸了。 什么是v4方式来做到这一点?
这里有多种情况:
- 访问传入的变量(
layout
) - 访问当前规则的返回值(
extractor
) - 访问局部变量(
first
,next
)
传入变量和当前规则的返回值
访问传入变量或当前规则的返回值时,您只需要在规则定义中给出的名称前缀为$
。
-
layout
变成了$layout
-
extractor
变成$extractor
局部变量
显然,需要做的是引用变量的成员,该成员是根据返回值的规则的returns
子句命名的。
例如, first
从expr
规则捕获结果, expr
命名其返回值ext
,表示:
-
first
变成$first.ext
-
next
变成$next.ext
何时使用$
表单
与在v3中您可以将某些变量引用为常规Java字段不同,在所有情况下都需要使用$
form,包括在操作中,在@init
和@after
块中,以及将变量传递给其他规则时。
其他陷阱
如果您在局部变量中捕获可选标记,则可能会遇到空指针exception,因为您正在引用该变量的属性。
single_lname returns [String s] : p=LNAME_PREFIX? r=NAME { $p.text + toNameCase($r.text); } ;
您需要检查$p
是否为空,但大多数情况下这会导致“缺少属性访问”错误。 ANTLR4发出一个特殊的exception,以便你可以检查它, 这只适用于在if
条件下使用(例如,重构这个以使用三元运算符仍然会导致错误)。
single_lname returns [String s] : p=LNAME_PREFIX? r=NAME { if ($p == null) { $s = toNameCase($r.text); } else { $s = $p.text + toNameCase($r.text); } } ;
更新的规则
总而言之, dataspec
规则变为:
dataspec[DataLayout layout] returns [DataExtractor extractor] @init { DataExtractorBuilder builder = new DataExtractorBuilder($layout); } @after { $extractor = builder.create(); } : first=expr { builder.addAll($first.ext); } (COMMA next=expr { builder.addAll($next.ext); })* ;