Вложенные скобки / символы '(' и ')' в грамматике / предупреждение ANTLRWorks: решение может соответствовать входным данным, таким как ... использование нескольких альтернатив - PullRequest
2 голосов
/ 31 июля 2011

Грамматика ниже парсинга ( left part = right part # comment ), # comment необязательна.

Два вопроса:

  1. Иногда предупреждение (ANTLRWorks 1.4.2): Решение может соответствовать вводу, такому как "{Int, Word}", используя несколько альтернатив: 1, 2 (ссылка id2)
    Но только иногда!
  2. Следующим расширением должно быть то, что комментарий (id2) может содержать символы '(' и ')'.

Грамматика:

grammar NestedBrackets1a1;

//==========================================================
// Lexer Rules
//==========================================================

Int
  :  Digit+
  ;

fragment Digit
  :  '0'..'9'
  ;

Special
  : ( TCUnderscore | TCQuote )
  ;
TCListStart   : '(' ; 
TCListEnd     : ')' ;   
fragment TCUnderscore  : '_' ;
fragment TCQuote       : '"' ;

// A word must start with a letter
Word
  :  ( 'a'..'z' | 'A'..'Z' | Special ) ('a'..'z' | 'A'..'Z' | Special | Digit )*
  ;

Space
  :  ( ' ' | '\t' | '\r' | '\n' ) { $channel = HIDDEN; }
  ;

//==========================================================
// Parser Rules
//==========================================================

assignment
  :  TCListStart id1 '=' id1 ( comment )? TCListEnd
  ;

id1
  :  Word+
  ;

comment
  : '#' ( id2 )*
  ;

id2
  :  ( Word | Int )+
  ;

1 Ответ

0 голосов
/ 31 июля 2011

ANTLRSстартер писал:

Иногда предупреждение (ANTLRWorks 1.4.2): решение может соответствовать вводу, например «{Int, Word}», используя несколько альтернатив: 1, 2 (ссылаясь на id2) Но только иногда!

Нет, введенная вами грамматика всегда выдаст это предупреждение. Возможно, вы не всегда замечаете это (ваш IDE-плагин или ANTLRWorks могут показывать это на вкладке, которую вы не открывали), но предупреждение есть. Убедитесь сами, создав лексер / парсер из командной строки:

java -cp antlr-3.4-complete.jar org.antlr.Tool NestedBrackets1a1.g

даст:

warning(200): NestedBrackets1a1.g:49:19:
Decision can match input such as "{Int, Word}" using multiple alternatives: 1, 2

As a result, alternative(s) 2 were disabled for that input

Это потому, что у вас есть * после ( id2 ) внутри вашего comment правила, а id2 также является повторением токенов: ( Word | Int )+. Допустим, ваш ввод "# foo bar" (#, за которым следуют два Word токена). ANTLR теперь может анализировать входные данные более чем одним способом: 2 токена "foo" и "bar" могут совпадать с ( id2 )*, где id2 соответствует одному токену Word за раз, но "foo" и "bar" также может совпадать с правилом id2.

Посмотрите на объединенные правила:

comment
  :  '#' ( ( Word | Int )+ )*
  ;

Видите, как вы повторяете повторение: ( ( ... )+ )*? Обычно это проблема, как и в вашем случае.

Решите эту проблему, заменив * на ?:

comment
  :  '#' ( id2 )?
  ;

id2
  :  ( Word | Int )+
  ;

или удалив +:

comment
  :  '#' ( id2 )*
  ;

id2
  :  ( Word | Int )
  ;

ANTLRSстартер писал:

Следующим расширением должно быть то, что комментарий (id2) может содержать символы '(' и ')'.

Это вызывает проблемы, поскольку за комментарием следует TCListEnd, то есть ). Я не рекомендую оставлять комментарии подходящими ).

EDIT

Обратите внимание, что комментарии обычно удаляются из исходного файла при маркировке входного источника. Таким образом, вам не нужно учитывать их в правилах парсера. Вы можете сделать это, "пропустив" эти токены в правиле лексера:

Comment
  :  '#' ~('\r' | '\n')* {skip();}
  ; 
...