ANTLR различать коды групп DXF и целые числа

Я плохо знаком с ANTLR и пытаюсь написать парсер для файлов DXF с ANTLRv4. Файлы DXF используют так называемые групповые коды для указания типа следующих данных.

Пример отрывка из некоторого файла DXF:

  0
SECTION
  2
HEADER
  9
$ORTHOMODE
 70
     0
  9
  0
ENDSEC

Например, первый 0 означает, что в следующей строке следует строка. Групповой код 70 означает, что за ним последует 16-битное целое число, в примере это 0. Моя проблема сейчас, например, как можно различить групповой код 0 и целое число 0. В фрагменте примера кажется, что у целочисленных значений есть какой-то особый отступ, но я не смог найти ничего об этом в справочнике DXF.

Моя идея до сих пор заключалась в соблюдении грамматики ANTLR:

grammar SimpleDXF;

start       :   HEADER variable* ENDSEC ;
variable    :   varstart (groupcode NL value NL)+ ;
varstart    :   VAR ;
groupcode   :   INT ;
value       :   INT | ANYCHARSEQ ;

WS          :   [ \t]+ -> skip ;  
NL          :   '\r'? '\n' ;
HEADER      :   '0' NL 'SECTION' NL '2' NL 'HEADER' NL ;
ENDSEC      :   '0' NL 'ENDSEC' NL ;
VAR         :   '9' NL VARNAME NL ;
VARNAME     :   '$' LETTER (LETTER | DIGIT)* NL ;
INT         :   DIGIT+ NL ;
ANYCHARSEQ  :   ANYCHAR+ NL ;

fragment ANYCHAR    :   [\u0021-\u00FF] ;
fragment LETTER     :   [A-Za-z_] ;
fragment DIGIT      :   [0-9] ;

Но, очевидно, это не удается при попытке синтаксического анализа Integer 0, так как это рассматривается лексером как групповой код 0 из-за правила header.

Так что теперь я не знаю, как решить мою проблему. Любая помощь высоко ценится.

ИЗМЕНИТЬ

изменена грамматика ANTLR, чтобы включить больше правил лексера. Теперь проблема в том, что лексер полностью не работает. Первый входной символ - это токен INT вместо части токена HEADER, как я предполагал ... Причина в том, что удаление пробелов с помощью -> skip не будет работать, если оно находится внутри одного токена (см. Следующий пример):

Для ввода A B (пробел между двумя буквами) эта грамматика будет работать:

start   :   'A' 'B' ;
WS      :   [ \t\r\n]+ -> skip ;  

Но эта грамматика работать не будет:

start   :   AB ;
AB      :   'A' 'B' ;
WS      :   [ \t\r\n]+ -> skip ;  

person schauk11erd    schedule 22.05.2014    source источник


Ответы (2)


Я решил проблему, выполнив некоторую предварительную обработку, где каждый код группы и соответствующее значение находятся в одной строке. Предварительная обработка также удаляет начальные и конечные пробелы, как предложил @UweAllner. Пример входного файла из вопроса после предварительной обработки выглядит следующим образом:

0 SECTION
2 HEADER
9 $ORTHOMODE
70 0
0 ENDSEC

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

grammar SimpleDXF;

start           :   HEADER variable* ENDSEC ;
variable        :   varstart groupcodevalue+ ;
varstart        :   VAR ;
groupcodevalue  :   GROUPCODE value ;
value           :   (INT | ANYCHARSEQ) NL ;

NL              :   '\r'? '\n' ;
HEADER          :   '0 SECTION' NL '2 HEADER' NL ;
ENDSEC          :   '0 ENDSEC' NL ;
VAR             :   '9 ' VARNAME NL ;
GROUPCODE       :   INT ' ' ;
VARNAME         :   '$' LETTER (LETTER | DIGIT)* ;
INT             :   '-'? DIGIT+ ;
ANYCHARSEQ      :   ANYCHAR+ ;

fragment ANYCHAR:   [\u0021-\u00FF] ;
fragment LETTER :   [A-Za-z_] ;
fragment DIGIT  :   [0-9] ;
person schauk11erd    schedule 26.05.2014

Вам не хватает правила вроде

group: groupcode NL value;

В противном случае (как вы говорите) невозможно различить групповые коды и значения как таковые. Или, если за одним групповым кодом может следовать несколько значений:

group: groupcode (NL value)+;

И вы должны определить header и endsec как HEADER и ENDSEC, чтобы лексер мог различать «просто число» и «это начало последовательности». То же самое, возможно, для начала правила переменной (и всего, что состоит из фиксированного предложения).

РЕДАКТИРОВАТЬ: что-то вроде

HEADER      :   '0' WS* NL WS* 'SECTION' WS* NL WS* '2' WS* NL WS* 'HEADER' WS* NL ;

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

Чтобы немного исправить это, можно ли обрезать строки начальных и конечных пробелов, прежде чем они будут лексированы и проанализированы?

person Uwe Allner    schedule 22.05.2014
comment
У меня неявно это есть в правиле variable как субправиле: (groupcode NL value NL)+ Я также пытался заменить это субправило вашим предложением, но, как и ожидалось, я все равно получил тот же результат ... - person schauk11erd; 22.05.2014
comment
Приведенный вами пример действительно не поддается синтаксическому анализу по этому правилу; с групповым кодом 70 и 0 в качестве потребляемого значения остается 0 между этим и предполагаемым endsec, состоящим из 0 NL ENDSEC. Возможно ли более одного значения для каждого кода группы? - person Uwe Allner; 22.05.2014
comment
Для каждого кода группы возможно только одно значение, но переменная в разделе заголовка может иметь несколько параметров (код группы + значение). IMO проблема в том, что значение 0 находится в неправильном классе токена из-за правила header, где '0' ... заставляет лексер создавать токен для нулей. - person schauk11erd; 22.05.2014
comment
@Ibizarudi Я попробовал еще раз; увидеть ответ - person Uwe Allner; 26.05.2014
comment
Спасибо за ваш вклад. Я смог придумать решение с предварительной обработкой файла dxf благодаря вашему последнему редактированию. - person schauk11erd; 26.05.2014