(* Syntax *)
Definition var := nat.
Definition val := nat.
Inductive expr :=
| Evar: var->expr
| Econst: val ->expr
| Eop: (val->val->val) -> expr -> expr -> expr.
Inductive command :=
| Cskip: command
| Cassign: var -> expr -> command
| Cload: var -> expr -> command
| Cstore: expr -> expr -> command
| Cseq : command -> command -> command
| Cif: expr -> command  -> command -> command
| Cwhile: expr  -> command -> command.
(* Semantics -- stacks, memories, and states *)
Definition stack := var -> option val.
Definition mem := val -> option val.
Definition rho0 : stack := fun _ => None.
Definition m0 : mem := fun _ => None.
Class EqDec (A : Type) : Type := eq_dec : forall a a' : A, {a = a'} + {a <> a'}.
Instance EqDec_nat: EqDec nat.
Instance EqDec_var: EqDec var := _.
Instance EqDec_val: EqDec val := _.
Definition upd{A B}{EA: EqDec A} (f: A -> option B) x y z :=
if eq_dec x z then y else f z.
Inductive state := State: forall (rho: stack) (m: mem) (c: command), state.
Definition stack_of (s: state) := match s with State rho _ _ => rho end.
Definition mem_of (s: state) := match s with State _ m _ => m end.
Definition cmd_of (s: state) := match s with State _ _ c => c end.
(* Operational semantics *)
Inductive eval: expr -> val -> stack -> Prop :=
| Eval_var: forall rho e v, rho e = Some v -> eval (Evar e) v rho
| Eval_const: forall rho v, eval (Econst v) v rho
| Eval_op: forall rho f e1 e2 v1 v2, eval e1 v1 rho -> eval e2 v2 rho ->
eval (Eop f e1 e2) (f v1 v2) rho.
Inductive step: relation state :=
| Step_skip: forall rho m c, step (State rho m (Cseq Cskip c)) (State rho m c)
| Step_assign: forall rho m x e c v, eval e v rho ->
step (State rho m (Cseq (Cassign x e) c)) (State (upd rho x (Some v)) m c)
| Step_load:  forall rho m x e c v v', eval e v rho -> m v = Some v' ->
step (State rho m (Cseq (Cload x e) c)) (State (upd rho x (Some v')) m c)
| Step_store: forall rho m e1 e2 c v1 v2,
eval e1 v1 rho -> eval e2 v2 rho ->
step (State rho m (Cseq (Cstore e1 e2) c)) (State rho (upd m v1 (Some v2)) c)
| Step_seq: forall rho m c1 c2 c,
step (State rho m (Cseq (Cseq c1 c2) c)) (State rho m (Cseq c1 (Cseq c2 c)))
| Step_iftrue: forall rho m e c1 c2 c v, eval e v  rho-> v<>0 ->
step (State rho m (Cseq (Cif e c1 c2) c)) (State rho m (Cseq c1 c))
| Step_iffalse: forall rho m e c1 c2 c, eval e 0 rho ->
step (State rho m (Cseq (Cif e c1 c2) c)) (State rho m (Cseq c2 c))
| Step_whiletrue: forall rho m e c1 c v, eval e v rho -> v<>0 ->
step (State rho m (Cseq (Cwhile e c1) c)) (State rho m (Cseq c1 (Cseq (Cwhile e c1) c)))
| Step_whilefalse: forall rho m e c1 c, eval e 0 rho ->
step (State rho m (Cseq (Cwhile e c1) c)) (State rho m c).
Definition stepstar := clos_refl_trans_1n _ step.
Definition a : var := 0.
Definition run (c: command) (v: val) : Prop :=
exists rho, exists m,
stepstar (State rho0 m0 (Cseq c Cskip)) (State rho m Cskip) /\ rho a = Some v.

(* Specifications: *)
Lemma eval_fun: forall {e rho v1}, eval e v1 rho -> forall {v2}, eval e v2 rho -> v1=v2.
Lemma step_fun: forall {s s1 s2}, step s s1 -> step s s2 -> s1=s2.
Definition h_assert := stack -> Prop.