Antlr4 不匹配输入
Antlr4 Mismatch input
首先,我已经阅读了以下类似问题的解决方案:q1 q3
我还是不明白为什么会收到以下消息:
line 1:0 missing 'PROGRAM' at 'PROGRAM'
当我尝试匹配以下内容时:
PROGRAM test
BEGIN
END
我的语法:
grammar Wengo;
program : PROGRAM id BEGIN pgm_body END ;
id : IDENTIFIER ;
pgm_body : decl func_declarations ;
decl : string_decl decl | var_decl decl | empty ;
string_decl : STRING id ASSIGN str SEMICOLON ;
str : STRINGLITERAL ;
var_decl : var_type id_list SEMICOLON ;
var_type : FLOAT | INT ;
any_type : var_type | VOID ;
id_list : id id_tail ;
id_tail : COMA id id_tail | empty ;
param_decl_list : param_decl param_decl_tail | empty ;
param_decl : var_type id ;
param_decl_tail : COMA param_decl param_decl_tail | empty ;
func_declarations : func_decl func_declarations | empty ;
func_decl : FUNCTION any_type id (param_decl_list) BEGIN func_body END ;
func_body : decl stmt_list ;
stmt_list : stmt stmt_list | empty ;
stmt : base_stmt | if_stmt | loop_stmt ;
base_stmt : assign_stmt | read_stmt | write_stmt | control_stmt ;
assign_stmt : assign_expr SEMICOLON ;
assign_expr : id ASSIGN expr ;
read_stmt : READ ( id_list )SEMICOLON ;
write_stmt : WRITE ( id_list )SEMICOLON ;
return_stmt : RETURN expr SEMICOLON ;
expr : expr_prefix factor ;
expr_prefix : expr_prefix factor addop | empty ;
factor : factor_prefix postfix_expr ;
factor_prefix : factor_prefix postfix_expr mulop | empty ;
postfix_expr : primary | call_expr ;
call_expr : id ( expr_list ) ;
expr_list : expr expr_list_tail | empty ;
expr_list_tail : COMA expr expr_list_tail | empty ;
primary : ( expr ) | id | INTLITERAL | FLOATLITERAL ;
addop : ADD | MIN ;
mulop : MUL | DIV ;
if_stmt : IF ( cond ) decl stmt_list else_part ENDIF ;
else_part : ELSE decl stmt_list | empty ;
cond : expr compop expr | TRUE | FALSE ;
compop : LESS | GREAT | EQUAL | NOTEQUAL | LESSEQ | GREATEQ ;
while_stmt : WHILE ( cond ) decl stmt_list ENDWHILE ;
control_stmt : return_stmt | CONTINUE SEMICOLON | BREAK SEMICOLON ;
loop_stmt : while_stmt | for_stmt ;
init_stmt : assign_expr | empty ;
incr_stmt : assign_expr | empty ;
for_stmt : FOR ( init_stmt SEMICOLON cond SEMICOLON incr_stmt ) decl stmt_list ENDFOR ;
COMMENT : '--' ~[\r\n]* -> skip ;
WS : [ \t\r\n]+ -> skip ;
NEWLINE : [ \n] ;
EMPTY : $ ;
KEYWORD : PROGRAM|BEGIN|END|FUNCTION|READ|WRITE|IF|ELSE|ENDIF|WHILE|ENDWHILE|RETURN|INT|VOID|STRING|FLOAT|TRUE|FALSE|FOR|ENDFOR|CONTINUE|BREAK ;
OPERATOR : ASSIGN|ADD|MIN|MUL|DIV|EQUAL|NOTEQUAL|LESS|GREAT|LBRACKET|RBRACKET|SEMICOLON|COMA|LESSEQ|GREATEQ ;
IDENTIFIER : [a-zA-Z][a-zA-Z0-9]* ;
INTLITERAL : [0-9]+ ;
FLOATLITERAL : [0-9]*'.'[0-9]+ ;
STRINGLITERAL : '"' (~[\r\n"] | '""')* '"' ;
PROGRAM : 'PROGRAM';
BEGIN : 'BEGIN';
END : 'END';
FUNCTION : 'FUNCTION';
READ : 'READ';
WRITE : 'WRITE';
IF : 'IF';
ELSE : 'ELSE';
ENDIF : 'ENDIF';
WHILE : 'WHILE';
ENDWHILE : 'ENDWHILE';
RETURN : 'RETURN';
INT : 'INT';
VOID : 'VOID';
STRING : 'STRING';
FLOAT : 'FLOAT' ;
TRUE : 'TRUE';
FALSE : 'FALSE';
FOR : 'FOR';
ENDFOR : 'ENDFOR';
CONTINUE : 'CONTINUE';
BREAK : 'BREAK';
ASSIGN : ':=';
ADD : '+';
MIN : '-';
MUL : '*';
DIV : '/';
EQUAL : '=';
NOTEQUAL : '!=';
LESS : '<';
GREAT : '>';
LBRACKET : '(';
RBRACKET : ')';
SEMICOLON : ';';
COMA : ',';
LESSEQ : '<=';
GREATEQ : '>=';
根据我的阅读,我认为 KEYWORD 和 PROGRAM 之间存在不匹配,但是完全删除 KEYWORD 并不能解决问题。
编辑:
删除 KEYWORD 会给出以下消息:
line 3:0 mismatched input 'END' expecting {'INT', 'STRING', 'FLOAT', '+'}
当 KEYWORD 可用时,这是我的 grun 输出:
[@0,0:6='PROGRAM',<KEYWORD>,1:0]
[@1,8:11='test',<IDENTIFIER>,1:8]
[@2,13:17='BEGIN',<KEYWORD>,2:0]
[@3,19:21='END',<KEYWORD>,3:0]
[@4,23:22='<EOF>',<EOF>,4:0]
line 1:0 mismatched input 'PROGRAM' expecting 'PROGRAM'
(program PROGRAM test BEGIN END)
这是删除 KEYWORD 后的输出:
[@0,0:6='PROGRAM',<'PROGRAM'>,1:0]
[@1,8:11='test',<IDENTIFIER>,1:8]
[@2,13:17='BEGIN',<'BEGIN'>,2:0]
[@3,19:21='END',<'END'>,3:0]
[@4,23:22='<EOF>',<EOF>,4:0]
line 3:0 mismatched input 'END' expecting {'INT', 'STRING', 'FLOAT', '+'}
(program PROGRAM (id test) BEGIN (pgm_body decl func_declarations) END)
有关 "missing 'PROGRAM'" 的错误已在您删除 KEYWORD
规则时解决(请注意,出于同样的原因,您还应删除 OPERATOR
规则)。
您现在遇到的错误与此完全无关。
您当前的问题与您没有显示的 empty
的定义有关。您说过您尝试了 EMPTY : $ ;
和 EMPTY : ^$ ;
(然后可能是 empty: EMPTY;
),但是其中 none 甚至可以编译,所以它们不会导致解析错误你发布了。无论哪种方式,EMPTY
令牌的概念都行不通。什么时候会生成这样的令牌?在所有其他令牌之间一次?在这种情况下,您会遇到很多 "unexpected EMPTY
" 错误。不,empty
规则的全部意义在于它应该在不消耗任何令牌的情况下成功。
为此,您只需定义 empty : ;
并完全删除 EMPTY
。或者,您也可以删除 empty
,并在当前使用 empty
的任何地方使用一个空的替代项(即 | ;
)。这两种方法都可以使您的代码正常工作,但还有更好的方法:
您正在使用 empty
作为基本上相当于列表的规则的基本情况。 ANTLR 提供重复运算符 *
(0 或更多)、+
(1 或更多)以及 ?
运算符来使事情成为可选的。这些允许您非递归地定义列表并且没有 empty
规则。例如 stmt_list
可以这样定义:
stmt_list : stmt* ;
和 id_list
像这样:
id_list : (id (',' id)*)? ;
顺便说一句,利用 ANTLR 4 支持直接左递归这一事实,您的语法可以大大简化,因此您可以摆脱所有不同的表达式规则,只使用一个左递归规则。
那会给你:
expr : primary
| id '(' expr_list ')'
| expr mulop expr
| expr addop expr
;
规则 expr_prefix
、factor
、factor_prefix
和 postfix_expr
和 call_expr
都可以删除。
首先,我已经阅读了以下类似问题的解决方案:q1
我还是不明白为什么会收到以下消息:
line 1:0 missing 'PROGRAM' at 'PROGRAM'
当我尝试匹配以下内容时:
PROGRAM test
BEGIN
END
我的语法:
grammar Wengo;
program : PROGRAM id BEGIN pgm_body END ;
id : IDENTIFIER ;
pgm_body : decl func_declarations ;
decl : string_decl decl | var_decl decl | empty ;
string_decl : STRING id ASSIGN str SEMICOLON ;
str : STRINGLITERAL ;
var_decl : var_type id_list SEMICOLON ;
var_type : FLOAT | INT ;
any_type : var_type | VOID ;
id_list : id id_tail ;
id_tail : COMA id id_tail | empty ;
param_decl_list : param_decl param_decl_tail | empty ;
param_decl : var_type id ;
param_decl_tail : COMA param_decl param_decl_tail | empty ;
func_declarations : func_decl func_declarations | empty ;
func_decl : FUNCTION any_type id (param_decl_list) BEGIN func_body END ;
func_body : decl stmt_list ;
stmt_list : stmt stmt_list | empty ;
stmt : base_stmt | if_stmt | loop_stmt ;
base_stmt : assign_stmt | read_stmt | write_stmt | control_stmt ;
assign_stmt : assign_expr SEMICOLON ;
assign_expr : id ASSIGN expr ;
read_stmt : READ ( id_list )SEMICOLON ;
write_stmt : WRITE ( id_list )SEMICOLON ;
return_stmt : RETURN expr SEMICOLON ;
expr : expr_prefix factor ;
expr_prefix : expr_prefix factor addop | empty ;
factor : factor_prefix postfix_expr ;
factor_prefix : factor_prefix postfix_expr mulop | empty ;
postfix_expr : primary | call_expr ;
call_expr : id ( expr_list ) ;
expr_list : expr expr_list_tail | empty ;
expr_list_tail : COMA expr expr_list_tail | empty ;
primary : ( expr ) | id | INTLITERAL | FLOATLITERAL ;
addop : ADD | MIN ;
mulop : MUL | DIV ;
if_stmt : IF ( cond ) decl stmt_list else_part ENDIF ;
else_part : ELSE decl stmt_list | empty ;
cond : expr compop expr | TRUE | FALSE ;
compop : LESS | GREAT | EQUAL | NOTEQUAL | LESSEQ | GREATEQ ;
while_stmt : WHILE ( cond ) decl stmt_list ENDWHILE ;
control_stmt : return_stmt | CONTINUE SEMICOLON | BREAK SEMICOLON ;
loop_stmt : while_stmt | for_stmt ;
init_stmt : assign_expr | empty ;
incr_stmt : assign_expr | empty ;
for_stmt : FOR ( init_stmt SEMICOLON cond SEMICOLON incr_stmt ) decl stmt_list ENDFOR ;
COMMENT : '--' ~[\r\n]* -> skip ;
WS : [ \t\r\n]+ -> skip ;
NEWLINE : [ \n] ;
EMPTY : $ ;
KEYWORD : PROGRAM|BEGIN|END|FUNCTION|READ|WRITE|IF|ELSE|ENDIF|WHILE|ENDWHILE|RETURN|INT|VOID|STRING|FLOAT|TRUE|FALSE|FOR|ENDFOR|CONTINUE|BREAK ;
OPERATOR : ASSIGN|ADD|MIN|MUL|DIV|EQUAL|NOTEQUAL|LESS|GREAT|LBRACKET|RBRACKET|SEMICOLON|COMA|LESSEQ|GREATEQ ;
IDENTIFIER : [a-zA-Z][a-zA-Z0-9]* ;
INTLITERAL : [0-9]+ ;
FLOATLITERAL : [0-9]*'.'[0-9]+ ;
STRINGLITERAL : '"' (~[\r\n"] | '""')* '"' ;
PROGRAM : 'PROGRAM';
BEGIN : 'BEGIN';
END : 'END';
FUNCTION : 'FUNCTION';
READ : 'READ';
WRITE : 'WRITE';
IF : 'IF';
ELSE : 'ELSE';
ENDIF : 'ENDIF';
WHILE : 'WHILE';
ENDWHILE : 'ENDWHILE';
RETURN : 'RETURN';
INT : 'INT';
VOID : 'VOID';
STRING : 'STRING';
FLOAT : 'FLOAT' ;
TRUE : 'TRUE';
FALSE : 'FALSE';
FOR : 'FOR';
ENDFOR : 'ENDFOR';
CONTINUE : 'CONTINUE';
BREAK : 'BREAK';
ASSIGN : ':=';
ADD : '+';
MIN : '-';
MUL : '*';
DIV : '/';
EQUAL : '=';
NOTEQUAL : '!=';
LESS : '<';
GREAT : '>';
LBRACKET : '(';
RBRACKET : ')';
SEMICOLON : ';';
COMA : ',';
LESSEQ : '<=';
GREATEQ : '>=';
根据我的阅读,我认为 KEYWORD 和 PROGRAM 之间存在不匹配,但是完全删除 KEYWORD 并不能解决问题。
编辑: 删除 KEYWORD 会给出以下消息:
line 3:0 mismatched input 'END' expecting {'INT', 'STRING', 'FLOAT', '+'}
当 KEYWORD 可用时,这是我的 grun 输出:
[@0,0:6='PROGRAM',<KEYWORD>,1:0]
[@1,8:11='test',<IDENTIFIER>,1:8]
[@2,13:17='BEGIN',<KEYWORD>,2:0]
[@3,19:21='END',<KEYWORD>,3:0]
[@4,23:22='<EOF>',<EOF>,4:0]
line 1:0 mismatched input 'PROGRAM' expecting 'PROGRAM'
(program PROGRAM test BEGIN END)
这是删除 KEYWORD 后的输出:
[@0,0:6='PROGRAM',<'PROGRAM'>,1:0]
[@1,8:11='test',<IDENTIFIER>,1:8]
[@2,13:17='BEGIN',<'BEGIN'>,2:0]
[@3,19:21='END',<'END'>,3:0]
[@4,23:22='<EOF>',<EOF>,4:0]
line 3:0 mismatched input 'END' expecting {'INT', 'STRING', 'FLOAT', '+'}
(program PROGRAM (id test) BEGIN (pgm_body decl func_declarations) END)
有关 "missing 'PROGRAM'" 的错误已在您删除 KEYWORD
规则时解决(请注意,出于同样的原因,您还应删除 OPERATOR
规则)。
您现在遇到的错误与此完全无关。
您当前的问题与您没有显示的 empty
的定义有关。您说过您尝试了 EMPTY : $ ;
和 EMPTY : ^$ ;
(然后可能是 empty: EMPTY;
),但是其中 none 甚至可以编译,所以它们不会导致解析错误你发布了。无论哪种方式,EMPTY
令牌的概念都行不通。什么时候会生成这样的令牌?在所有其他令牌之间一次?在这种情况下,您会遇到很多 "unexpected EMPTY
" 错误。不,empty
规则的全部意义在于它应该在不消耗任何令牌的情况下成功。
为此,您只需定义 empty : ;
并完全删除 EMPTY
。或者,您也可以删除 empty
,并在当前使用 empty
的任何地方使用一个空的替代项(即 | ;
)。这两种方法都可以使您的代码正常工作,但还有更好的方法:
您正在使用 empty
作为基本上相当于列表的规则的基本情况。 ANTLR 提供重复运算符 *
(0 或更多)、+
(1 或更多)以及 ?
运算符来使事情成为可选的。这些允许您非递归地定义列表并且没有 empty
规则。例如 stmt_list
可以这样定义:
stmt_list : stmt* ;
和 id_list
像这样:
id_list : (id (',' id)*)? ;
顺便说一句,利用 ANTLR 4 支持直接左递归这一事实,您的语法可以大大简化,因此您可以摆脱所有不同的表达式规则,只使用一个左递归规则。
那会给你:
expr : primary
| id '(' expr_list ')'
| expr mulop expr
| expr addop expr
;
规则 expr_prefix
、factor
、factor_prefix
和 postfix_expr
和 call_expr
都可以删除。