import java.io.*;
import java.util.*;

class Interp {

  // Support for reading white-space-separated from stdin
  static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  static StringTokenizer st;
  static String readToken() throws IOException {
    while (true) {
      try {
	return st.nextToken();
      } catch (NoSuchElementException exn) {
	st = new StringTokenizer(br.readLine());
      }
    }
  };

  static ArrayList store = new ArrayList();

  static int allocateStore(int n) {
    int l = store.size();
    //    System.out.println("Allocating " + n + " at " + l);
    while (n-- > 0)
      store.add(null);
    return l;
  }

  static void storeSet(int l, int v) {
    //    System.out.println("Storing into " + l);
    store.set(l,new Integer(v));
  }

  static int storeGet(int l) {
    //    System.out.println("Getting " + l);
    return ((Integer) store.get(l)).intValue();
  }

  static int storeValue(int v) {
    int l = allocateStore(1);
    storeSet(l,v);
    return l;
  }

  static void interp(Ast.Program p) throws InterpError {
    store = new ArrayList();
    br = new BufferedReader(new InputStreamReader(System.in));
    st = new StringTokenizer("");
    Env env = Env.empty;
    interp(p.body,env);
  }

  // Return values are as for Ast.St, below
  static Object interp(Ast.Body b,Env env) throws InterpError {
    for (int i = 0; i < b.decslist.length; i++)
      env = interp(b.decslist[i],env);
    return interp(b.statement,env);
  }

  static Env interp(Ast.Decs d, final Env env) throws InterpError {
    class DecsVisitor implements Ast.DecsVisitor {
      public Object visit(Ast.VarDecs d) throws InterpError {
	Env newEnv = env;
	for (int i = 0; i< d.vardeclist.length; i++) {
	  int v = interp(d.vardeclist[i].initializer,newEnv);
	  newEnv = new VarEnv(d.vardeclist[i],storeValue(v),newEnv);
	}
	return newEnv;
      }

      public Object visit(Ast.TypeDecs d) throws InterpError {
	// ...
	return env;  // just temporary
      }

      public Object visit(Ast.ProcDecs d) throws InterpError {
	// ...
	return env; // just temporary
      }
    }
    try {
      return (Env) d.accept(new DecsVisitor());
    } catch (Ast.Error exn) {
      throw (InterpError) exn;
    }
  }

  // Statement interp returns an Object as follows:
  // EXIT statement: EXIT object.
  // RETURN statement without a value: RETURN object.
  // RETURN statement with a value: Integer object containing that value.
  // All other leaf statements: null.
  // Non-leaf statements propagate RETURN and, unless they are loops, EXIT.
  
  static Object EXIT = new Object();
  static Object RETURN = new Object();

  static Object interp(Ast.St s,final Env env) throws InterpError {
    class StVisitor implements Ast.StVisitor {

      public Object visit(Ast.AssignSt s) throws InterpError {
	// ...
	return null;
      }

      public Object visit(Ast.CallSt s) throws InterpError {
	// ...
	return null;
      }

      public Object visit(Ast.ReadSt s) throws InterpError {
	// ...
	return null;
      }

      public Object visit(Ast.WriteSt s) throws InterpError {
	for (int i = 0; i < s.exps.length; i++) {
	  if (s.exps[i] instanceof Ast.StringLitExp) {  // not very "object-oriented" !
	    System.out.print(((Ast.StringLitExp) s.exps[i]).lit);
	  } else {
	    int v = interp(s.exps[i],env);
	    System.out.print(v);  
	  }
	}
	System.out.println();
	return null;
      }

      public Object visit(Ast.IfSt s) throws InterpError {
	// ...
	return null; // just temporary
      }

      public Object visit(Ast.WhileSt s) throws InterpError {
	Object r = null;
	while (r == null) {
	  int v = interp(s.test,env);
	  if (v == 1)
	    r = interp(s.body,env);
	  else
	    break;
	}
	if (r == EXIT)
	  r = null;
	return r;
      }

      public Object visit(Ast.LoopSt s) throws InterpError {
	// ...
	return null; // just temporary
      }

      public Object visit(Ast.ForSt s) throws InterpError {
	// ...
	return null; // just temporary
      }

      public Object visit(Ast.ExitSt s) throws InterpError {
	return EXIT;
      }

      public Object visit(Ast.ReturnSt s) throws InterpError {
	Object v = null;
	if (s.returnValue != null) 
	  return new Integer(interp(s.returnValue,env));
	return RETURN;
      }

      public Object visit(Ast.SequenceSt s) throws InterpError {
	Object r = null;
	for (int i = 0; i < s.statements.length && r == null; i++) 
	  r = interp(s.statements[i],env);
	return r;
      }
    }
    try {
      return s.accept(new StVisitor());
    } catch (Ast.Error exn) {
      throw (InterpError) exn;
    }
  }

