2013-05-31 2 views
4

У меня есть задача написать простой парсер-генератор, так что я писал ANTLR подобную грамматику и пытался разобрать простой файл как «Foo: бар;», но получил следующий вывод:ANTLR: нет реальной альтернативы ошибки

[@0,0:2='foo',<1>,1:0] 
[@1,3:3=':',<16>,1:3] 
[@2,4:6='bar',<1>,1:4] 
[@3,7:7=';',<18>,1:7] 
[@4,8:7='<EOF>',<-1>,1:8] 
line 1:0 no viable alternative at input 'foo' 
(rule foo : bar ;) 

Моя грамматика выглядит

grammar parsGen; 

gram : rule SEMICOLON (NEWLINE+ rule SEMICOLON)* ; 

rule : lRule | pRule ; 

lRule : LRULEID COLON lRule1 ; 
lRule1 : (((LRULEID | STRING | SET) | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE+)+ ; 

pRule : PRULEID COLON pRule1 ; 
pRule1 : (((LRULEID | PRULEID) | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE+)+ ; 

modificator : PLUS | ASTERISK | QUESTION ; 

ID : LRULEID | PRULEID ; 

LRULEID : UPPERLETTER (UPPERLETTER | LOWERLETTER | DIGIT)* ; 
PRULEID : LOWERLETTER (UPPERLETTER | LOWERLETTER | DIGIT)* ; 

STRING : ('\''.*?'\'') ; 
SET : '\''.*?'\'..\''.*?'\'' ; 

UPPERLETTER : [A-Z] ; 
LOWERLETTER : [a-z] ; 
DIGIT : [0-9] ; 

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

PLUS : '+' ; 
ASTERISK : '*' ; 
QUESTION : '?' ; 

LBRACE : '(' ; 
RBRACE : ')' ; 

SPACE : ' ' ; 

COLON : ':' ; 

PIPE : '|' ; 

SEMICOLON : ';' ; 

Итак, где я мог ошибиться? Я попытался найти везде (google, SO и т. Д.) Ошибку «нет жизнеспособной альтернативы», но мне это действительно не помогло.

ответ

15

ANTLR lexers полностью назначают однозначные типы токенов до того, как парсер когда-либо используется. Когда несколько типов токенов могут совпадать с токеном, первый из них появляется в грамматике - тот, который используется. Для вашей грамматики токен не может иметь тип ID и тип LRULEID в то же время. Так как вход foo соответствует обоим этим правилам лексера, первый из них отображается в грамматике, поэтому ваши токены: ID, COLON, ID, SEMICOLON, <EOF>.

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

Предисловие

Вы должны изменить ссылки пространства от SPACE+ к SPACE*, или правило будет требуют по крайней мере один символ пробела между bar и ;.

Вариант 1

Удалить правило ID лексического анализатора в целом.

Вариант 2

  1. Изменение ID правилу синтаксического анализатора, так что не пытается присвоить тип маркера ID для всех ваших идентификаторов.

    id : LRULEID | PRULEID; 
    
  2. Update pRule1 правило с помощью ссылки id.

    pRule1 : ((id | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE+)+ ; 
    

Unrelated Side Примечание

Вы грамматика может быть легче прочитать, если вы удалите крайнюю + закрытия внутри правил lRule и pRule1, и вместо того, чтобы добавить их к правило ссылается на себя, как это. Обратите внимание, что я изменил ссылки SPACE, как описано в предисловии.

lRule : LRULEID COLON lRule1+ ; 
lRule1 : ((LRULEID | STRING | SET) | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE* ; 

pRule : PRULEID COLON pRule1+ ; 
pRule1 : ((LRULEID | PRULEID) | LBRACE lRule1 PIPE lRule1 RBRACE) modificator? SPACE* ; 
+0

Спасибо, это работает! –

Смежные вопросы