ANTLR: разбор заголовка, за которым следует фрагмент двоичных данных неизвестной длины - PullRequest
1 голос
/ 18 декабря 2011

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

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

grammar TEST;

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

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

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

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

1 Ответ

2 голосов
/ 18 декабря 2011

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

DATA : .*;

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

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

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

EDIT

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