我正在尝试将我的语法从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<ValueExtractor> ext]
...
然而,由于v4中的规则返回这些自定义上下文对象而不是我明确告诉他们返回的内容,所以事情都搞砸了。 v4的方法是什么?
答案 0 :(得分:4)
这里有多种情况:
layout
)extractor
)first
,next
)访问传入变量或当前规则的返回值时,您只需要在规则定义中为$
添加前缀。
layout
变为$layout
extractor
变为$extractor
显然需要做的是引用变量的成员,该成员是根据返回值的规则的returns
子句命名的。
例如,first
正在从expr
规则中捕获结果,expr
将其返回值命名为ext
,这意味着:
first
变为$first.ext
next
变为$next.ext
$
表格与在v3中您可以将某些变量引用为常规Java字段的情况不同,在所有情况下,包括在操作中,$
和@init
中都需要使用@after
表单single_lname returns [String s]
: p=LNAME_PREFIX? r=NAME { $p.text + toNameCase($r.text); }
;
阻止,以及将变量传递给其他规则时。
如果您在局部变量中捕获可选标记,则可能会遇到空指针异常,因为您正在引用该变量的属性。
$p
您需要检查if
是否为空,但大多数时候这会导致“缺少属性访问”错误。 ANTLR4发出一个特殊异常,以便您可以在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); })*
;
规则变为:
{{1}}