ANTLR: заголовок синтаксического анализа, сопровождаемый порцией двоичных данных с неизвестной длиной

Там в потоке данных два пакета. Каждый имеет заголовок, за которым следуют некоторые двоичные данные с неизвестной длиной, пока не будет найден другой заголовок или не будет достигнут EOF. Вот данные: HDR12HDR345 HDR - маркер12 заголовка, а 345 - двоичные данные.

А вот моя текущая неправильная грамматика:

grammar TEST;

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

Первый токен заголовка распознан, но токен данных слишком длинный и использует следующий заголовок и данные.

После трех дней поиска решения я не нашел ни одного, который бы соответствовал аспектам "двоичных данных" и "неизвестной длины". Но все же я думаю, что это должен быть какой-то общий сценарий разбора. ANTLR не так прост, как кажется на первый взгляд:(

Спасибо за любую помощь или предложения.

1 ответ

Без чего-либо непосредственно размещенного после .*, ANTLR будет потреблять как можно больше (до EOF). Итак, правило:

DATA : .*;

должно быть изменено (должно быть что-то после .*).

Кроме того, каждое правило лексера должно как минимум соответствовать одному символу. Но твой STREAM Правило может потенциально соответствовать пустой строке, в результате чего ваш лексер создает бесконечное количество пустых лексем.

Наконец, ANTLR предназначен для анализа текстового ввода, а не двоичных данных. См. Эти вопросы и ответы в списке рассылки ANTLR для получения дополнительной информации или выполните поиск в списке.

РЕДАКТИРОВАТЬ

Помимо размещения чего-то после .* Вы также можете выполнить немного "ручного" просмотра в лексере. Небольшая демонстрация того, как вы можете сказать 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...
Другие вопросы по тегам