End correctness.
(** ** A Syntactically Correct Compiler *)
(** Now we build a correct linker & compiled program pair *)
Variable (P : nat * list X) (iQ : nat).
Let iP := fst P.
Let cP := snd P.
Let err := iQ+length_compiler ilen cP.
Definition gen_linker := linker ilen (iP,cP) iQ err.
Definition gen_compiler := compiler icomp ilen (iP,cP) iQ err.
Notation cQ := gen_compiler.
Notation lnk := gen_linker.
Let P_eq : P = (iP,cP).

(* Specifications: *)
Theorem gen_compiler_sound i1 v1 i2 v2 w1 :
v1 ⋈ w1 /\ (iP,cP) /X/ (i1,v1) ~~> (i2,v2)
-> exists w2, v2 ⋈ w2 /\ (iQ,cQ) /Y/ (lnk i1,w1) ~~> (lnk i2,w2).
Theorem gen_compiler_complete i1 v1 w1 :
v1 ⋈ w1 -> (iQ,gen_compiler) /Y/ (gen_linker i1,w1) ↓ -> (iP,cP) /X/ (i1,v1) ↓.
Corollary gen_compiler_output v w i' v' :
v ⋈ w -> (iP,cP) /X/ (iP,v) ~~> (i',v') -> exists w', (iQ,gen_compiler) /Y/ (iQ,w) ~~> (code_end (iQ,cQ),w') /\ v' ⋈ w'.
Corollary gen_compiler_terminates v w :
v ⋈ w -> (iQ,gen_compiler) /Y/ (iQ,w) ↓ -> (iP,cP) /X/ (iP,v) ↓.
Theorem gen_compiler_correction :
{ lnk : nat -> nat
& { Q | fst Q = iQ
/\ lnk iP = iQ
/\ (forall i, out_code i P -> lnk i = code_end Q)
/\ (forall i1 v1 w1 i2 v2, v1 ⋈ w1 /\ P /X/ (i1,v1) ~~> (i2,v2)     -> exists w2,    v2 ⋈ w2 /\ Q /Y/ (lnk i1,w1) ~~> (lnk i2,w2))
/\ (forall i1 v1 w1 j2 w2, v1 ⋈ w1 /\ Q /Y/ (lnk i1,w1) ~~> (j2,w2) -> exists i2 v2, v2 ⋈ w2 /\ P /X/ (i1,v1) ~~> (i2,v2) /\ j2 = lnk i2)
} }.