首页 > 解决方案 > Antlr4 不匹配输入

问题描述

首先,我已经阅读了以下类似问题的解决方案:q1 q2 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)

标签: antlr4

解决方案


当您删除KEYWORD规则时,有关“缺少'PROGRAM'”的错误已得到解决(请注意,OPERATOR出于相同的原因您也应该删除该规则)。

您现在遇到的错误完全不相关。

您当前的问题涉及 的定义empty,您没有显示。您已经说过您尝试了EMPTY : $ ;and EMPTY : ^$ ;(然后大概是empty: EMPTY;),但是这些都没有编译,因此它们不会导致您发布的解析错误。无论哪种方式,EMPTY令牌的概念都行不通。什么时候会生成这样的令牌?在所有其他令牌之间一次?在这种情况下,您会收到很多“意外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,factorfactor_prefixpostfix_exprcall_expr可以删除。


推荐阅读