Antlr MissingTokenException с простой грамматикой - PullRequest
1 голос
/ 02 марта 2012

У меня есть, как мне кажется, самая простая в мире грамматика, разбирающая пути файловой системы в форме dir1 / dir2 / filename (без начального /). Я вырезал некоторые детали, чтобы получить небольшой образец, показывающий проблему.

compilationUnit : relativePath;
identifier: IdentifierStart IdentifierPart*;    
relativePath : identifier (SLASH identifier)*;

SLASH   :   '/';
fragment IdentifierPart : 'a'..'z' | 'A'..'Z' | '_' | '0'..'9';
fragment IdentifierStart :  'a'..'z' | 'A'..'Z' | '_';    

если я передаю что-то вроде foo / aa / bb, я получаю исключение MissingTokenException. Он идентифицирует идентификатор, затем получает SLASH, и я получаю исключение MissingTokenException, висящее за идентификатором. Должно быть что-то фундаментальное, чего мне не хватает, но что?

1 Ответ

2 голосов
/ 02 марта 2012

Когда вы ставите ключевое слово fragment перед правилом лексера, вы не можете использовать это правило в правилах синтаксического анализатора.fragment может использоваться только внутри других правил лексера.Такие правила никогда не становятся токенами сами по себе, их можно использовать только как часть других токенов (других правил лексера).

Другими словами: удалите эти ключевые слова fragment из своей грамматики:

// parser rules
compilationUnit : relativePath;
relativePath    : identifier (SLASH identifier)*;
identifier      : IdentifierStart (IdentifierStart | Digit)*;    

// lexer rules
SLASH           : '/';
IdentifierStart : 'a'..'z' | 'A'..'Z' | '_';   
Digit           : '0'..'9';

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

// parser rule
compilationUnit : RelativePath;

// lexer rules
RelativePath    : Identifier ('/' Identifier)*;

fragment Identifier      : IdentifierStart IdentifierPart*;
fragment IdentifierPart  : 'a'..'z' | 'A'..'Z' | '_' | '0'..'9';
fragment IdentifierStart : 'a'..'z' | 'A'..'Z' | '_';    

Но тогда для анализатора никогда не будет создан токен Identifier, поскольку RelativePath соответствует одному Identifier.Для этого Identifier также должен быть fragment.Так что, возможно, это не то, что вы хотите.

...