在 ANTLR 中解析 DECAF 文法
Parsing DECAF grammar in ANTLR
我正在使用 Antlr 创建 DECAF 的解析器
语法 DECAF ;
//********* LEXER ******************
LETTER: ('a'..'z'|'A'..'Z') ;
DIGIT : '0'..'9' ;
ID : LETTER( LETTER | DIGIT)* ;
NUM: DIGIT(DIGIT)* ;
COMMENTS: '//' ~('\r' | '\n' )* -> channel(HIDDEN);
WS : [ \t\r\n\f | ' '| '\r' | '\n' | '\t']+ ->channel(HIDDEN);
CHAR: (LETTER|DIGIT|' '| '!' | '"' | '#' | '$' | '%' | '&' | '\'' | '(' | ')' | '*' | '+'
| ',' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | '\' | ']' | '^' | '_' | '`'| '{' | '|' | '}' | '~'
'\t'| '\n' | '\"' | '\'');
// ********** PARSER *****************
program : 'class' 'Program' '{' (declaration)* '}' ;
declaration: structDeclaration| varDeclaration | methodDeclaration ;
varDeclaration: varType ID ';' | varType ID '[' NUM ']' ';' ;
structDeclaration : 'struct' ID '{' (varDeclaration)* '}' ;
varType: 'int' | 'char' | 'boolean' | 'struct' ID | structDeclaration | 'void' ;
methodDeclaration : methodType ID '(' (parameter (',' parameter)*)* ')' block ;
methodType : 'int' | 'char' | 'boolean' | 'void' ;
parameter : parameterType ID | parameterType ID '[' ']' ;
parameterType: 'int' | 'char' | 'boolean' ;
block : '{' (varDeclaration)* (statement)* '}' ;
statement : 'if' '(' expression ')' block ( 'else' block )?
| 'while' '(' expression ')' block
|'return' expressionA ';'
| methodCall ';'
| block
| location '=' expression
| (expression)? ';' ;
expressionA: expression | ;
location : (ID|ID '[' expression ']') ('.' location)? ;
expression : location | methodCall | literal | expression op expression | '-' expression | '!' expression | '('expression')' ;
methodCall : ID '(' arg1 ')' ;
arg1 : arg2 | ;
arg2 : (arg) (',' arg)* ;
arg : expression;
op: arith_op | rel_op | eq_op | cond_op ;
arith_op : '+' | '-' | '*' | '/' | '%' ;
rel_op : '<' | '>' | '<=' | '>=' ;
eq_op : '==' | '!=' ;
cond_op : '&&' | '||' ;
literal : int_literal | char_literal | bool_literal ;
int_literal : NUM ;
char_literal : '\'' CHAR '\'' ;
bool_literal : 'true' | 'false' ;
当我给它输入时:
class Program {
void main(){
return 3+5 ;
}
}
分析树没有正确构建,因为它没有将 3+5 识别为表达式。是不是我的语法有什么问题导致了这个问题?
词法分析器规则从上到下匹配。当 2 个或多个词法分析器规则匹配相同数量的字符时,第一个定义的将 win。因此,单个数字整数将匹配为 DIGIT
而不是 NUM
.
尝试解析以下内容:
class Program {
void main(){
return 33 + 55 ;
}
}
这将被很好地解析。这是因为 33
和 55
被 匹配为 NUM
s,因为 NUM
现在可以匹配 2 个字符(DIGIT
只有1个,所以NUM
胜).
要修复它,请将 DIGIT
设为片段(以及 LETTER
):
fragment LETTER: ('a'..'z'|'A'..'Z') ;
fragment DIGIT : '0'..'9' ;
ID : LETTER( LETTER | DIGIT)* ;
NUM: DIGIT(DIGIT)* ;
词法分析器片段仅供其他词法分析器规则在内部使用,永远不会成为它们自己的标记。
其他几件事:您的 WS
规则匹配太多(它现在还匹配 |
和 '
),它应该是:
WS : [ \t\r\n\f]+ ->channel(HIDDEN);
并且您不应该在解析器中匹配字符文字:在词法分析器中执行:
CHAR : '\'' ( ~['\r\n\] | '\' ['\] ) '\'';
如果不这样做,将无法正确解析以下内容:
class Program {
void main(){
return '1';
}
}
因为 1
将被标记为 NUM
而不是 CHAR
。
我正在使用 Antlr 创建 DECAF 的解析器 语法 DECAF ;
//********* LEXER ******************
LETTER: ('a'..'z'|'A'..'Z') ;
DIGIT : '0'..'9' ;
ID : LETTER( LETTER | DIGIT)* ;
NUM: DIGIT(DIGIT)* ;
COMMENTS: '//' ~('\r' | '\n' )* -> channel(HIDDEN);
WS : [ \t\r\n\f | ' '| '\r' | '\n' | '\t']+ ->channel(HIDDEN);
CHAR: (LETTER|DIGIT|' '| '!' | '"' | '#' | '$' | '%' | '&' | '\'' | '(' | ')' | '*' | '+'
| ',' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | '\' | ']' | '^' | '_' | '`'| '{' | '|' | '}' | '~'
'\t'| '\n' | '\"' | '\'');
// ********** PARSER *****************
program : 'class' 'Program' '{' (declaration)* '}' ;
declaration: structDeclaration| varDeclaration | methodDeclaration ;
varDeclaration: varType ID ';' | varType ID '[' NUM ']' ';' ;
structDeclaration : 'struct' ID '{' (varDeclaration)* '}' ;
varType: 'int' | 'char' | 'boolean' | 'struct' ID | structDeclaration | 'void' ;
methodDeclaration : methodType ID '(' (parameter (',' parameter)*)* ')' block ;
methodType : 'int' | 'char' | 'boolean' | 'void' ;
parameter : parameterType ID | parameterType ID '[' ']' ;
parameterType: 'int' | 'char' | 'boolean' ;
block : '{' (varDeclaration)* (statement)* '}' ;
statement : 'if' '(' expression ')' block ( 'else' block )?
| 'while' '(' expression ')' block
|'return' expressionA ';'
| methodCall ';'
| block
| location '=' expression
| (expression)? ';' ;
expressionA: expression | ;
location : (ID|ID '[' expression ']') ('.' location)? ;
expression : location | methodCall | literal | expression op expression | '-' expression | '!' expression | '('expression')' ;
methodCall : ID '(' arg1 ')' ;
arg1 : arg2 | ;
arg2 : (arg) (',' arg)* ;
arg : expression;
op: arith_op | rel_op | eq_op | cond_op ;
arith_op : '+' | '-' | '*' | '/' | '%' ;
rel_op : '<' | '>' | '<=' | '>=' ;
eq_op : '==' | '!=' ;
cond_op : '&&' | '||' ;
literal : int_literal | char_literal | bool_literal ;
int_literal : NUM ;
char_literal : '\'' CHAR '\'' ;
bool_literal : 'true' | 'false' ;
当我给它输入时:
class Program {
void main(){
return 3+5 ;
}
}
分析树没有正确构建,因为它没有将 3+5 识别为表达式。是不是我的语法有什么问题导致了这个问题?
词法分析器规则从上到下匹配。当 2 个或多个词法分析器规则匹配相同数量的字符时,第一个定义的将 win。因此,单个数字整数将匹配为 DIGIT
而不是 NUM
.
尝试解析以下内容:
class Program {
void main(){
return 33 + 55 ;
}
}
这将被很好地解析。这是因为 33
和 55
被 匹配为 NUM
s,因为 NUM
现在可以匹配 2 个字符(DIGIT
只有1个,所以NUM
胜).
要修复它,请将 DIGIT
设为片段(以及 LETTER
):
fragment LETTER: ('a'..'z'|'A'..'Z') ;
fragment DIGIT : '0'..'9' ;
ID : LETTER( LETTER | DIGIT)* ;
NUM: DIGIT(DIGIT)* ;
词法分析器片段仅供其他词法分析器规则在内部使用,永远不会成为它们自己的标记。
其他几件事:您的 WS
规则匹配太多(它现在还匹配 |
和 '
),它应该是:
WS : [ \t\r\n\f]+ ->channel(HIDDEN);
并且您不应该在解析器中匹配字符文字:在词法分析器中执行:
CHAR : '\'' ( ~['\r\n\] | '\' ['\] ) '\'';
如果不这样做,将无法正确解析以下内容:
class Program {
void main(){
return '1';
}
}
因为 1
将被标记为 NUM
而不是 CHAR
。