Fixpoint expr_get (s: locals)(h: heap) (e: expr) : option adr :=
 match e with
 | Const n => Some n
 | Var x => table_get s x
 | Offset e n => do1 v <- expr_get s h e; Some (v+n)
 | Mem e => do1 v <- expr_get s h e; heap_get h v
 end.Fixpoint get_list s h (xs: list expr) : option (list adr) :=
  match xs with
  | nil => Some nil
  | e :: es => do1 v <- expr_get s h e; do1 vs <- get_list s h es; Some (v::vs)
 end.Definition mk_locals  (xs: list var) (ys: list adr) : locals := combine xs ys.Definition state := (locals * heap * control)%type.Definition step (p: program) (sk: state) : option state :=
 match sk with
 | ((stk,hp), Assign (Var x) y c) =>
                           do1 v <- expr_get stk hp y;
                           Some ((table_set x v stk, hp), c)
 | ((stk,hp), Assign (Mem x) y c) =>
                           do1 v <- expr_get stk hp y;
                           do1 p <- expr_get stk hp x;
                           Some ((stk, heap_set p v hp), c)
 | (_, Assign _ y c) => None
 | ((stk,hp), IfThenElse x c1 c2) =>
                           do1 v <- expr_get stk hp x;
                           Some (if eq_dec v 0 then ((stk,hp), c2) else ((stk,hp), c1))
 | ((stk, hp), Go x ys) =>
                           do1 v <- expr_get stk hp x;
                           do1 k <- table_get p v;
                           do1 vs <- get_list stk hp ys;
                           Some ((mk_locals (fst k) vs, hp), snd k)
 end.Fixpoint stepN (p: program) (sk: state) (n: nat) : option state :=
  match n with O => Some sk
  | S n' => match step p sk with Some sk' => stepN p sk' n' | _ => None end
  end.Fixpoint boundary (p: program) : nat :=
  match p with (n, _)::p' => Max.max (S n) (boundary p') | nil => 2 end.Definition initial_locals (p: program) : locals := (0, boundary p)::nil.Definition initial_heap (p: program) : heap :=
    fun i => if lt_dec i (boundary p) then None else Some 0.Definition run (p: program) (n: nat) : option state :=
    stepN p (nil, initial_heap p, Go (Const 0) (Const (boundary p) :: nil)) n.Definition safe (p: program) : Prop :=  forall n, exists sk', run p n = Some sk'.(* LOCAL VARIABLE ENVIRONMENTS *)

Definition env := var -> adr.Definition env_set (f: env) (x: var) (y: adr) :=
   fun i => if eq_dec i x then y else f i.

Lemma env_gso: forall s x y z, x<>z -> env_set s x y z = s z.