Как обращаться с токенами, когда один является подмножеством другого в Antlr? - PullRequest
1 голос
/ 02 января 2012

Я пытаюсь перенести существующую грамматику, разработанную для неизвестного инструмента, в Antlr. В грамматике есть сценарий использования, в котором есть два токена, таких как TEXT и TEXT_WITHOUT_A Некоторые правила в грамматике должны разрешать только текст без, но остальное в порядке с использованием текста.

Мои первоначальные попытки дали следующую грамматику, но проблема в том, что Antlr соответствует более конкретному правилу грамматики (txtwa), когда txt на самом деле является его расширенным набором. Если я введу что-то вроде «sometextwth», которое не содержит, Antlr не будет следовать правилу для текста (txt). Ожидаемый ввод - txt, а предоставленный ввод соответствует, но Antlr выясняет, что ввод соответствует txtwa, и даже если это не ожидается в этот момент в грамматике, решает не использовать txt.

    /*------------------------------------------------------------------
 * PARSER RULES
 *------------------------------------------------------------------*/
 expr   :   (  txt)* ;
 txt    :   TEXT ;
 txtwa  :   LETTERS_MINUS_A;
 term   :   factor ( (MULT | DIV) factor)*;
 factor :   NUMBER;

/*------------------------------------------------------------------
 * LEXER RULES
 *------------------------------------------------------------------*/


NUMBER              :   (DIGIT)+ ;

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

fragment LETTER_MINUS_A :   ('b'..'z' | 'B'..'Z');

fragment LETTER :   ('a'..'z' | 'A'..'Z');


fragment DIGIT      :   '0'..'9' ;   



LETTERS_MINUS_A 
    :   LETTER_MINUS_A (LETTER_MINUS_A)*;       

TEXT    :   LETTER (LETTER)* ;

Я бы хотел свободно использовать txt без необходимости делать (txt | txtwa), что, кстати, работает. Что мне здесь не хватает?

1 Ответ

1 голос
/ 02 января 2012

Вы должны понимать, что лексер не учитывает то, что нужно анализатору в конкретное время: он просто пытается создать токен, проходящий через правила лексера сверху вниз.

Поскольку вы определили LETTERS_MINUS_A до TEXT, вместо TEXT всегда будет создаваться LETTERS_MINUS_A, который будет содержать только 'a' и 'A'.

Это просто, как работает ANTLR.

Что вы можете сделать, это просто выбросить правило LETTERS_MINUS_A и сделать что-то вроде этого:

txt
 : TEXT 
 ;

txtwa 
 : TEXT 
   {
     if($TEXT.text.contains("a") || $TEXT.text.contains("A")) {
       throw new Exception("Eeek, I saw an `[aA]`!");
     }
   }
 ;
...