// This code evaluates expressions using the Main symboltable. Expr { traversal evaluate (EvalVisitor) { to *; } Double evaluate() = evaluate(EvalVisitor); } EvalVisitor { // The grammar is defined such that operator precedence rules will be // enforced. For example, "3+4*5" will result in 23, not 35. Unfortunately, // this means the parse trees that are created are not as friendly to the // evaluator as we'd like. // // In particular, an expression with operators at the same precedence // level will be constructed more like a list of operators rather than // an expression tree. This list is formed left-to-right, whereas an // expression tree would be derived right-to-left. For example, the // expression "8-4+3" has the result is 7. In an ideal world, the data // structure would look like this: // // + // / \ // - 3 // / \ // 8 4 // // Due to the precedence-enforcing grammar, we actually get: // // NumExpr // / \ // 8 NumExpr_ (-) // / \ // 4 NumExpr_ (+) // / \ // 3 NumExpr_ (empty) // // Simply evaluating this like an expression tree produces the wrong // result -- 1. To treat this properly, the actions are on the right // construction edges from a given operator node, such as Add and Sub, // instead of on the node itself. {{ Stack stack; }} init {{ stack = new Stack(); }} public Double get_return_val() {{ return (Double) stack.peek(); }} double booleanToDouble (boolean b) {{ return b ? 1.0 : 0.0; }} boolean doubleToBoolean (double d) {{ return (d != 0.0); }} after IntegerLiteral {{ stack.push(new Double (host.get_v().doubleValue())); }} after DoubleLiteral {{ stack.push (host.get_v()); }} after Varname {{ // look up var in symbol table Symbol sym = Main.symbolTable.findSymbol(host.toString()); if (sym == null) { System.out.println ("Error: the symbol " + host.toString() + " is not defined"); Main.stopSimulation = true; stack.push (new Double(0.0)); } else { stack.push (new Double(sym.getValue())); } }} before -> Add, next, * {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push(new Double(left + right)); }} before -> Sub, next, * {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push(new Double(left - right)); }} before -> Mul, next, * {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push(new Double(left * right)); }} before -> Div, next, * {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push(new Double(left / right)); }} after GT {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push( new Double(booleanToDouble(left > right))); }} after LT {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push( new Double(booleanToDouble(left < right))); }} after GE {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push( new Double(booleanToDouble(left >= right))); }} after LE {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push( new Double(booleanToDouble(left <= right))); }} after EQ {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push( new Double(booleanToDouble(left == right))); }} after NE {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push( new Double(booleanToDouble(left != right))); }} before -> And, next, * {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push( new Double (booleanToDouble( doubleToBoolean(left) && doubleToBoolean(right)))); }} before -> Or, next, * {{ double right = ((Double)stack.pop()).doubleValue(); double left = ((Double)stack.pop()).doubleValue(); stack.push( new Double (booleanToDouble( doubleToBoolean(left) || doubleToBoolean(right)))); }} // Unary ops are a little more difficult to treat, since // the value on which they operate is not known until // after the UnaryOp node has been traversed. Thus, we // simple check for specific the UnaryOp on the way up // the traversal. after Factor {{ double value = ((Double)stack.pop()).doubleValue(); UnaryOp unop = host.get_unaryop(); if (unop instanceof Negate) { value = -value; } else if (unop instanceof Not) { value = booleanToDouble(value == 0.0); } stack.push (new Double(value)); }} }