ANTLR4中的规则变量



我试图将语法从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的方法是什么?

这里有多种情况:

  • 访问传入变量(layout
  • 访问当前规则的返回值(extractor
  • 访问局部变量(firstnext

传入变量和当前规则的返回值

访问传入变量或当前规则的返回值时,只需在规则定义中给定的名称前面加上$即可。

  • 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是否为null,但大多数情况下这会导致"缺少属性访问"错误。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); })* 
    ;

相关内容

  • 没有找到相关文章

最新更新