1

データ ストリームには 2 つのパケットがあります。それぞれのヘッダーには、別のヘッダーが見つかるか EOF に到達するまで、長さが不明なバイナリ データが続きます。データは次のとおりです。 HDR12HDR345 HDRはヘッダー マーカー 12で、345はバイナリ データです。

そして、ここに私の現在の間違った文法があります:

grammar TEST;

parse   :   STREAM EOF;
STREAM  :   PACKET*;
PACKET  :   HEADER DATA;
HEADER  :   'HDR';
DATA    :   .*;

最初のヘッダー トークンは認識されますが、データ トークンが長すぎて、次のヘッダーとデータを消費します。

解決策を3日間探した後、「バイナリデータ」と「不明な長さ」の両方の側面に一致するものは見つかりませんでした。しかし、これは解析の一般的なシナリオであるに違いないと思います。ANTLRは一見したように簡単ではありません:(

助けや提案をありがとう。

4

1 に答える 1

2

の直後に何も配置しない.*と、ANTLR は可能な限り (EOF まで) 消費します。したがって、ルールは次のとおりです。

DATA : .*;

変更する必要があります( の .*に何かがある必要があります)。

また、すべてのレクサー ルールは、少なくとも 1 つの文字に一致する必要があります。ただし、STREAMルールが空の文字列と一致する可能性があり、レクサーが無限の数の空の文字列トークンを作成する原因になります。

最後に、ANTLR はバイナリ データではなく、テキスト入力を解析することを目的としています。詳細については、ANTLR メーリング リストでこの Q&Aを参照するか、リストで検索してください

編集

の後に何かを配置するだけでなく.*、レクサーで「手動の」先読みを少し実行することもできます。レクサーが先に何かを「見る」まで文字を消費し続けるようにANTLRに指示する方法の小さなデモ("HDR"あなたの場合は):

grammar T;

@parser::members {
  public static void main(String[] args) throws Exception {
    String input = "HDR1 foo HDR2 bar \n\n baz HDR3HDR4 the end...";
    TLexer lexer = new TLexer(new ANTLRStringStream(input));
    TParser parser = new TParser(new CommonTokenStream(lexer));
    parser.parse();
  }
}

@lexer::members {
  private boolean hdrAhead() {
    return input.LA(1) == 'H' && 
           input.LA(2) == 'D' && 
           input.LA(3) == 'R';
  }
}

parse  : stream EOF;
stream : packet*; // parser rules _can_ match nothing
packet : HEADER DATA? {System.out.println("parsed :: " + $text.replaceAll("\\s+", ""));};
HEADER : 'HDR' '0'..'9'+;
DATA   : ({!hdrAhead()}?=> .)+;

上記のデモを実行すると:

java -cp antlr-3.3.jar org.antlr.Tool T.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar TParser

(Windows では、最後のコマンドは: java -cp .;antlr-3.3.jar TParser)

以下がコンソールに出力されます。

parsed :: HDR1foo
parsed :: HDR2barbaz
parsed :: HDR3
parsed :: HDR4theend...

入力文字列の場合:

HDR1 foo HDR2 bar 

baz HDR3HDR4 the end...
于 2011-12-18T19:01:30.637 に答える