2016-01-24 43 views
1

我使用antlr4在C#antlr4在點網「不匹配輸入 '開始' 期待{ ';', '+', ' - ', '*',DIV,MOD}

一切工作正常。除了當我使用「塊」一切都瘋了

例如,這是我輸入代碼:

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 : [ \t\r\n\u000C]+ -> skip ; 

COMMENT : '/*' .*? '*/' ; 

LINE_COMMENT : '//' ~[\r\n]*; 

時我運行解析器我得到以下錯誤信息:

沒有可行的替代在輸入'如果(a == 2)begina:= a * 2; a:= a + 5;結束' 不匹配的輸入'開始'期待{';','+',' - ','*',DIV,MOD} 在輸入'結束'時沒有可行的替代方案

在此先感謝。

回答

2

的問題是你的語句列表規則:

statements : statement statements | EOF ; 

此規則有兩個選擇:一個statement其次是statements,或EOF另一個列表。唯一的非遞歸選項是EOF,當你使用這個在您的規則在block成爲了一個問題:

block : BEGIN statements END ; 

你永遠不能遇到EOFblock的中間,所以當解析器讀取在您的示例輸入中的end之前,它預計讀取的另一個內容是另一個statement。單詞end本身並不是有效的statement,這就是爲什麼它會拋出您所看到的錯誤。

一個可能的解決辦法是讓你的statements規則可選的遞歸部分:

statements : statement statements? | EOF ; 

這將使你的樣品輸入到成功解析。在我看來,一個更好的選擇是完全去掉遞歸:

statements : statement* | EOF ; 

最後,你可以看到EOF仍然爲statements規則的選項之一。當您在block規則的一部分中使用此規則時,這並沒有多大意義,因爲您應該在block的中間找不到EOF。我會做的是將此移至新的頂級解析器規則:

program : statements EOF ; 
statements : statement* ; 
相關問題