2014-09-02 1 views
1

ANTLR4를 사용하여 스크립팅 언어 용 인터프리터를 만들려고합니다. 나는 방문자를 사용하여 표준 작업 (mul, div, sub, etc ...)을 구현했으며 이제는 jump \ Salta 함수 호출을 구현해야한다. 점프 (n) FunctionCall은 그의 호출 후에 n 행을 무시합니다. 예 :점프 기능 구현

Fai var1 = 3,var2 = 4; 
Fai Salta(1); //my jump() function call 
Fai var1=4; 
println(var1); 

output: 3 

이 내 현재의 문법입니다 :

grammar TL; 
@members{ 
int salta=0; 
} 
parse 
: block+ EOF 
; 

block 
: DO statement (','statement)* END // Fai a=2,B=e; 
; //manca l'if 

DO:'Fai'; 
END:';'; 
Salta:'Salta'; 
statement 
:assign 
|functionCall 
|saltaCall 
; 
functionCall 
: Identifier '(' exprList? ')' #identifierFunctionCall 
| Println '(' expr? ')' #printlnFunctionCall 
| Print '(' expr ')' #printFunctionCall 
; 
saltaCall 
:Salta '(' Number ')' rows[$Number.int] 
; 
rows[int n] 
locals[int i=0;] 
:({$i<$n}?END? block {$i++;})* 
; 

exprList 
: expr (',' expr)* 
; 
assign 
:Identifier '=' expr 
; 

Identifier 
: [a-zA-Z_] [a-zA-Z_0-9]* 
; 

expr 
: '-'expr #unaryMinusExpr 
| '!'expr #notExpr 
| expr '^' expr #powerExpr 
| expr '*' expr #multiplyExpr 
| expr '/' expr #divideExpr 
| expr '%' expr #modulusExpr 
| expr '+' expr #addExpr 
| expr '-' expr #subtractExpr 
| expr '>=' expr #gtEqExpr 
| expr '<=' expr #ltEqExpr 
| expr '>' expr #gtExpr 
| expr '<' expr #ltExpr 
| expr '==' expr #eqExpr 
| expr 'O' expr #orExpr 
| expr 'E' expr #andExpr 
| expr '=' expr #eqExpr 
| Number  #numberExpr 
| Bool   #boolExpr 
| Null   #nullExpr 
| functionCall #functionCallExpr 
| Identifier #identifierExpr 
| String  #stringExpr 
| '(' expr ')' #exprExpr 
; 
Println:'println'; 
Print:'print'; 

Null:'null'; 

Or : 'O'; 
And : 'E'; 
Equals : '=='; 
NEquals : '!='; 
GTEquals : '>='; 
LTEquals : '<='; 
Pow : '^'; 
Excl : '!'; 
GT : '>'; 
LT : '<'; 
Add : '+'; 
Subtract : '-'; 
Multiply : '*'; 
Divide : '/'; 
Modulus : '%'; 
OBrace : '{'; 
CBrace : '}'; 
OBracket : '['; 
CBracket : ']'; 
OParen : '('; 
CParen : ')'; 
Assign : '='; 
QMark : '?'; 
Colon : ':'; 


Bool 
: 'true' 
| 'false' 
; 
Number 
: Int ('.' Digit*)? 
; 


String 
: ["] (~["\r\n] | '\\\\' | '\\"')* ["] 
| ['] (~['\r\n] | '\\\\' | '\\\'')* ['] 
; 



fragment Int 
: [1-9] Digit* 
| '0' 
; 
fragment Digit 
: [0-9] 
; 
fragment NL 
: '\n' 
; 

// ---------SKIP------------ 
Comment 
: ('#' ~[\r\n]*) -> skip 
; 
Space 
: [ \t\r\n\u000C] -> skip 
; 

어떻게 그 기능을 구현할 수있다?

+0

'SaltaCall'을 파서 규칙, 즉 'saltaCall'로 설정하면 해당 부분 (즉, '번호')에 액세스 할 수 있습니다. 댓글을 주신 덕분에 – Onur

+0

!! 지금, n 블록을 어떻게 무시할 수 있습니까? –

답변

0

Mu interpreter을 살펴 보는 것이 더 쉽습니다. 귀하의 jump 호출은 log 전화처럼 많이 보일 것이다

jump 
: JUMP expr SCOL 
; 

JUMP : 'jump'; 

는 그 다음 visitJump 메소드를 오버라이드 (override)하고 EvalVisitor 내부의 jump(...) 전화 내부의 값을 추적합니다.

이제 visitBlock 메서드를 무시하고 jump(...) 안에있는 값의 내부에 기록 된 값이 0보다 크면 다음 표현식을 방문하지 마십시오. 일부 의사 코드 :

public class EvalVisitor extends MuBaseVisitor<Value> { 

    ... 

    private Double jumpAmount = 0.0; 

    @Override 
    public Value visitBlock(@NotNull MuParser.BlockContext ctx) { 

     for (MuParser.StatContext statContext : ctx.stat()) { 

      if jumpAmount is more than 0, decrease by 1 
      else visit (execute) statContext 
     } 

     return Value.VOID; 
    } 

    @Override 
    public Value visitJump(@NotNull MuParser.JumpContext ctx) { 

     Value amount = this.visit(ctx.expr()); 

     jumpAmount = amount.asDouble(); 

     return amount; 
    } 

    ... 
} 
+0

감사합니다 !!! 그것은 작동합니다! –

+0

@nikfer, 듣기 좋습니다. –