Search code examples
javagrammarantlr4visitor-pattern

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


Solution

  • 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)* ;