Проблема пробелов скрытого канала Antlr

У меня есть следующая грамматика Antlr:

grammar MyGrammar;

doc :   intro planet;
intro   :   'hi';
planet  :   'world';
MLCOMMENT 
    :   '/*' ( options {greedy=false;} : . )* '*/' { $channel = HIDDEN; };
WHITESPACE : ( 
    (' ' | '\t' | '\f')+
  |
    // handle newlines
    ( '\r\n'  // DOS/Windows
      | '\r'    // Macintosh
      | '\n'    // Unix
    )
    )
 { $channel = HIDDEN; };

В интерпретаторе ANTLRWorks 1.2.3 входы hi world, hi/**/world и hi /*A*/ world работают, как и ожидалось.

Однако ввод hiworld, который не должен работать, также принимается. Как сделать так, чтобы hiworld не сработало? Как заставить хотя бы один пробел (или комментарий) между «привет» и «мир»?

Обратите внимание, что я использовал только MLCOMMENT и WHITESPACE в этом примере для упрощения, но другие типы комментариев будут поддерживаться.


person luiscubal    schedule 18.07.2009    source источник
comment
Ну, я не знаю Antlr, но не будет ли наиболее очевидным doc: intro WHITESPACE planet или что-то в этом роде?   -  person schnaader    schedule 18.07.2009
comment
Поскольку канал WHITESPACE скрыт, возникает исключение MismatchedTokenException.   -  person luiscubal    schedule 18.07.2009
comment
Итак, вы не можете создать другую грамматику пробелов, которая не скрыта, и использовать ее?   -  person schnaader    schedule 18.07.2009
comment
Я могу, и я временно использую ваш метод, но почему тогда каждый учебник предлагает либо использовать СКРЫТЫЙ канал, либо skip()?   -  person luiscubal    schedule 18.07.2009


Ответы (2)


Вам необходимо создать токен общего идентификатора. Поскольку лексер создает максимально длинную лексему, он увидит ввод «hiworld» как одно слово, поскольку оно длиннее, чем «hi» или «world» сами по себе. Такое правило может выглядеть так:

ID : ('a'..'z' | 'A'..'Z')+;

Например, именно так синтаксические анализаторы для языков программирования отделяют ключевое слово «do» от «double» (тип ключевого слова, начинается с «do») или «done» (имя переменной).

person Sam Harwell    schedule 19.07.2009
comment
Этот ответ просто заставил так много вещей щелкнуть в моей голове. Благодарность - person Kenny Cason; 10.04.2013

Один из способов сделать строку hiworld ошибочной — использовать проверяющий семантический предикат, который гарантированно не сработает, следующим образом:

doc:      intro planet;
failure : 'hiworld' { false }?;
intro   : 'hi';
planet  : 'world';
// rest of grammar omitted
person Luke Woodward    schedule 18.07.2009
comment
Очень интересно, но если бы я добавил каждый возможный случай сбоя в более сложные грамматики, количество ситуаций сбоя росло бы экспоненциально. - person luiscubal; 18.07.2009