1

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

HMD
  • 468
  • 1
  • 5
  • 21

2 Answers2

2

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.

TomServo
  • 7,248
  • 5
  • 30
  • 47
  • well, the grammar is provided as a project by my university master, and we just have to create a compiler for it. it's not all a calculator, it does some other functions like printing. – HMD Jun 22 '17 at 20:16
  • Understood. However, just be aware that operator precedence is basically upside-down from norms. This will affect expression evaluation and probably give puzzling results if no parentheses are used to group expressions. See [this old answer](https://stackoverflow.com/questions/4899538/antlr-rule-priorities) from one of the masters, Bart Kiers. – TomServo Jun 22 '17 at 20:38
1

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)* ;      
k5_
  • 5,450
  • 2
  • 19
  • 27