Внутренняя ошибка в грамматических правилах ANTLR4

Я написал свою собственную грамматику:

grammar SimpleCode;

program: 'class Program' '{' field_decl* method_decl* '}' ;

field_decl: type id_int_list ;

id_int: id
      | id '[' int_literal ']'
      ;

id_int_list: id_int
           | id_int (',' id_int)*
           ;

method_decl: (type | 'void') id id_type_list? block ;

id_type_list: (type id)
            | (type id) (','(type id))*
            ;

block: '{' var_decl* statement* '}' ;

var_decl: type id_list ;

id_list: id
       | id (',' id)*
       ;

type: 'int'
    | 'boolean'
    ;

statement: location assign_op expr ';'
         | method_call ';'
         | 'if' expr block 'else' block
         | 'for' id '=' expr ',' expr block
         | 'return' expr? ';'
         | 'break' ';'
         | 'continue' ';'
         | block
         ;

assign_op: '='
         | '+='
         | '-='
         ;

method_call: method_name expr_list?
           | 'callout' (string_literal (',' callout_arg_list)?)
           ;

expr_list: expr
         | expr (',' expr)*
         ;

callout_arg_list: callout_arg
                | callout_arg (',' callout_arg)*
                ;

method_name: id ;

location: id
        | id '[' expr ']'
        ;

expr: location
    | method_call
    | literal
    | expr bin_op expr
    | '-' expr
    | '!' expr
    | '(' expr ')'
    ;

callout_arg: expr
           | string_literal
           ;

bin_op: arith_op
      | rel_op
      | eq_op
      | cond_op
      ;

arith_op: '+'
        | '-'
        | '*'
        | '\\'
        | '%'
        ;

rel_op: '>'
      | '<'
      | '>='
      | '<='
      ;

eq_op: '=='
     | '!='
     ;

cond_op: '&&'
       | '||'
       ;

literal: int_literal
       | char_literal
       | bool_literal
       ;

id: alpha alpha_num* ;

alpha_num: alpha
         | digit
         ;

alpha: ( 'a'..'z' | 'A'..'Z' ) ;

digit: '0'..'9' ;

hex_digit: digit
         | 'a'..'f'
         | 'A'..'F'
         ;

int_literal: decimal_literal
           | hex_literal
           ;

decimal_literal: digit digit* ;

hex_literal: '0x' hex_digit hex_digit* ;

bool_literal: 'true'
            | 'false'
            ;

char_literal: '\'' char '\'' ;


string_literal: '\"' char* '\"' ;

WS: [ \t\r\n]+ ->skip ;

Я получил эту ошибку:

error(20): SimpleCode.g4:8:12: internal error: Rule int_literal undefined

Я не знаю, почему произошла эта ошибка. Int_literal был определен. Пожалуйста, объясните мне, почему произошла эта ошибка. Я не выяснил причину.

Спасибо за помощь.

1 ответ

Я просмотрел ваш код, и главная проблема в том, что вы не отделили правила Parser от правил Lexer. Это делается с помощью Capitals/Case чувствительности. Правила Lexer определены заглавными буквами. как только это было исправлено, ваша грамматика также имела еще 1 ошибку в том, что правило "char" было неопределенным.

вот исправленная версия:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

grammar SimpleCode;


program: 'class Program' '{' field_decl* method_decl* '}' ;

field_decl: type id_int_list ;

id_int: id
      | id '[' int_literal ']'
      ;

id_int_list: id_int
           | id_int (',' id_int)*
           ;

method_decl: (type | 'void') id id_type_list? block ;

id_type_list: (type id)
            | (type id) (','(type id))*
            ;

block: '{' var_decl* statement* '}' ;

var_decl: type id_list ;

id_list: id
       | id (',' id)*
       ;

type: 'int'
    | 'boolean'
    ;

statement: location assign_op expr ';'
         | method_call ';'
         | 'if' expr block 'else' block
         | 'for' id '=' expr ',' expr block
         | 'return' expr? ';'
         | 'break' ';'
         | 'continue' ';'
         | block
         ;

assign_op: '='
         | '+='
         | '-='
         ;

method_call: method_name expr_list?
           | 'callout' (string_literal (',' callout_arg_list)?)
           ;

expr_list: expr
         | expr (',' expr)*
         ;

callout_arg_list: callout_arg
                | callout_arg (',' callout_arg)*
                ;

method_name: id ;

location: id
        | id '[' expr ']'
        ;

expr: location
    | method_call
    | literal
    | expr bin_op expr
    | '-' expr
    | '!' expr
    | '(' expr ')'
    ;

callout_arg: expr
           | string_literal
           ;

bin_op: arith_op
      | rel_op
      | eq_op
      | cond_op
      ;

arith_op: '+'
        | '-'
        | '*'
        | '\\'
        | '%'
        ;

rel_op: '>'
      | '<'
      | '>='
      | '<='
      ;

eq_op: '=='
     | '!='
     ;

cond_op: '&&'
       | '||'
       ;

literal: int_literal
       | char_literal
       | bool_literal
       ;

id: ALPHA alpha_num* ;

alpha_num: ALPHA
         | DIGIT
         ;

ALPHA: ( 'a'..'z' | 'A'..'Z' ) ;

DIGIT: '0'..'9' ;

HEX_DIGIT: DIGIT
         | 'a'..'f'
         | 'A'..'F'
         ;

int_literal: decimal_literal
           | hex_literal
           ;

decimal_literal: DIGIT DIGIT* ;

hex_literal: '0x' HEX_DIGIT HEX_DIGIT* ;

bool_literal: 'true'
            | 'false'
            ;

char_literal: '\'' ALPHA '\'' ;


string_literal: '\"' ALPHA* '\"' ;

WS: [ \t\r\n]+ ->skip ;

Правила лексера используются для создания потоков токенов, а синтаксический анализатор - для определения семантики, что важно для объединенной грамматики.

На этом форуме есть хороший пост с довольно подробным описанием разницы и причин, по которым она нужна. Но кроме отсутствующего правила и отсутствия определения лексера все это было хорошо. Просто запомните INT: DIGIT+; // правила лексера в заглавных буквах.

Удачи с проектом!

Другие вопросы по тегам