HMD
HMD

Reputation: 460

Visitor pattern program doesn't work correct

I need to create a simple compiler for a calculator and I'm using antlr4 and the Visitor-Pattern. this is my grammar file 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 ;

and the follow is visitOpeand visitAssign methods in MainVisitor extends Simple_CalculatorBaseVisitor class :

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

the problem is, when i wanna use '-' operator in an assign expression, when the program read the line String value = (String)(visit(ctx.expr())); in visitAssign, it wont visit visitOpe after that, instead it returns the whole expression. for example, when I give the program :

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

as input, it works fine. it stores i as an identifier in a HashMap, and in second line, it will add 2 units to it and print its value finally. but if i change i=i+2; to i=i-2, it stores i with initial value of 5, but in second line, it just doesn't go through visitOpe method, instead it returns "i-2" and stores this as value of i and finally print it. '*' and '/' operators work fine as addition. It is only about '-' and i don't know what is the problem. So, How to fix this:

Regards

Upvotes: 1

Views: 133

Answers (2)

TomServo
TomServo

Reputation: 7409

Different observation, but if you're making a calculator or anything that evaluates math expressions, you might also rethink your binop precedence. Within a single group they are evaluated top to bottom. It's not like old BNF grammars where people did tricks and the higher precedence operators fell to the bottom. So in your case, an expression like 3+2*5 would yield 25 instead of 13 because addition is of higher precedence than multiplication. Notice how this excellent grammar (Mu) from Bart Kiers precedence is laid out:

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
 ;

Highest precedence at top.

Upvotes: 2

k5_
k5_

Reputation: 5568

With that grammar fragment

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

i-2 is a valid identifier. One option would be to remove the '-' from identifier.

So:

identifier : STRING+(STRING|INT)* ;      

Upvotes: 1

Related Questions