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...