Section correctness.
(* We assume each instruction in P is compiled in Q according to the individual instruction compiler combined with what the linker says for branching. This is a *syntactic correctness criterion* for the whole compiled program Q *)
Variables (linker : nat -> nat) (P : nat * list X) (Q : nat * list Y)
(HPQ : forall i I, (i,I::nil) <sc P -> (linker i, icomp linker i I) <sc Q
/\ linker (1+i) = ilen I + linker i).
(* From semantic correctness of individually compiled instructions and syntactic correctness of the whole compiled program, we derive soundness and completeness of the compiled program Q wrt the source program P *)
(* When still inside of P, the computation in Q simulates a computation in P *)
Local Lemma compiler_complete_step p st1 w1 w3 :
snd st1 ⋈ snd w1
-> linker (fst st1) = fst w1
-> in_code (fst st1) P
-> out_code (fst w3) Q
-> Q /Y/ w1 -[p]-> w3
-> exists q st2 w2, snd st2 ⋈ snd w2
/\ linker (fst st2) = fst w2
/\ P /X/ st1 ->> st2
/\ Q /Y/ w2 -[q]-> w3
/\ q < p.
(* Termination in Q simulates termination in P *)
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).

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)
} }.