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)
  • ローカル変数へのアクセス ( firstnext)

渡された変数と現在のルールの戻り値

渡された変数または現在のルールの戻り値にアクセスするときは、ルール定義で指定された名前の前に$.

  • layoutになる$layout
  • extractorになる$extractor

ローカル変数

returns明らかに、値を返すルールの句に従って名前が付けられた変数のメンバーを参照する必要があります。

たとえば、はルールfirstから結果を取得し、その戻り値に名前を付けます。つまり、次のことを意味します。exprexprext

  • firstになる$first.ext
  • nextになる$next.ext

$フォームを使用する場合

特定の変数を通常の Java フィールドとして参照できた v3 とは異なり、アクション内、ブロック内、変数を他のルールに渡すときなど、すべての場合でフォームを使用$する必要があります。@init@after

その他のトラップ

ローカル変数でオプションのトークンをキャプチャしている場合、その変数の属性を参照しているため、null ポインター例外が発生する可能性があります。

single_lname returns [String s]
    : p=LNAME_PREFIX? r=NAME { $p.text + toNameCase($r.text); }
;

が nullかどうかを確認する必要があり$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 に答える