实现跳转功能



我正在尝试使用ANTLR4为我的脚本语言创建一个解释器。我还使用访问者实现了标准操作(mul、div、sub等),现在我必须实现jump\Salta函数调用Jump(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
: ["] (~["rn] | '\\' | '\"')* ["]
| ['] (~['rn] | '\\' | '\'')* [']
;

fragment Int
: [1-9] Digit*
| '0'
;
fragment Digit
: [0-9]
;
fragment NL
: 'n'
;
// ---------SKIP------------
Comment
: ('#' ~[rn]* ) -> skip
;
Space
: [ trnu000C] -> skip
;

我该如何实现该功能?

查看Mu解释器更容易。你的jump呼叫看起来很像log呼叫:

jump
 : JUMP expr SCOL
 ;
JUMP : 'jump';

然后重写visitJump方法,并在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;
    }
    ...
}

相关内容

  • 没有找到相关文章

最新更新