ANTLR не распознает неправильное ключевое слово

#compiler-construction #antlr #antlr4 #compiler-optimization

#конструкция компилятора #antlr #antlr4 #оптимизация компилятора

Вопрос:

Я новичок в ANTLR. Я создаю компилятор для простого языка, но я не понимаю, почему, если я пишу неправильную клавиатуру, компилятор не выдает мне правильную ошибку.

Это моя грамматика:

             grammar Exercise;

            block  : '{' statement* '}';

            statement : assignment ';' 
                      | deletion ';' 
                      | print ';'
                      | declaration* ';'
                      | ifStat
                      | functionDecl
                      | exp
                      | block 
                      ;


            assignment : ID '=' exp;

            type  : 'int'
                  | 'boolean'
                  ;

            typeF  : 'void' ;


            declaration : type ID ;

            deletion : 'delete' ID;

            print  : 'print' exp;

            bool  : 'true' 
                  | 'false' 
                  ;

            exp : '(' exp ')'   
                | ID '(' expList? ')'
                | NUMBER 
                | bool
                | ID
                ;

            expIF   : ID EQ ID
                    | ID EQ bool
                    | ID GT ID
                    | ID LT ID
                    | ID NEQ ID 
                    | ID GTEQ ID
                    | ID LTEQ ID
                    | NOT ID
                    | ID 
                    ;

            ifStat  : 'if' '('expIF')' 'then' block ('else' block)? ;

            formalParameter  : declaration 
                             | rif declaration
                             ;

            rif : 'var';

            formalParameters    : formalParameter (',' formalParameter)* ; 

            functionDecl    : typeF ID LPAR formalParameters? RPAR block ; 

            expList : ID (',' ID )* ; 

            //IDs
            fragment CHAR  : 'a'..'z' |'A'..'Z' ;
            ID              : (CHAR)  | (DIGIT)  ;

            //Numbers
            fragment DIGIT : '0'..'9'; 
            NUMBER          : DIGIT ;

            OR : '||';
            AND : 'amp;amp;';
            NOT : '!';
            EQ : '==';
            NEQ : '!=';
            GT : '>';
            LT : '<';
            GTEQ : '>=';
            LTEQ : '<=';
            LPAR : '(';
            RPAR : ')';

            //ESCAPE SEQUENCES
            WS              : (' '|'t'|'n'|'r')-> skip;
            LINECOMMENTS  : '//' (~('n'|'r'))* -> skip;
            BLOCKCOMMENTS    : '/*'( ~('/'|'*')|'/'~'*'|'*'~'/'|BLOCKCOMMENTS)* '*/' -> skip;
            ERR: . -> channel(HIDDEN);
  

Здесь мой основной:

    public static void main(String[] args) {

   //create lexer

       ExerciseLexer lexer = new ExerciseLexer(new ANTLRInputStream("{ double a ;  boolean d; a = 4 ; {boolean d ; int a} int s;}") );

   //create parser
       CommonTokenStream tokens = new CommonTokenStream(lexer);
       ExerciseParser parser = new ExerciseParser(tokens);

   //tell the parser to build the AST
        parser.setBuildParseTree(true);

    //build custom visitor
        ExerciseVisitorImpl visitor = new ExerciseVisitorImpl();
        ParseTree pt = parser.block();
        visitor.visit(pt);  
  

Например, в этом случае я должен получить ошибку для ключевого слова «double», но я получаю «строка 1: 51 посторонний ввод ‘}’ ожидающий {‘boolean’, ‘;’, ‘int’}».
В чем проблема? Большое вам спасибо!

Комментарии:

1. Ваше ID правило выглядит неправильно. Оно соответствовало бы abc (всем буквам) или 123 (всем цифрам), но не abc123 . Также ваше NUMBER правило никогда ничему не будет соответствовать, потому что все, чему оно могло бы соответствовать, уже было бы сопоставлено ID .

2. Я бы также переосмыслил expIF правило. Как есть, вы можете сравнивать идентификаторы только друг с другом или ID == bool (но не ID != bool ) или использовать переменные непосредственно в качестве условий. Однако вы ничего не можете сравнить с числовыми константами (по крайней мере, ни разу NUMBER не сопоставив их правильно), вы не можете использовать вызовы функций в качестве условий или сравнивать любые другие вещи. Вы также не можете отменить условия, отличные от переменных. Я бы рекомендовал вместо этого разрешить произвольные выражения в качестве операндов операторов сравнения и объединить exp и expIf в единое правило (именно так это обычно делается).

3. Вы правы! Спасибо за ваши советы!

Ответ №1:

В вашей грамматике a statement — это exp an. Вы, вероятно, имели в виду exp ';' .

Как написано, a block является statement* и это может совпадать exp exp . Поскольку ID это exp и double и a оба являются ID s, double a распознается как два последовательных statement s.

Кроме того, ваша грамматика распознает declaration* ';' как statement . Поскольку declaration* включает в себя случай нулевых объявлений, то есть пустую строку, единственное, что ; соответствует этому результату. Я не знаю, действительно ли это то, чего вы хотите, но я сильно подозреваю, что вы не хотели сопоставлять два последовательных declaration без разделяющей их точки с запятой.