用antlr制作计算器

时间:2018-01-04 11:43:07

标签: java antlr antlr4

使用antlr非常新。我正在制作一个计算器,我已经完成了我的语法。如果我使用听众而不是访客,是否有可能获得结果?我不知道这是否有意义,但我正在使用监听器,我唯一能做的就是让它打印输入而不是输入的计算结果。我在网上查了一下,每个例子都使用了访客。所以我应该使用访客还是在那里你可以在使用听众时获得结果?我希望这是有道理的。

这是我的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

中使用的变量和variableList类
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中放入的代码

    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);
    }

}

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

3 个答案:

答案 0 :(得分:0)

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

此时将简单地引用提供两者的this GitHub repository:一个使用侦听器的实现和一个使用访问者的实现。

由于上面提到的语法不能处理赋值,我建议看看this repo,它确实提供了纯算术解析旁边的赋值功能。请注意,虽然这个没有利用ANTLR处理直接左递归的能力,这导致了相同任务的更多代码。

一般来说,我建议你利用直接的左递归规则,因为tehy使你的语法更容易阅读。在替代规则标签的组合中,它是一个真正强大的功能。

答案 1 :(得分:0)

请查找基于antlr4 FreeBSD documentation的示例。

语法非常相似。但是我会严格遵循Raven所表达的建议并将所有&#34;代数优先级的东西组合在一起#34;在一个antlr4规则。这样做将确保优先权得到尊重,因为antlr4将在加法和减法之前探索(没有大括号)表达式的乘除部分。

我确实使用过访问者。访问者绝对是管理结果计算的最佳位置。访客的建立是为了返回结果。听众没有返回结果。 建议的实现是用python编写的。访问者创建一个字典,其中键是在相等的左侧找到的变量的名称。每次在访问者中触发操作符时,我们都会询问操作数,根据操作类型计算结果,并将结果值存储在变量的字典中。

此致

答案 2 :(得分:-1)

我对ANTLR 4并不熟悉,但总的来说 - 制作计算器意味着你需要考虑的不是单独的令牌/术语,而是你还需要考虑它们在解析树中的关系和位置(例如,进程添加,您还需要访问操作数)。

访问者似乎是一种更合适的方法(因为你决定访问节点的顺序和方式)而不是监听器(何时调用监听器?你确定解析树所需的子代已经是处理过并可以访问?)