Разбор строк, EOF как маркер конца оператора с ANTLR3 - PullRequest
4 голосов
/ 18 апреля 2011

Мой вопрос касается выполнения следующей грамматики в ANTLRWorks:

INT :('0'..'9')+;
SEMICOLON: ';';
NEWLINE: ('\r\n'|'\n'|'\r');
STMTEND: (SEMICOLON (NEWLINE)*|NEWLINE+);

statement
    : STMTEND
    | INT STMTEND
    ;

program: statement+;

Я получаю следующие результаты со следующим вводом (с программой в качестве правила запуска), независимо от того, какую новую строку NL (CR / LF / CRLF) или целое число я выберу:

"; NL " или "32; NL " анализирует без ошибок. ";" или "45;" (без перевода строки) приводит к исключению EarlyExitException. " NL " само по себе анализирует без ошибок. «456 NL » без точки с запятой приводит к исключению MismatchedTokenException.

Я хочу, чтобы оператор заканчивался символом новой строки, точкой с запятой или точкой с запятой, за которым следует символ новой строки, и я хочу, чтобы синтаксический анализатор съел как можно больше непрерывных символов новой строки при завершении, поэтому "; NL NL NL NL"- это всего лишь одно окончание, а не четыре или пять. Кроме того, я хотел бы, чтобы дело конца файла также было допустимым завершением, но я пока не знаю, как это сделать.

Так что же с этим не так, и как я могу сделать так, чтобы это хорошо заканчивалось в EOF? Я абсолютно новичок во всем анализе, ANTLR и EBNF, и я не нашел много материала, чтобы прочитать его на уровне где-то между простым примером калькулятора и ссылкой (у меня есть The Definitive ANTLR Reference, но это на самом деле - это справочник, с быстрым началом работы, который я пока не выполнил за пределами ANTLRWorks), поэтому любые предложения по чтению (кроме статьи ACM Вирта 1977 года) также были бы полезны. Спасибо!

1 Ответ

5 голосов
/ 18 апреля 2011

В случае ввода типа ";" или "45;" токен STMTEND никогда не будет создан.

";" создаст один токен: SEMICOLON, а "45;" выдаст: INT SEMICOLON.

То, что вы (вероятно) хотите, заключается в том, чтобы SEMICOLON и NEWLINE никогда не доходили до реальных токенов, но они всегда будут STMTEND.Вы можете сделать это, сделав их так называемыми «фрагментными» правилами:

program: statement+;

statement
 : STMTEND
 | INT STMTEND
 ;

INT     : '0'..'9'+;
STMTEND : SEMICOLON NEWLINE* | NEWLINE+;

fragment SEMICOLON : ';';
fragment NEWLINE   : '\r' '\n' | '\n' | '\r';

Правила фрагментов доступны только для других правил лексера, поэтому они никогда не окажутся в правилах синтаксического анализа (производства).Подчеркнем: приведенная выше грамматика создаст только токены INT или STMTEND.

...