import java.io.*; import java.util.*; class TooManyCalls extends Exception {} class Scanner { static final int END=-1; static final int LPAR='('; static final int RPAR=')'; static final int CONST=-2; static final int NAME=-3; String sval; int nval; StreamTokenizer st; int token=0; Scanner(Reader rdr) throws Exception { st = new StreamTokenizer(rdr); st.resetSyntax(); st.wordChars('a','z'); st.parseNumbers(); st.whitespaceChars(0,' '); } void advance() { if (token != END) token=0; } int nextToken() throws Exception { if (token == END) return END; if (token == 0) { int t = st.nextToken(); if (t == st.TT_EOF) token = END; else if (t == st.TT_NUMBER) { nval = (int)Math.round(st.nval); token = CONST; } else if (t == st.TT_WORD) { sval = st.sval; token = NAME; } else token = t; } return token; } } class Actual { String name; Expr expr; HashMap bindings; Actual (String n, Expr ex, HashMap bnd) { name = n; expr = ex; bindings = bnd; } } class Stat { int nadd=0, nsub=0, nmult=0, ndiv=0, nrem=0; static int toteval=0; void incr(Stat s) throws TooManyCalls { nadd += s.nadd; nsub += s.nsub; ndiv += s.ndiv; nrem += s.nrem; nmult += s.nmult; } } abstract class Expr { abstract Expr eval(HashMap funcs, HashMap acts, Stat stat, boolean strict) throws Exception; } class Name extends Expr { String name; Name(String s) { name = s; } Expr eval(HashMap funcs, HashMap acts, Stat stat, boolean strict) throws Exception,TooManyCalls { Actual act = (Actual)acts.get(name); if (act != null) return act.expr = act.expr.eval(funcs, act.bindings, stat, strict); else { Expr f = (Expr)funcs.get(name); if ( f!=null) return f; return this; // should not happen } } public String toString() { return "Name = " + name; } } class Const extends Expr { int val; Const(int n) throws Exception { val = n; } Expr eval(HashMap funcs, HashMap acts, Stat stat, boolean strict) throws Exception { return this; } public String toString() { return "Const = " + val; } } class FunCall extends Expr { ArrayList e; FunCall(ArrayList ee) { e=ee; } Expr eval(HashMap funcs, HashMap acts, Stat stat, boolean strict) throws Exception { Stat.toteval++; if (Stat.toteval > 10000) throw new TooManyCalls(); Function func = (Function)((Expr)e.get(0)).eval(funcs, acts, stat, strict); if (func instanceof Builtin) return ((Builtin)func).callBuiltin(funcs, acts, stat, strict, (Expr)e.get(1), (Expr)e.get(2)); String[] formals = func.formals; Expr body = func.body; int nf = formals.length; HashMap newacts = new HashMap(); for (int i = 0; i < nf; ++i) { Actual act = new Actual(formals[i], strict ? ((Expr)e.get(i+1)).eval(funcs, acts, stat, strict) : ((Expr)e.get(i+1)), acts); newacts.put(act.name, act); } /* evaluate the body in the new environment */ Expr be = body.eval(funcs, newacts, stat, strict); return be; } public String toString() { StringBuffer sb = new StringBuffer(); sb.append("BEGIN FUNCALL"); Iterator p = e.iterator(); while(p.hasNext()) sb.append(" " + p.next().toString()); sb.append(" END FUNCALL"); return sb.toString(); } } class Function extends Expr { String name; String[] formals; Expr body; Function(String n, String[] f, Expr b) { name = n; formals = f; body = b; } Expr eval(HashMap funcs, HashMap acts, Stat s, boolean strict) { return this; } public String toString() { return "function " + name; } } class Builtin extends Function { Builtin(String n) { super(n,null,null); } Expr callBuiltin(HashMap funcs, HashMap acts, Stat stat, boolean strict, Expr e1, Expr e2) throws Exception { if (name.equals("add")) { stat.nadd++; e1 = e1.eval(funcs, acts, stat, strict); e2 = e2.eval(funcs, acts, stat, strict); return new Const(((Const)e1).val + ((Const)e2).val); } if (name.equals("sub")) { stat.nsub++; e1 = e1.eval(funcs, acts, stat, strict); e2 = e2.eval(funcs, acts, stat, strict); return new Const(((Const)e1).val - ((Const)e2).val); } if (name.equals("mult")) { stat.nmult++; e1 = e1.eval(funcs, acts, stat, strict); e2 = e2.eval(funcs, acts, stat, strict); return new Const(((Const)e1).val * ((Const)e2).val); } if (name.equals("div")) { stat.ndiv++; e1 = e1.eval(funcs, acts, stat, strict); e2 = e2.eval(funcs, acts, stat, strict); return new Const(((Const)e1).val / ((Const)e2).val); } if (name.equals("rem")) { stat.nrem++; e1 = e1.eval(funcs, acts, stat, strict); e2 = e2.eval(funcs, acts, stat, strict); return new Const(((Const)e1).val % ((Const)e2).val); } if (name.equals("eq")) { e1 = e1.eval(funcs, acts, stat, strict); e2 = e2.eval(funcs, acts, stat, strict); Expr e3 = ((Const)e1).val == ((Const)e2).val ? (Expr)funcs.get("true") : (Expr)funcs.get("false"); return e3; } if (name.equals("gt")) { e1 = e1.eval(funcs, acts, stat, strict); e2 = e2.eval(funcs, acts, stat, strict); return ((Const)e1).val > ((Const)e2).val ? (Expr)funcs.get("true") : (Expr)funcs.get("false"); } if (name.equals("true")) { e1 = e1.eval(funcs, acts, stat, strict); if (strict) e2.eval(funcs, acts, stat, strict); return e1; } if (name.equals("false")) { if (strict) e1.eval(funcs, acts, stat, strict); e2 = e2.eval(funcs, acts, stat, strict); return e2; } return null; } } class lazy_mg { static BufferedReader stdin; HashMap functions = new HashMap(); public static void main(String[] ss) throws Exception { Reader rdr = new InputStreamReader(System.in); stdin = new BufferedReader(rdr); (new lazy_mg()).run(); } void run() throws Exception { String line; Stat sstat = new Stat(); Stat lstat = new Stat(); HashMap empty = new HashMap(); functions.put("add", new Builtin("add")); functions.put("sub", new Builtin("sub")); functions.put("mult", new Builtin("mult")); functions.put("div", new Builtin("div")); functions.put("rem", new Builtin("rem")); functions.put("eq", new Builtin("eq")); functions.put("gt", new Builtin("gt")); functions.put("false", new Builtin("false")); functions.put("true", new Builtin("true")); for (line = stdin.readLine().trim(); line.length() > 0; line = stdin.readLine().trim()) declareFunction(line); for (line = stdin.readLine(); line != null && line.trim().length() > 0; line = stdin.readLine()){ line = line.trim(); Expr e = parse(line); Stat s1 = new Stat(); Stat s2 = new Stat(); try { // System.out.println("strict"); Stat.toteval=0; e.eval(functions, empty, s1, true); // System.out.println("lazy"); Stat.toteval=0; e.eval(functions, empty, s2, false); sstat.incr(s1); lstat.incr(s2); } catch(TooManyCalls exc) { /* just skip to next case */ } } present(sstat, lstat); } Expr funcall(Scanner lex) throws Exception { lex.advance(); // skip '('; ArrayList e = new ArrayList(); while (lex.nextToken() != Scanner.RPAR) e.add(expr(lex)); lex.advance(); // skip ')'; return new FunCall(e); } Expr expr(Scanner lex) throws Exception { Expr e; int t; switch(t=lex.nextToken()) { case Scanner.CONST: e = new Const(lex.nval); lex.advance(); return e; case Scanner.NAME: e = new Name(lex.sval); lex.advance(); return e; case Scanner.LPAR: return funcall(lex); default: System.err.println("Very bad " + t); return null; } } Expr parse(String s) throws Exception { Scanner sc = new Scanner(new StringReader(s)); Expr e = expr(sc); return e; } void declareFunction (String s) throws Exception { int eqpos = s.indexOf('"'); String[] parts = s.split("\\s*=\\s*"); String[] head = parts[0].split("\\s+"); String fname = head[0]; String[] formals = new String[head.length-1]; for (int i = 1; i < head.length; ++i) formals[i-1] = head[i]; Expr body = parse(parts[1]); Function f = new Function(fname, formals, body); functions.put(fname, f); } String format(String s1, int n1, int n2) { String s2 = Integer.toString(n1), s3 = Integer.toString(n2); String space = " "; return s1 + space.substring(0,9-s1.length()) +s2 + space.substring(0,16-s2.length()) +s3; } void present(Stat s, Stat l) { System.out.println("operator lazy_evaluation strict_evaluation"); System.out.println(format("add", l.nadd, s.nadd)); System.out.println(format("sub", l.nsub, s.nsub)); System.out.println(format("mult", l.nmult, s.nmult)); System.out.println(format("div", l.ndiv, s.ndiv)); System.out.println(format("rem", l.nrem, s.nrem)); } }