Файл результатов из программного обеспечения Engineering состоит из множества страниц со строкой заголовка и несколькими строками данных на странице. Каждая строка заголовка состоит из:
- Символ '1' в первой позиции строки
- Некоторые алфавитные символы c символов (общие данные не анализируются)
- Строка 'PAGE' в позиции 122 строки
- Numeri c строка (номер страницы)
- NL
Пример такой строки заголовка: :
Программное обеспечение назначает следующие шесть символов после PAGE для нумерации страниц.
Парсер работает нормально, за исключением документов с более чем 99999 страниц, для которых программа выводит строки типа PAGE123456 без пробелов между PAGE и номером страницы (да, некоторые программы генерируют такой огромный объем данных).
Первая грамматика, которую я попробовал:
grammar F06Reader01;
readF06: dataBlock+ EOF;
dataBlock: pageLine row+;
pageLine: ONE_AT_FIRST_POS ALPNUM* PAGEATPOS ALPNUM NL;
row: ALPNUM* NL ;
PAGEATPOS: P_ATPOS A_ATPOS G_ATPOS E_ATPOS;
P_ATPOS : 'P' {getCharPositionInLine() == 119}?;
A_ATPOS : 'A' {getCharPositionInLine() == 120}?;
G_ATPOS : 'G' {getCharPositionInLine() == 121}?;
E_ATPOS : 'E' {getCharPositionInLine() == 122}?;
ONE_AT_FIRST_POS : '1' {getCharPositionInLine() == 1}?;
ALPNUM : (LETTER | DIGIT)+;
DIGIT: [0-9] ;
LETTER: ~[ \t\n\r\u0030-\u0039]; //everything but DIGITS, NL or WL
NL: '\r'? '\n';
WS : [ \t]+ ->skip;
Сгенерированные токены определяют PAGE231236 как ALPNUM, так как он находит его больше, чем PAGE.
После обнаружения этой проблемы я изменил файл g4, добавив лексический режим (PAGENUM), чтобы он активировался, когда лексер находит PAGE. но этого не произошло s и все же лексер создает токены ALPNUM.
Ниже приведен файл лексера:
lexer grammar ModeTest01Lexer;
PAGEATPOS: P_ATPOS A_ATPOS G_ATPOS E_ATPOS -> mode(PAGENUM);
P_ATPOS : 'P' {getCharPositionInLine() == 119}?;
A_ATPOS : 'A' {getCharPositionInLine() == 120}?;
G_ATPOS : 'G' {getCharPositionInLine() == 121}?;
E_ATPOS : 'E' {getCharPositionInLine() == 122}?;
ONE_AT_FIRST_POS : '1' {getCharPositionInLine() == 1}?;
ALPNUM : (LETTER | DIGIT)+;
DIGIT: [0-9] ;
LETTER: ~[ \t\n\r\u0030-\u0039]; //everything but DIGITS, NL or WL
NL: '\r'? '\n';
WS : [ \t]+ ->skip;
mode PAGENUM;
NUM : [0-9]+;
WS2 : [ \t]+ ->skip;
NL2: '\r'? '\n' -> mode(DEFAULT_MODE);
и анализатор:
parser grammar ModeTest01;
options { tokenVocab=ModeTest01Lexer; }
modeTest: dataBlock+ EOF;
dataBlock: pageLine row+;
pageLine: ONE_AT_FIRST_POS ALPNUM* PAGEATPOS NUM NL2;
row: ALPNUM* NL ;
Этот код по-прежнему использует PAGE123456 в качестве ALPNUM вместо перехода в режим PAGENUM после того, как PAGE найден, как показано в следующем примере и его AST:
1 MSC.NASTRAN JOB MARCH 12, 2020 MSC Nastran 11/27/13 PAGE992306
LC01 row
1 MSC.NASTRAN JOB MARCH 12, 2020 MSC Nastran 11/27/13 PAGE 2306
another row of data