#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
без разделяющей их точки с запятой.