访客模式程序无法正常工作

Visitor pattern program doesn't work correct

我需要为计算器创建一个简单的编译器,我正在使用 antlr4 和访问者模式。 这是我的语法文件 Simple_Calculator.g4 :

grammar Simple_Calculator;
program : statements ;
statements : statement | statements statement ;
statement : identifier '=' expr ';'                         #assign
      | 'begin' statements 'end'                            #brac
      | 'if' expr 'then' statement                          #if
      | 'if' expr 'then' statement 'else' statement                 #if_elset
      | 'while' expr 'do' statement                         #while
      | 'for' identifier '=' number ':' number 'do' statement           #for
      | 'print' identifier ';'                          #print
      ;
expr    : expr binop expr                               #ope
    | '!' expr                                  #invert
    | '(' expr ')'                                  #parenthesis
    | identifier                                    #identify
    | number                                    #num
    ;
binop   : '+'
    | '-'
    | '*'
    | '/'
    | '<'
    | '>'
    | '<='
    | '>='
    | '=='
    | '!='
    | '^'
    ;
identifier : STRING+('-'|STRING|INT)* ;                     
number  : INT+('.'INT+)? ;
STRING: [a-zA-Z]+ ;
INT : [0-9]+ ;
WS  : [ \t\r\n] -> skip ;

下面是 MainVisitor extends Simple_CalculatorBaseVisitor class 中的 visitOpevisitAssign 方法:

public class MainVisitor extends Simple_CalculatorBaseVisitor<Object> {

@Override
    public Object visitAssign(Simple_CalculatorParser.AssignContext ctx) {
        String id = (String) (visit(ctx.identifier()));
        String value = (String)(visit(ctx.expr()));

        if (storage.containsKey(id)) {
            storage.replace(id, value);
        } else {
            storage.put(id, value);
        }
        return storage; //To change body of generated methods, choose Tools | Templates.
    } // end of visitAssign

@Override
    public Object visitOpe(Simple_CalculatorParser.OpeContext ctx) {
        String leftOperand = (String) visit(ctx.expr(0));
        String rightOperand = (String) visit(ctx.expr(1));
        /*if (rightOperand.matches("^\d+$")) {
        return rightOperand;
        }*/
        String Operation = ctx.binop().getText();
        switch (Operation) {
            case "+": {
                leftOperand = setOperands(leftOperand);
                rightOperand = setOperands(rightOperand);
                return String.valueOf(Integer.parseInt(leftOperand) + Integer.parseInt(rightOperand));
            }
            case "-":
                leftOperand = setOperands(leftOperand);
                rightOperand = setOperands(rightOperand);
                return String.valueOf(Integer.parseInt(leftOperand) - Integer.parseInt(rightOperand));
            case "*":
                leftOperand = setOperands(leftOperand);
                rightOperand = setOperands(rightOperand);
                return String.valueOf(Integer.parseInt(leftOperand) * Integer.parseInt(rightOperand));
            case "/":
                leftOperand = setOperands(leftOperand);
                rightOperand = setOperands(rightOperand);
                return String.valueOf(Integer.parseInt(leftOperand) / Integer.parseInt(rightOperand));

// the rest possible conditions
    }

//other methods
}// end of visitOpe

问题是,当我想在赋值表达式中使用“-”运算符时,当程序读取 visitAssign 中的行 String value = (String)(visit(ctx.expr())); 时,它不会在那之后访问 visitOpe ,而是 returns 整个表达式。 例如,当我给出程序时:

i=5;
i=i+2;
print i;

作为输入,它工作正常。它将 i 作为标识符存储在 HashMap 中,在第二行中,它将向其添加 2 个单位并最终打印其值。 但是如果我将 i=i+2; 更改为 i=i-2,它会存储初始值为 5 的 i,但在第二行中,它不会通过 visitOpe 方法,而是通过它returns "i-2" 并将其存储为 i 的值,最后打印它。 '*' 和 '/' 运算符可以很好地作为加法。它只是关于'-',我不知道是什么问题。 那么,如何解决这个问题:

此致

有了那个语法片段

identifier : STRING+('-'|STRING|INT)* ;      

i-2 是一个有效的标识符。一种选择是从标识符中删除 '-'

所以:

identifier : STRING+(STRING|INT)* ;      

不同的观察,但如果您正在制作计算器或任何计算数学表达式的东西,您可能还会重新考虑您的 binop 优先级。在一个小组中,他们从上到下进行评估。它不像旧的 BNF 文法那样人们耍花招,高优先级的运算符掉到底部。因此,在您的情况下,像 3+2*5 这样的表达式会产生 25 而不是 13,因为加法的优先级高于乘法。请注意这个来自 Bart Kiers 优先级的优秀语法 (Mu) 是如何布局的:

expr
 : expr POW<assoc=right> expr           #powExpr
 | MINUS expr                           #unaryMinusExpr
 | NOT expr                             #notExpr
 | expr op=(MULT | DIV | MOD) expr      #multiplicationExpr
 | expr op=(PLUS | MINUS) expr          #additiveExpr
 | expr op=(LTEQ | GTEQ | LT | GT) expr #relationalExpr
 | expr op=(EQ | NEQ) expr              #equalityExpr
 | expr AND expr                        #andExpr
 | expr OR expr                         #orExpr
 | atom                                 #atomExpr
 ;

最高优先级。