Add LoadPath "../..".
Definition table (A B : Type) := list (A*B).
Fixpoint table_get {A B}{H: EqDec A} (rho: table A B) (x: A) : option B :=
match rho with
| (y,v)::ys => if eq_dec x y then Some v else table_get ys x
| nil => None
end.
Definition table_set {A B}{H: EqDec A} (x: A) (v: B) (rho: table A B)  : table A B := (x,v)::rho.
Definition var := nat.
Definition adr := nat.
Definition stack := table var adr.
Definition heap := table adr adr.
Definition state := (stack * heap)%type.
Inductive command :=
| Skip : command
| Assign: var -> var -> command
| Load : var -> var -> command
| Store: var -> var -> command
| Seq: command -> command -> command.
Inductive step: relation (command * state) :=
| stepAssign:
forall x y v stk hp,
table_get stk y = Some v ->
step (Assign x y, (stk,hp)) (Skip, (table_set x v stk, hp))
| stepLoad:
forall x y v v' stk hp,
table_get stk y = Some v ->
table_get hp v = Some v' ->
step (Load x y, (stk,hp)) (Skip, (table_set x v' stk, hp))
| stepStore:
forall x y v p stk hp,
table_get stk y = Some v ->
table_get stk x = Some p ->
step (Store x y, (stk,hp)) (Skip, (stk, table_set p v hp))
| stepSeq0:
forall c2 s,
step (Seq Skip c2, s) (c2, s)
| stepSeq1:
forall c1 c1' c2 s s',
step (c1,s) (c1',s') ->
step (Seq c1 c2, s) (Seq c1' c2, s').
Inductive step': relation (list command * state)  :=
| step'Skip:
forall k s,
step' (Skip :: k, s) (k,s)
| step'Assign:
forall x y v stk hp k,
table_get stk y = Some v ->
step' (Assign x y :: k, (stk,hp)) (k, (table_set x v stk, hp))
| step'Load:
forall x y v v' stk hp k,
table_get stk y = Some v ->
table_get hp v = Some v' ->
step' (Load x y :: k, (stk,hp)) (k, (table_set x v' stk, hp))
| step'Store:
forall x y v p stk hp k,
table_get stk y = Some v ->
table_get stk x = Some p ->
step' (Store x y :: k, (stk,hp)) (k, (stk, table_set p v hp))
| step'Seq:
forall c1 c2 k s cs',
step' (c1 :: c2 ::k, s) cs' ->
step' (Seq c1 c2 :: k, s) cs'.
Fixpoint stackit (k: list command) (c: command) : command :=
match k with
| nil => c
| c'::k' => stackit k' (Seq c c')
end.
Definition stackit' (k: list command) : command :=
match k with nil => Skip | c::k' => stackit k' c end.
(* Eval compute in stackit' (Skip :: Assign 0 1 :: Assign 0 2 :: Assign 0 3 :: nil). *)
Ltac inv H := inversion H; clear H; subst.

Lemma stackit_step:
forall s s' k c c',
step (c,s) (c',s') -> step (stackit k c, s) (stackit k c', s').