用antlr制作计算器 [英] making calculator with antlr

查看:22
本文介绍了用antlr制作计算器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对使用 antlr 非常陌生.我正在制作一个计算器,我已经制作了我的语法.如果我使用侦听器而不是访问者,是否可以获得结果?我不知道这是否有意义,但我正在使用侦听器,我唯一能做的就是让它打印出输入而不是输入的计算结果.我在网上查过,每个例子都使用了访问者.那么我应该使用访问者还是在使用侦听器时可以得到结果?我希望这是有道理的.

am very new to using antlr. I am making a calculator and I have already made my grammar. is it possible to get results if I use listener instead of visitor? I don't know if that makes sense but I am using the listener and the only thing I have been able to do is to get it to print out the input but not the calculated result from the input. I have checked online and every example uses the visitor. so should I use visitor or is there someway you can get results when using listener? I hope that makes sense.

这是我的 g4 文件

grammar calc;

TYPE_INT: 'int';
TYPE_FLOAT: 'float';
EQU: '=';
MUL: '*';
DIV: '/';
PLU: '+';
MIN: '-';
L_BKT: '(';
R_BKT: ')';
WRITE: 'write';
END_MARK: ';';
ID: ([A-Z]|[a-z]) ([A-Z]|[a-z]|[0-9])*;
INT: ('0'|([1-9]([0-9])*));
FLOAT: ('0'|([1-9]([0-9])*))'.'([0-9]+)(('e'|'E')('+'|'-')?('0'|([1-9]([0-
9])*)))? ;
WS : [ \t\r\n]+ -> skip ;

declare: (typeInt=TYPE_INT|typeFloat=TYPE_FLOAT) id=ID;
assign: id=ID equ=EQU expr;
expr: expr (plu=PLU|min=MIN) expr2|expr2;
expr2: expr2 (mul=MUL|div=DIV) expr3 |expr3;
expr3: floatNumber=FLOAT| intNumber=INT| id=ID| lBkt=L_BKT expr rBkt=R_BKT;
writeFunction: write=WRITE lBkt=L_BKT id=ID rBkt=R_BKT;

stmt: declare| assign| writeFunction;
stmts: (stmt endMark=END_MARK)*;
r: stmts;

这是我在 calcbaseListener 中使用的 variable 和 variableList 类

this is the variable and variableList class I made to use in calcbaseListener

public class Variable {
public String name="";
public String type="int";
public float value=(float) 0.0;

}


public class VariableList {

List<Variable> list=new ArrayList();

private static VariableList self=new VariableList();

public static VariableList getList(){
    return self;
}

public Variable find(String name){
    Variable v=null;
    for(int i=0;i<list.size();i++){
        Variable tmp=list.get(i);
        if(tmp.name.equals(name)){
            v=tmp;
        }
    }
    return v;
}

public void add(Variable v){
    list.add(v);
}

}

这是我放在 calcBaseListener 中的代码

