Asm{{
  public static void p(String s){ System.out.print(s); }
  public static void main(String args[]) throws Exception {
    OpList code = Asm.parse(System.in).c;
    p("\n OpCodes: \n"+code.print()+"\n");
    List<Entry> labels = code.labels();
    p("\n Eval = "+(code.eval(new ExecStack(labels)).top())+"\n");
  }
}}

OpList{{
  public abstract OpList append(Opcode o);
  public abstract OpList append(OpList ol);
  public abstract ExecStack eval(ExecStack s);
  public ExecStack eval(){ return eval(new ExecStack(labels())); }
  OpList prepend(Opcode o){ return new OpCons(o,this); }
  public List<Entry> labels(){ return labels(new Empty<Entry>()); }
  abstract List<Entry> labels(List<Entry> e);
}}

OpCons{{
  public OpList append(Opcode o){ return new OpCons(first, rest.append(o)); }
  public OpList append(OpList ol){ return new OpCons(first, rest.append(ol)); }
  public ExecStack eval(ExecStack s){ return first.eval(s,rest); }
  List<Entry> labels(List<Entry> e){
    return rest.labels((first instanceof Label)?
           e.push(new Entry(((Label)first).id.toString(),rest)):e);
  }
}}

OpEmpty{{
  public OpList append(Opcode o){ return new OpCons(o, this); }
  public OpList append(OpList ol){ return ol; }
  public ExecStack eval(ExecStack s){ return s; }
  List<Entry> labels(List<Entry> e){ return e; }
}}

Opcode{{
  abstract ExecStack eval(ExecStack s);
  ExecStack eval(ExecStack s, OpList cc){ return cc.eval(eval(s)); }
}}

MathOp{{
  int op(int l, int r){ throw new RuntimeException("NYI Opcode"); }
  ExecStack eval(ExecStack s){
    int r = op(s.top(), s.popRes().top());
    return s.popRes().popRes().pushRes(r);
  }
}}

Plus   {{ int op(int l, int r){ return l+r; } }}
Minus  {{ int op(int l, int r){ return l-r; } }}
Times  {{ int op(int l, int r){ return l*r; } }}
Divide {{ int op(int l, int r){ return l/r; } }}
Less   {{ int op(int l, int r){ return (l<r)?1:0; } }}
Greater{{ int op(int l, int r){ return (l>r)?1:0; } }}
Equal  {{ int op(int l, int r){ return (l==r)?1:0; } }}
And    {{ int op(int l, int r){ return ((l&r&1)==1)?1:0; } }}
Or     {{ int op(int l, int r){ return ((l|r&1)==1)?1:0; } }}

Push {{ ExecStack eval(ExecStack s){ return s.pushRes(i); } }}
Pop  {{ ExecStack eval(ExecStack s){ return s.popRes(); } }}
Def  {{ ExecStack eval(ExecStack s){ return s.pushEnv(s.top()).popRes(); } }}
Undef{{ ExecStack eval(ExecStack s){ return s.popEnv(); } }}
Load {{ ExecStack eval(ExecStack s){ return s.pushRes(s.load(i)); } }}

ControlOp{{
  abstract String id();
  abstract boolean branch(ExecStack s);
  ExecStack eval(ExecStack s){ return s; }
  ExecStack eval(ExecStack s, OpList cc){
      if(branch(s))
          return s.labels.find(new Find(id())).pc.eval(s);
      return cc.eval(s);
  }
  static class Find extends List.Pred<Entry>{
      String id;
      Find(String s){ id = s; }
      public boolean huh(Entry e){ return e.label.equals(id); }
  }
}}

Label{{
  String id(){ return ""+id; }
  boolean branch(ExecStack s){ return false; }
}}
Jmp{{
  String id(){ return ""+id; }
  boolean branch(ExecStack s){ return true; }
}}
IfZ{{
  String id(){ return ""+id; }
  boolean branch(ExecStack s){ return (s.top() == 0); }
}}

ExecStack{{
  List<Integer> env = List.create(), result = env;
  List<Entry> labels = List.create();

  public ExecStack(List<Integer> e, List<Integer> r, List<Entry> l)
  { env = e; result = r; labels = l; }
  public ExecStack(List<Entry> e){ this(); labels = e; }
  ExecStack pushEnv(int i){ return make(env.push(i),result); }
  ExecStack pushRes(int i){ return make(env,result.push(i)); }
  ExecStack popEnv(){ return make(env.pop(),result); }
  ExecStack popRes(){ return make(env,result.pop()); }
  int load(int i){ return env.lookup(i); }
  public int top(){ return result.top(); }
  ExecStack make(List<Integer> e, List<Integer> r)
  { return new ExecStack(e,r,labels); }
  public String toString(){
      return "    Env: ["+env+"]\n"+
             "    Res: ["+result+"]\n";
  }
}}
