5

我正在尝试将我的语法从 v3 转换为 v4 并且遇到了一些麻烦。

在 v3 中,我有这样的规则:

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 的方法是什么?

4

1 回答 1

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为空,但大多数情况下这会导致“缺少属性访问”错误。ANTLR4 做了一个特殊的例外,以便您可以检查它,它适用于在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); })* 
    ;
于 2013-08-07T21:00:32.640 回答