this is the code I put in calcBaseListener

    public void exitDeclare(calcParser.DeclareContext ctx) {
    String name=ctx.id.getText();
    Variable v=new Variable();
    v.name = name;

    if(ctx.typeFloat != null) {
        v.type = "float";
    } else {
        v.type = "int";
    }

    VariableList list = VariableList.getList();

    if(list.find(v.name) == null) {
        list.add(v);
    } else {
        System.out.println("The id has already been declared");
        System.exit(0);
    }
}


    public void exitAssign(calcParser.AssignContext ctx) {
    String name = ctx.id.getText();
    VariableList list = VariableList.getList();

    if(list.find(name) == null) {
        System.out.println("Undeclared id");
        System.exit(0);
    } else {
        Variable v = list.find(name);
        if(v.type.equals(ctx.expr().v.type) || v.type.equals("float") && 
        ctx.expr().v.type.equals("int")) {
            v.value = ctx.expr().v.value;
        }
        else {
            System.out.println("The type of int assigned to the type of type 
            of float error");
            System.exit(0);
        }
    } 
}


    public void exitExpr(calcParser.ExprContext ctx) {
    if(ctx.expr()==null){
        if(ctx.v.type.equals(ctx.expr2().v.type)||
            ctx.v.type.equals("float")&&ctx.expr2().v.type.equals("int")){
            ctx.v.value=ctx.expr().v.value;
        }else{
            System.out.println("The type of int assign to the tpye of float 
             error");
            System.exit(0);
        }
        ctx.v.value=ctx.expr().v.value;
        return;
    }
    if(ctx.plu!=null){
        String type="";
        if(ctx.expr().v.type.equals("float")
                ||ctx.expr2().v.type.equals("float")){
            type="float";
        }else{
            type="int";
        }
        if(ctx.v.type.equals(type)||
                ctx.v.type.equals("float")&&type.equals("int")){
            ctx.v.value=ctx.expr().v.value;
        }else{
            System.out.println("The type of int assign to the tpye of float 
             error");
            System.exit(0);
        }
        ctx.v.value=ctx.expr().v.value+ctx.expr2().v.value;
        return;
    }
    if(ctx.min!=null){
        String type="";
        if(ctx.expr().v.type.equals("float")
                ||ctx.expr2().v.type.equals("float")){
            type="float";
        }else{
            type="int";
        }
        if(ctx.v.type.equals(type)||
                ctx.v.type.equals("float")&&type.equals("int")){
            ctx.v.value=ctx.expr().v.value;
        }else{
            System.out.println("The type of int assign to the tpye of float 
            error");
            System.exit(0);
        }
        ctx.v.value=ctx.expr().v.value-ctx.expr2().v.value;

        return;
    }

}



   public void exitExpr2(calcParser.Expr2Context ctx) {
    if(ctx.expr2()==null){
        if(ctx.v.type.equals(ctx.expr3().v.type)||
                ctx.v.type.equals("float")&&ctx.expr3().v.type.equals("int")){
                    ctx.v.value=ctx.expr2().v.value;
        }else{
            System.out.println("The type of int assign to the tpye of float error");
            System.exit(0);
        }
        ctx.v.value=ctx.expr2().v.value;
        return;
    }
    if(ctx.mul!=null){
        String type="";
        if(ctx.expr2().v.type.equals("float")
                ||ctx.expr3().v.type.equals("float")){
            type="float";
        }else{
            type="int";
        }
        if(ctx.v.type.equals(type)||
                ctx.v.type.equals("float")&&type.equals("int")){
            ctx.v.value=ctx.expr2().v.value;
        }else{
            System.out.println("The type of int assign to the tpye of float error");
            System.exit(0);
        }
        ctx.v.value=ctx.expr2().v.value*ctx.expr3().v.value;
        return;
    }
    if(ctx.div!=null){
        String type="";
        if(ctx.expr2().v.type.equals("float")
                ||ctx.expr3().v.type.equals("float")){
            type="float";
        }else{
            type="int";
        }
        if(ctx.v.type.equals(type)||
                ctx.v.type.equals("float")&&type.equals("int")){
            ctx.v.value=ctx.expr2().v.value;
        }else{
            System.out.println("The type of int assign to the tpye of float error");
            System.exit(0);
        }
        ctx.v.value=ctx.expr2().v.value/ctx.expr3().v.value;
        return;
    }
}


    public void exitExpr3(calcParser.Expr3Context ctx) {
    if(ctx.floatNumber!=null){
        ctx.v.type="float";
        ctx.v.value=Float.valueOf(ctx.floatNumber.getText());
    }
    if(ctx.intNumber!=null){
        ctx.v.type="int";
        ctx.v.value=Float.valueOf(ctx.intNumber.getText());
    }
    if(ctx.id!=null){

        VariableList list=VariableList.getList();
        String name=ctx.id.getText();
        ctx.v.type=list.find(name).type;
        ctx.v.value=list.find(name).value;
    }

    if(ctx.expr()!=null){
        ctx.v.type=ctx.expr().v.type;
        ctx.v.value=ctx.expr().v.value;
    }
}


 public void exitWriteFunction(calcParser.WriteFunctionContext ctx) {
    VariableList list=VariableList.getList();
    String name=ctx.id.getText();
    if(list.find(name)!=null){
        Variable v=list.find(name);
        System.out.println(v.value);

    }else{
        System.out.println("Undecleared id");
        System.exit(0);
    }

}

如果我像这样编写代码,是否有可能获得计算值?

is it possible for me to get value of a calculation if i write my code like this?

推荐答案

为了回答您的原始问题:是的,可以使用侦听器来实现计算器.

In order to answer your orignal question: Yes it is possible to implement a calculator using a listener.

此时将简单地参考 这个 GitHub 存储库,它提供了两个:一个使用侦听器的实现一个使用访问者.

At this point will simply refer to this GitHub repository that provides both: One implementation using a listener and one using a visitor.

由于上面引用的语法无法处理分配,我建议看看这个 repo 也确实提供了除纯算术解析之外的赋值功能.但请注意,该方法没有利用 ANTLR 处理直接左递归的能力,这会导致为同一任务产生更多代码.

As the above referenced grammar can't handle assignments I'D suggest to have a look at this repo as well that does provide the assignment-functionality next to the pure arithmetic-parsing. Note though that this one does not take advantage of ANTLR's capability to deal with direct left-recursion which leads to a lot more code for the same task.

总的来说,我建议您利用直接左递归规则,因为这样会使您的语法更易于阅读.结合替代规则标签,这是一个真正强大的功能.

In general I'd advise you to do take advantage of direct left-recursive rules as tehy make your grammar a lot simpler to read. In combination alternative-rule-labeling it's a real powerful feature.

这篇关于用antlr制作计算器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