tree grammar CalcWalker;

options
{
        tokenVocab = Calc;
        ASTLabelType = CommonTree;
}

@header
{
        import java.util.Map;
        import java.util.HashMap;
}

@members
{
        static private final Map<String,Double> registers = new HashMap<String,Double> ();
        static private double ans = 0;
}

program
        : stat+
        ;

stat returns [double value]
        // mathemathical expression
        : expr
        {
         $value = $expr.value;
         ans = $expr.value;
         System.out.println ("ans = " + $value);
        }
        // assignment
        | ^('=' REGISTER expr)
        {
         $value = $expr.value;
         ans = $expr.value;
         System.out.println ($REGISTER.text + " = " + $value);
         registers.put ($REGISTER.text, new Double (value));
        }
        ;

expr returns [double value]
        // addition
        : ^('+' a=expr b=expr)         { $value = $a.value + $b.value; }
        // subtraction
        | ^('-' a=expr b=expr)         { $value = $a.value - $b.value; }
        // multiplication
        | ^('*' a=expr b=expr)         { $value = $a.value * $b.value; }
        // division
        | ^('/' a=expr b=expr)         { $value = $a.value / $b.value; }
        // power (indicy)
        | ^('**' a=expr b=expr)        { $value = Math.pow ($a.value, $b.value); }
        // negation
        | ^(NEGATE a=expr)             { $value = -$a.value; }
        // square root
        | ^('sqrt' a=expr)             { $value = Math.sqrt ($a.value); }
        // absolute value
        | ^('abs' a=expr)              { $value = Math.abs ($a.value); }
        // a number
        | NUMBER                       { $value = new Double ($NUMBER.text).doubleValue (); }
        // the previous answer
        | ANS                          { $value = ans; }
        // the value of a register
        | REGISTER
        {
         if (!registers.containsKey ($REGISTER.text))
         {
          throw new Error ("Unknown register " + $REGISTER.text);
         }
         $value = registers.get ($REGISTER.text).doubleValue ();
        }
        ;