Невозможно интерпретировать вывод ANTLRWorks - PullRequest
0 голосов
/ 14 февраля 2012

Я использую следующую простую грамматику, чтобы понять ANTLR.

grammar Example;
options {
language=Java;
}

ID  : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

INT : '0'..'9'+
    ;
PLUS    :   '+';


ADDNUM  :   
    INT PLUS INT;

prog    :    ADDNUM;

Когда я пытаюсь запустить грамматику в ANTLRWorks для ввода 1+2, в консоли появляется следующая ошибка:

[16:54:08]... [16:54:08] проблема соответствия токена при 2: 0
NoViableAltException ('' @ [1: 1: токены: (ID | INT | PLUS | ADDNUM);])

Может кто-нибудь, пожалуйста, помогите мне понять, где я иду не так.

1 Ответ

1 голос
/ 14 февраля 2012

Возможно, вы не указали prog в качестве начального правила в ANTLRWorks.Если вы это сделаете, все будет хорошо.

Но вы действительно не должны создавать правило лексера, которое соответствует выражению, как вы делаете в ADDNUM: это должно быть правило синтаксического анализатора:

grammar Example;

prog    : addExpr EOF;
addExpr : INT PLUS INT;
ID      : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
INT     : '0'..'9'+;
PLUS    : '+';

ANTLR правила

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

правила лексера

Правило лексераобычно самая маленькая часть языка (строка, числа, идентификатор, комментарий и т. д.).Попытка создать правило лексера из ввода, например 1+2, вызывает проблемы, потому что:

  • , если вы когда-нибудь захотите извлечь что-то значимое из этого токена (например, оцените его), вам нужно разделить содержимоеэтого токена, потому что после создания 1 токена из него текст всего выражения «склеивается»;
  • вы сталкиваетесь с проблемами, если между ними есть пробел: 1 + 2.

Выражение 1+2 - это три токена: INT, PLUS и еще один INT.

правила фрагмента

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

ID    : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
FLOAT : '0'..'9'+ '.' '0'..'9'+; 
INT   : '0'..'9'+;

В приведенных выше правилах вы используете '0'..'9' четыре раза, так что вы можете поместить это в отдельное правило

ID    : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | DIGIT)*
FLOAT : DIGIT+ '.' DIGIT+; 
INT   : DIGIT+;
DIGIT : '0'..'9';

Но вы не хотите когда-либо создавать токен DIGIT: вам нужно, чтобы DIGIT использовался другими правилами лексера.В этом случае вы можете создать fragment правило:

ID    : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | DIGIT)*
FLOAT : DIGIT+ '.' DIGIT+; 
INT   : DIGIT+;
fragment DIGIT : '0'..'9';

. Это гарантирует, что никогда не будет токена DIGIT: и поэтому никогда не сможет использовать его в ваших правилах синтаксического анализа!

правила парсера

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


Также см .: ANTLR: есть простой пример?

...