  static Object interpCall(String procName, Ast.Exp[] args, Env env) throws InterpError {
    ProcEnv binding = (ProcEnv) find(procName,env);
    Ast.ProcDec pd = (Ast.ProcDec) binding.dec;
    Env newEnv = binding.staticEnv;
    for (int i = 0; i < args.length; i++) {
      int v = interp(args[i],env);
      newEnv = new VarEnv(pd.formals[i],storeValue(v),newEnv);
    }
    return interp(pd.body,newEnv);
  }

  
  // Return value of expression.
  static int interp(Ast.Exp e,final Env env) throws InterpError {
    class ExpVisitor implements Ast.ExpVisitor {

      public Object visit(Ast.BinOpExp e) throws InterpError {
	int r = 0;
	// ...
	int v1 = interp(e.left,env);
	int v2 = interp(e.right,env);
	switch (e.binOp) {
	  // ...
	  case Ast.PLUS:
	    r = v1 + v2;
	    break;
          // ...
	}
	return new Integer(r);
      }

      public Object visit(Ast.UnOpExp e) throws InterpError {
	// ...
	return null; // just temporary
      }

      public Object visit(Ast.LvalExp e) throws InterpError {
	return new Integer(storeGet(interp(e.lval,env)));
      }

      public Object visit(Ast.CallExp e) throws InterpError {
	Object res = interpCall(e.procName,e.args,env);
	if (res == null)
	  throw new InterpError(e.line,"Function call returned no value");
	return res;
      }

      public Object visit(Ast.ArrayExp e) throws InterpError {
	// ...
	return null; // just temporary
      }

      public Object visit(Ast.RecordExp e) throws InterpError {
	int rec = allocateStore(e.initializers.length);
	for (int i = 0; i < e.initializers.length; i++) {
	  int v = interp(e.initializers[i].value,env);
	  storeSet(rec+e.initializers[i].offset,v);
	}
	return new Integer(rec);
      }

      public Object visit(Ast.IntLitExp e) throws InterpError {
	return new Integer(e.lit);
      }
      
      public Object visit(Ast.RealLitExp e) throws InterpError {
	throw new InterpError(e.line,"RealLitExp not supported"); // should never happen
      }

      public Object visit(Ast.StringLitExp e) throws InterpError {
	throw new InterpError(e.line,"Impossible StringLitExp");  // should never happen
      }
    }
    try {
      return ((Integer) e.accept(new ExpVisitor())).intValue();
    } catch (Ast.Error exn) {
      throw (InterpError) exn;
    }
  }

  // Return store location for lvalue.
  static int interp(Ast.Lvalue l, final Env env) throws InterpError {
    class LvalueVisitor implements Ast.LvalueVisitor {

      public Object visit(Ast.VarLvalue l) throws InterpError {
	VarEnv binding = (VarEnv) find(l.name,env);
	return new Integer(binding.location);
      }      

      public Object visit(Ast.ArrayDerefLvalue l) throws InterpError {
	int l0 = interp(l.array,env);
	int base = storeGet(l0);
	int v = interp(l.index,env);
	if (v < 0 || v >= storeGet(base-1))
	  throw new InterpError(l.line,"Array subscript out of bounds");
	return new Integer(base + v);
      }

      public Object visit(Ast.RecordDerefLvalue l) throws InterpError {
	// ...
	return null; // just temporary
      }
    }
    try {
      return ((Integer) l.accept(new LvalueVisitor())).intValue();
    } catch (Ast.Error exn) {
      throw (InterpError) exn;
    }
  }

  static class Env {
    Ast.Dec dec;
    Env next;

    /** Empty environment is just a null Env. */
    static final Env empty = null;

    /** Creates new Env by extending an existing Env with a new declaration binding.
     */
    Env(Ast.Dec dec, Env next) {
      this.dec = dec; this.next = next;
    }

    public String toString() {
      String r = "[ ";
      for (Env env = this; env != null; env = env.next) {
	r += env.dec + "\n";
      }
      r += "]";
      return r;
    }
  }

  static class ProcEnv extends Env {
    Env staticEnv;
    ProcEnv(Ast.Dec dec, Env staticEnv, Env next) {
      super(dec,next); this.staticEnv = staticEnv;
    }
  }

  static class VarEnv extends Env {
    int location;
    VarEnv(Ast.Dec dec, int location, Env next) {
      super(dec,next); this.location = location; 
    }
  }


  static Env find(String name,Env env) {
    for (; env != null; env = env.next)
      if (env.dec.name.equals(name))
	return env;
    return null;
  }

  static class InterpError extends Ast.Error {
    InterpError(int line, String text) {
      super("Error at line " + line + ": " + text);
    }
  }

}





