antlr4 in dot net "不匹配的输入'开始'期望 {';', '+', '-', '*', DIV, MOD}



我在C#中使用antlr4。

一切都

很好,除了当我使用"阻止"时,一切都会变得疯狂。

例如这是我的输入代码:

a:int;
a:=2;
if(a==2) begin
a:= a * 2;
a:=a + 5;
end

这是我的格拉默:

grammar Our;
options{
    language=CSharp;
    TokenLabelType=CommonToken;
    ASTLabelType=CommonTree;
}
statements  :   statement statements
        |EOF;
statement   :
            expression SEMI
        |   ifstmt
        |   whilestmt 
        |   forstmt
        |   readstmt SEMI
        |   writestmt SEMI
        |   vardef SEMI
        |   block
        ;
block       :   BEGIN statements END ;
expression  :   ID ASSIGN expression
        |   boolexp;
boolexp     :   relexp AND boolexp
        |   relexp OR boolexp
        |   relexp;
relexp      :   modexp EQUAL relexp
        |   modexp LE relexp 
        |   modexp GE relexp
        |   modexp NOTEQUAL relexp 
        |   modexp GT relexp 
        |   modexp LT relexp
        |   modexp;
modexp      :   modexp  MOD exp 
        //| exp DIV modexp 
        |   exp;
exp         :   exp  ADD term 
        |   exp  SUB  term 
        |   term;
term        :   term MUL factor 
        |   term DIV factor
        |   factor POW term 
        |   factor;
factor      :   LPAREN expression RPAREN
        |   LPAREN vartype RPAREN  factor
        |   ID
        |   SUB factor
        |   ID LPAREN explist RPAREN 
        |   ID LPAREN RPAREN
        |   ID LPAREN LPAREN NUM RPAREN RPAREN 
        |   ID LPAREN LPAREN NUM COMMA NUM RPAREN RPAREN
        |   const;
explist     :   exp  COMMA  explist
        |exp;
const       :   NUM 
        |   BooleanLiteral          
        |   STRING;
ifstmt      :   IF LPAREN boolexp RPAREN statement
        |   IF LPAREN boolexp  RPAREN statement ELSE statement ;
whilestmt   :   WHILE LPAREN boolexp  RPAREN statement ;
forstmt     :   FOR ID ASSIGN exp  COLON exp statement;
readstmt    :   READ LPAREN  idlist  RPAREN ;
idlist      :   ID COMMA idlist
        |ID;
writestmt   :   WRITE  LPAREN explist RPAREN ;
vardef      :   idlist COLON vartype;

vartype     :   basictypes 
        |   basictypes LPAREN NUM RPAREN 
        |   basictypes LPAREN NUM COMMA NUM RPAREN ;
basictypes  :   INT 
        |   FLOAT 
        |   CHAR 
        |   STRING 
        |   BOOLEAN  ; 

BEGIN         : 'begin';
END           : 'end';
To            : 'to';
NEXT          : 'next';
REAL          : 'real';
BOOLEAN       : 'boolean';
CHAR          : 'char';
DO            : 'do';
DOUBLE        : 'double';
ELSE          : 'else';
FLOAT         : 'float';
FOR           : 'for';
FOREACH       : 'foreach';
FUNCTION      : 'function';
IF            : 'if';
INT           : 'int';
READ          : 'read';
RETURN        : 'return';
VOID          : 'void';
WHILE         : 'while';
WEND          : 'wend';
WRITE         : 'write';
LPAREN          : '(';
RPAREN          : ')';
LBRACE          : '{';
RBRACE          : '}';
LBRACK          : '[';
RBRACK          : ']';
SEMI            : ';';
COMMA           : ',';
ASSIGN          : ':=';
GT              : '>';
LT              : '<';
COLON           : ':';
EQUAL           : '==';
LE              : '<=';
GE              : '>=';
NOTEQUAL        : '!=';
AND             : '&&'|'and';
OR              : '||'|'or';
INC             : '++';
DEC             : '--';
ADD             : '+';
SUB             : '-';
MUL             : '*';
DIV             : '/'|'div';
MOD             : '%'|'mod';
ADD_ASSIGN      : '+=';
SUB_ASSIGN      : '-=';
MUL_ASSIGN      : '*=';
DIV_ASSIGN      : '/=';
POW             : '^';
BooleanLiteral : 'true'|'false';
STRING : '"'([a-zA-Z]|NUM)*'"';
ID : ([a-z]|[A-Z])([a-z]|[A-z]|[0-9])*;
NUM : ('+'|'-')?[0-9]([0-9]*)('.'[0-9][0-9]*)?;
WS  :  [ trnu000C]+ -> skip ;
COMMENT : '/*' .*? '*/' ;
LINE_COMMENT : '//' ~[rn]*;

当我运行解析器时,我收到以下错误消息:

输入时没有可行的替代方案 'if(a==2)begina:=a*2;a:=a+5;end'不匹配的输入"开始"期望 {';', '+', '-', '*', DIV, MOD}在输入"结束"没有可行的替代方案

提前谢谢。

问题是语句列表的规则:

statements : statement statements | EOF ;

此规则有两个选项:一个statement后跟另一个statements列表,或EOF 。唯一的非递归选项是 EOF ,当您在规则中使用它时,它会成为一个问题block

block : BEGIN statements END ;

您永远不会在block中间遇到EOF,因此当解析器读取示例输入中end之前的行时,它期望读取的下一件事是另一个statement。单词本身end不是一个有效的statement,这就是为什么它会抛出您看到的错误。

一种可能的解决方法是将statements规则的递归部分设置为可选:

statements : statement statements? | EOF ;

这将允许示例输入成功解析。在我看来,更好的选择是完全删除递归:

statements : statement* | EOF ;

最后,您可以看到EOF仍然是statements规则的选项之一。当你在 作为block规则的一部分使用这个规则时,这没有多大意义,因为你不应该在block中间找到EOF。我要做的是将其移动到新的顶级解析器规则:

program : statements EOF ;
statements : statement* ;

最新更新