// Semantics.java import java.util.*; class State extends Hashtable { // Defines the set of variables and their associated values // that are active during interpretation: State is implemented as // a Java Hashtable. // construct the empty state public State() { } // construct a new state with a single key-value pair public State(Variable key, Value val) { put(key, val); } // Overriding union function "onion" on two states s and t; // returns a state composed of all elements in t together // with all elements in s that are not in t. public State onion (State t) { for (Enumeration e = t.keys(); e.hasMoreElements(); ) { Variable key = (Variable)e.nextElement(); put(key, t.get(key)); } return this; } public void display () { System.out.print("{ "); for (Enumeration e = keys(); e.hasMoreElements(); ) { Variable key = (Variable)e.nextElement(); Value val = (Value)get(key); System.out.print("<" + key.id + ", "); if (val.type.isInteger()) System.out.print (val.intValue + ">"); else if (val.type.isBoolean()) System.out.print (val.boolValue + ">"); else System.out.print ("undefined>"); if (e.hasMoreElements()) System.out.print(", "); } System.out.println(" }"); } } // Following is the semantics class, characterized by the meaning // function M and its auxiliary function applyBinary. public class Semantics { State M (Program p) { return M (p.body, initialState(p.decpart)); } State initialState (Declarations d) { State sigma = new State(); Value undef = new Value(); for (int i = 0; i < d.size(); i++) sigma.put(((Declaration)(d.elementAt(i))).v, undef); return sigma; } Value applyBinary (Operator op, Value v1, Value v2) { if (v1.type.isUndefined() || v2.type.isUndefined()) { return new Value(); } else if (op.ArithmeticOp( )) { if (op.val.equals(Operator.PLUS)) return new Value(v1.intValue + v2.intValue); if (op.val.equals(Operator.MINUS)) return new Value(v1.intValue - v2.intValue); if (op.val.equals(Operator.TIMES)) return new Value(v1.intValue * v2.intValue); if (op.val.equals(Operator.DIV)) return new Value(v1.intValue / v2.intValue); } else if (op.RelationalOp( )) { if (op.val.equals(Operator.LT)) return new Value(v1.intValue < v2.intValue); if (op.val.equals(Operator.LE)) return new Value(v1.intValue <= v2.intValue); if (op.val.equals(Operator.EQ)) return new Value(v1.intValue == v2.intValue); if (op.val.equals(Operator.NE)) return new Value(v1.intValue != v2.intValue); if (op.val.equals(Operator.GE)) return new Value(v1.intValue >= v2.intValue); if (op.val.equals(Operator.GT)) return new Value(v1.intValue > v2.intValue); } else if (op.BooleanOp( )) { if (op.val.equals(Operator.AND)) return new Value(v1.boolValue && v2.boolValue); if (op.val.equals(Operator.OR)) return new Value(v1.boolValue || v2.boolValue); } return null; } Value applyUnary (Operator op, Value v) { if (v.type.isUndefined()) return new Value(); else if (op.val.equals("!")) return new Value(!v.boolValue); return null; } Value M (Expression e, State sigma) { if (e instanceof Value) return (Value)e; if (e instanceof Variable) if (!sigma.containsKey((Variable)e)) return new Value(); else return (Value)(sigma.get((Variable)e)); if (e instanceof Binary) return applyBinary (((Binary)e).op, M(((Binary)e).term1, sigma), M(((Binary)e).term2, sigma)); if (e instanceof Unary) return applyUnary(((Unary)e).op, M(((Unary)e).term, sigma)); return null; } State M (Statement s, State sigma) { if (s instanceof Skip) return M((Skip)s, sigma); if (s instanceof Assignment) return M((Assignment)s, sigma); if (s instanceof Conditional) return M((Conditional)s, sigma); if (s instanceof Loop) return M((Loop)s, sigma); if (s instanceof Block) return M((Block)s, sigma); return null; } State M (Skip s, State sigma) { return sigma; } State M (Assignment a, State sigma) { return sigma.onion(new State(a.target, M (a.source, sigma))); } State M (Block b, State sigma) { for (int i=0; i