| Research | Projects Last updated: Wednesday, 26-Apr-2006 12:41:18 MDT |
|
Provable Compiler | |
Progress | |
| I have chosen for my project in the Formal Methods (CS6110) class is to prove a very simple
compiler. This compiler only recognizes four basic statement types: Assignment, Condition,
Loop, and Iterate. An additional statement, Procedure Call, may be added later if time
permits. For a more detailed description, read the proposal (PDF). | |
| The prover will work with two tools, ML and HOL. Since there are many different versions of
HOL and since each appears to work differently, I have made the version I am using through
this download. Please keep in mind that this is
about 7MB. I began working on a tool that will facilitate working with HOL. This tool opens a server socket on a host machine and connects to a HOL session. Eventually, I would like to use a Java client to track a session for the user. | |
| While working on the proof, I had to convince myself that it is possible to prove a compiler "correct". Here (PDF) I used both theoretical and functional methods to demonstrate that a program is an ordered array of statements and a compiler is a composite of transform functions that match up with each program statement. Later, I wrote a program interpreter, compiler, and opcode-evaluator in ML. | |
My effort was to convert the full ML program to a HOL program. (***********************************************************************)
load "intLib";
load "stringLib";
type_abbrev("ID", Type`:string`);
Hol_datatype `operand = Num of int | VarName of ID | Empty`;
Hol_datatype `opcode = opPush of operand | opAdd | opSub | opMul | opDiv | opGt | opGtEq
| opLt | opLtEq | opEq | opNEq | opNeg | opAnd | opOr | opNot | opXor
| opBrT of int| opBrF of int| opJmp of int| opPop of ID | Label of int`;
Hol_datatype `arith_exp =
Term of operand
|Add of arith_exp => arith_exp
|Subtract of arith_exp => arith_exp
|Multiply of arith_exp => arith_exp
|Divide of arith_exp => arith_exp
|Negate of arith_exp`;
Hol_datatype `bool_exp =
Gt of arith_exp => arith_exp
|Lt of arith_exp => arith_exp
|Eq of arith_exp => arith_exp
|LtE of arith_exp => arith_exp
|GtE of arith_exp => arith_exp
|NEq of arith_exp => arith_exp
|And of bool_exp => bool_exp
|Or of bool_exp => bool_exp
|Xor of bool_exp => bool_exp
|Not of bool_exp`;
Hol_datatype `statement =
Assign of ID => arith_exp
|Loop_PreTest of bool_exp => statement list
|Loop_PostTest of statement list => bool_exp
|Iterate of ID => arith_exp => arith_exp => arith_exp => statement list
|If_Then of bool_exp => statement list
|If_Then_Else of bool_exp => statement list => statement list`;
val getnum_def = Define `
(getnum(Num(i)) = i)`;
val STRLT_def = Define `
(STRLT "" s = T) /\
(STRLT (STRING c s) "" = F) /\
(STRLT (STRING c1 t1) (STRING c2 t2) = ORD c1 < ORD c2 /\ STRLT t1 t2)`;
val setvar_def = Define `
(setvar([], n:ID, v:operand) = [(n,v)]) /\
(setvar(((N, V)::List), n, v) =
if STRLT N n then (N,V)::setvar(List, n, v)
else if N = n then (N, v)::List
else (n,v)::(N,V)::List)`;
val getvar_def = Define `
(getvar([], n:ID) = Empty) /\
(getvar(((N, V)::List), n) =
if STRLT N n then getvar(List, n)
else if N = n then V
else Empty)`;
val evalexp_def = Define `
(evalexp(Term(Empty), VarTable) = 0) /\
(evalexp(Term(Num(r)), VarTable) = r) /\
(evalexp(Add A B, VarTable) = evalexp(A, VarTable) + evalexp(B, VarTable)) /\
(evalexp(Subtract A B, VarTable) = evalexp(A, VarTable) - evalexp(B, VarTable)) /\
(evalexp(Multiply A B, VarTable) = evalexp(A, VarTable) * evalexp(B, VarTable)) /\
(evalexp(Divide A B, VarTable) = evalexp(A, VarTable) / evalexp(B, VarTable)) /\
(evalexp(Negate A, VarTable) = ~(evalexp(A, VarTable))) /\
(evalexp(Term(VarName(v)), VarTable) = getnum(getvar(VarTable, v)))`;
val evalbool_def = Define `
(evalbool((Gt A1 A2), VarTable) = evalexp(A1, VarTable) > evalexp(A2, VarTable)) /\
(evalbool((Lt A1 A2), VarTable) = evalexp(A1, VarTable) < evalexp(A2, VarTable)) /\
(evalbool((Eq A1 A2), VarTable) = (evalexp(A1, VarTable) = evalexp(A2, VarTable))) /\
(evalbool((LtE A1 A2), VarTable) = evalexp(A1, VarTable) <= evalexp(A2, VarTable)) /\
(evalbool((GtE A1 A2), VarTable) = evalexp(A1, VarTable) >= evalexp(A2, VarTable)) /\
(evalbool((NEq A1 A2), VarTable) = ~((evalexp(A1, VarTable)) = (evalexp(A2, VarTable)))) /\
(evalbool((And B1 B2), VarTable) = evalbool(B1, VarTable) /\ evalbool(B2, VarTable)) /\
(evalbool((Or B1 B2), VarTable) = evalbool(B1, VarTable) \/ evalbool(B2, VarTable)) /\
(evalbool((Xor B1 B2), VarTable) = ~(evalbool(B1, VarTable) = evalbool(B2, VarTable))) /\
(evalbool((Not B), VarTable) = ~(evalbool(B, VarTable)))`;
val defn = Hol_defn "evaluate1" `
(evaluate1(0n, _, VarTable) = VarTable) /\
(evaluate1(_, [], VarTable) = VarTable) /\
(evaluate1(N, ((Assign Var Exp)::Program), VarTable) =
evaluate1(N-1, Program, setvar(VarTable, Var, Num(evalexp(Exp, VarTable))))) /\
(evaluate1(N, ((If_Then B_exp St)::Program), VarTable) =
if evalbool(B_exp, VarTable)
then evaluate1(N-1, Program, evaluate1(N-1, St, VarTable))
else evaluate1(N-1, Program, VarTable)) /\
(evaluate1(N, ((If_Then_Else B_exp St Sf)::Program), VarTable) =
if evalbool(B_exp, VarTable)
then evaluate1(N-1, Program, evaluate1(N-1, St, VarTable))
else evaluate1(N-1, Program, evaluate1(N-1, Sf, VarTable))) /\
(evaluate1(N, ((Loop_PreTest B_exp St)::Program), VarTable) =
if evalbool(B_exp, VarTable)
then evaluate1(N-1, ((Loop_PreTest B_exp St)::Program), evaluate1(N-1, St, VarTable))
else evaluate1(N-1, Program, VarTable)) /\
(evaluate1(N, ((Loop_PostTest St B_exp)::Program), VarTable) =
let VarTable = evaluate1(N-1, St, VarTable) in
if evalbool(B_exp, VarTable)
then evaluate1(N-1, ((Loop_PostTest St B_exp)::Program), evaluate1(N-1, St, VarTable))
else evaluate1(N-1, Program, VarTable)
) /\
(evaluate1(N, ((Iterate Var Low High Inc St)::Program), VarTable) =
let VarTable = setvar(VarTable, Var, Num(evalexp(Low, VarTable))) in
let NewLow = Term(Num(evalexp(Add Low Inc, VarTable))) in
if evalbool(GtE Low High, VarTable)
then evaluate1(N-1, ((Iterate Var NewLow High Inc St)::Program), evaluate1(N-1, St, VarTable))
else evaluate1(N-1, Program, VarTable))`;
val (evaluate1_def, evaluate1_ind) = Defn.tprove(defn, WF_REL_TAC `measure FST`);
val evaluate_def = Define `
(evaluate(Program, State) = ?n. evaluate1(n, Program, []) = State)`;
val compexp_def = Define `
(compexp(Term(Empty)) = [opPush(Empty)]) /\
(compexp(Term(Num(r))) = [opPush(Num(r))]) /\
(compexp(Term(VarName(v))) = [opPush(VarName(v))]) /\
(compexp(Add A B) = compexp(A) ++ compexp(B) ++ [opAdd]) /\
(compexp(Subtract A B) = compexp(A) ++ compexp(B) ++ [opSub]) /\
(compexp(Multiply A B) = compexp(A) ++ compexp(B) ++ [opMul]) /\
(compexp(Divide A B) = compexp(A) ++ compexp(B) ++ [opDiv]) /\
(compexp(Negate A) = compexp(A) ++ [opNeg])`;
val compbool_def = Define `
(compbool(Gt A1 A2) = compexp(A1) ++ compexp(A2) ++ [opGt]) /\
(compbool(Lt A1 A2) = compexp(A1) ++ compexp(A2) ++ [opLt]) /\
(compbool(Eq A1 A2) = compexp(A1) ++ compexp(A2) ++ [opEq]) /\
(compbool(LtE A1 A2) = compexp(A1) ++ compexp(A2) ++ [opLtEq]) /\
(compbool(GtE A1 A2) = compexp(A1) ++ compexp(A2) ++ [opGtEq]) /\
(compbool(NEq A1 A2) = compexp(A1) ++ compexp(A2) ++ [opNEq]) /\
(compbool(And B1 B2) = compbool(B1) ++ compbool(B2) ++ [opAnd]) /\
(compbool(Or B1 B2) = compbool(B1) ++ compbool(B2) ++ [opOr]) /\
(compbool(Xor B1 B2) = compbool(B1) ++ compbool(B2) ++ [opXor]) /\
(compbool(Not B) = compbool(B) ++ [opNot])`;
val defn = Hol_defn "compile1" `
(compile1([], label) = ([], label)) /\
(compile1(((Assign Var Exp)::Program), label) =
let (prog_ops, label) = compile1(Program, label) in
( compexp(Exp) ++
[opPop Var] ++
prog_ops, label )) /\
(compile1(((If_Then B_exp St)::Program), label) =
let DoneLabel = label in
let (stmt_ops, label) = compile1(St, label+1) in
let (prog_ops, label) = compile1(Program, label) in
( compbool(B_exp) ++
[opBrF DoneLabel] ++
stmt_ops ++
[Label DoneLabel] ++
prog_ops, label )) /\
(compile1(((If_Then_Else B_exp St Sf)::Program), label) =
let ElseLabel = label in
let DoneLabel = label+1 in
let (stmtT_ops, label) = compile1(St, label+2) in
let (stmtF_ops, label) = compile1(Sf, label) in
let (prog_ops, label) = compile1(Program, label) in
( compbool(B_exp) ++
[opBrF ElseLabel] ++
stmtT_ops ++
[opJmp DoneLabel] ++
[Label ElseLabel] ++
stmtF_ops ++
[Label DoneLabel] ++
prog_ops, label)) /\
(compile1(((Loop_PreTest B_exp St)::Program), label) =
let TestLabel = label in
let DoneLabel = label+1 in
let (stmt_ops, label) = compile1(St, label+2) in
let (prog_ops, label) = compile1(Program, label) in
( [Label TestLabel] ++
compbool(B_exp) ++
[opBrF DoneLabel] ++
stmt_ops ++
[opJmp TestLabel] ++
[Label DoneLabel] ++
prog_ops, label )) /\
(compile1(((Loop_PostTest St B_exp)::Program), label) =
let TestLabel = label in
let (stmt_ops, label) = compile1(St, label+1) in
let (prog_ops, label) = compile1(Program, label) in
( [Label TestLabel] ++
stmt_ops ++
compbool(B_exp) ++
[opBrT TestLabel] ++
prog_ops, label )) /\
(compile1(((Iterate Var El Eh Ei St)::Program), label) =
let AssignLabel = label in
let DoneLabel = label+1 in
let (stmt_ops, label) = compile1(St, label+2) in
let (prog_ops, label) = compile1(Program, label) in
( compexp(El) ++
[Label AssignLabel] ++
[opPop(Var)] ++
compexp(Eh) ++
[opPush (VarName Var)] ++
[opGt] ++
[opBrT DoneLabel] ++
stmt_ops ++
compexp(Ei) ++
[opPush (VarName Var)] ++
[opAdd] ++
[opJmp AssignLabel] ++
[Label DoneLabel] ++
prog_ops, label ))`;
val statement_size_def = fetch "-" "statement_size_def";
val list_size_def = listTheory.list_size_def;
val list_size_eq_statement1_size =
Q.prove (`!sl. list_size statement_size sl = statement1_size sl`, Induct
THEN RW_TAC list_ss [statement_size_def,list_size_def]);
val (compile1_def, compile1_ind) =
Defn.tprove (defn, WF_REL_TAC `measure (list_size statement_size o FST)`
THEN RW_TAC arith_ss [list_size_eq_statement1_size]);
val compile_def = Define `
(compile(Program) =
let (oplist, lbl) = compile1(Program, 1) in
oplist)`;
val findlabel_def = Define `
(findlabel([], L) = []) /\
(findlabel((Label(l)::P), L) = if l = L then P else findlabel(P, L)) /\
(findlabel((_::P), L) = findlabel(P, L))`;
val defn = Hol_defn "interpret1" `
(interpret1(0n, _, _, VarTable, _) = VarTable) /\
(interpret1(_, _, [], VarTable, _) = VarTable) /\
(interpret1(N, WOpcodes, (opPush(Empty)::Opcodes), VarTable, Q) =
interpret1(N-1, WOpcodes, Opcodes, VarTable, Q)) /\
(interpret1(N, WOpcodes, (opPush(Num Val)::Opcodes), VarTable, Q) =
interpret1(N-1, WOpcodes, Opcodes, VarTable, [(Num Val)] ++ Q)) /\
(interpret1(N, WOpcodes, (opPush(VarName Var)::Opcodes), VarTable, Q) =
interpret1(N-1, WOpcodes, Opcodes, VarTable, [getvar(VarTable, Var)] ++ Q)) /\
(interpret1(N, WOpcodes, ((opPop Var)::Opcodes), VarTable, (op1::Q)) =
interpret1(N-1, WOpcodes, Opcodes, setvar(VarTable, Var, op1), Q)) /\
(interpret1(N, WOpcodes, (opAdd::Opcodes), VarTable, ((Num val1)::(Num val2)::Q)) =
interpret1(N-1, WOpcodes, Opcodes, VarTable, [Num(val1+val2)] ++ Q)) /\
(interpret1(N, WOpcodes, (opSub::Opcodes), VarTable, ((Num val1)::(Num val2)::Q)) =
interpret1(N-1, WOpcodes, Opcodes, VarTable, [Num(val1-val2)] ++ Q)) /\
(interpret1(N, WOpcodes, (opDiv::Opcodes), VarTable, ((Num val1)::(Num val2)::Q)) =
interpret1(N-1, WOpcodes, Opcodes, VarTable, [Num(val1/val2)] ++ Q)) /\
(interpret1(N, WOpcodes, (opMul::Opcodes), VarTable, ((Num val1)::(Num val2)::Q)) =
interpret1(N-1, WOpcodes, Opcodes, VarTable, [Num(val1*val2)] ++ Q)) /\
(interpret1(N, WOpcodes, (opGt::Opcodes), VarTable, ((Num val1)::(Num val2)::Q)) =
interpret1(N-1, WOpcodes, Opcodes, VarTable, [Num(if val1 | |
Then, I tried a smaller ML program to a HOL program. (***************************************HOL PROGRAM***************************************)
load "intLib";
load "stringLib";
type_abbrev("ID", Type`:string`);
Hol_datatype `operand = Num of num | VarName of ID | Empty`;
Hol_datatype `opcode = opPush of operand | opAdd | opPop of ID `;
Hol_datatype `arith_exp =
Term of operand
|Add of arith_exp => arith_exp`;
Hol_datatype `statement =
Assign of ID => arith_exp`;
val getnum_def = Define `
(getnum(Num(i)) = i)`;
val STRLT_def = Define `
(STRLT "" s = T) /\
(STRLT (STRING c s) "" = F) /\
(STRLT (STRING c1 t1) (STRING c2 t2) = ORD c1 < ORD c2 /\ STRLT t1 t2)`;
val setvar_def = Define `
(setvar(a, _, VarName(_)) = a) /\
(setvar([], n:ID, v:operand) = [(n,v)]) /\
(setvar(((N, V)::List), n, v) =
if STRLT N n then (N,V)::setvar(List, n, v)
else if N = n then (N, v)::List
else (n,v)::(N,V)::List)`;
val getvar_def = Define `
(getvar([], n:ID) = Empty) /\
(getvar(((N, V)::List), n) =
if STRLT N n then getvar(List, n)
else if N = n then V
else Empty)`;
val evaladd_def = Define `
(evaladd(Num(x), Num(y)) = Num(x+y)) /\
(evaladd(_, _) = Empty)`;
val evalexp_def = Define `
(evalexp(Term(Empty), _) = Empty) /\
(evalexp(Term(Num(r)), _) = Num(r)) /\
(evalexp(Add A B, VarTable) = evaladd(evalexp(A, VarTable), evalexp(B, VarTable))) /\
(evalexp(Term(VarName(v)), VarTable) = getvar(VarTable, v))`;
val evaluate1_def = Define `
(evaluate1([], VarTable) = VarTable) /\
(evaluate1(((Assign Var Exp)::Program), VarTable) =
evaluate1(Program, setvar(VarTable, Var, evalexp(Exp, VarTable))))`;
val evaluate1_ind = fetch "-" "evaluate1_ind";
val evaluate_def = Define `
(evaluate(Program) = evaluate1(Program, []))`;
val compexp_def = Define `
(compexp(Term(Empty)) = [opPush(Empty)]) /\
(compexp(Term(Num(r))) = [opPush(Num(r))]) /\
(compexp(Term(VarName(v))) = [opPush(VarName(v))]) /\
(compexp(Add A B) = compexp(A) ++ compexp(B) ++ [opAdd])`;
val compile1_def = Define `
(compile1([]) = ([])) /\
(compile1(((Assign Var Exp)::Program)) =
compexp(Exp) ++
[opPop Var] ++
compile1(Program) )`;
val compile1_ind = fetch "-" "compile1_ind";
val compile_def = Define `
(compile(Program) = compile1(Program))`;
val interpret1_def = Define `
(interpret1(((opPop Var)::Opcodes), VarTable, []) =
interpret1(Opcodes, setvar(VarTable, Var, Empty), [])) /\
(interpret1([], VarTable, _) = VarTable) /\
(interpret1((opPush(Empty)::Opcodes), VarTable, Q) =
interpret1(Opcodes, VarTable, Q)) /\
(interpret1((opPush(Num Val)::Opcodes), VarTable, Q) =
interpret1(Opcodes, VarTable, [(Num Val)] ++ Q)) /\
(interpret1((opPush(VarName Var)::Opcodes), VarTable, Q) =
interpret1(Opcodes, VarTable, [getvar(VarTable, Var)] ++ Q)) /\
(interpret1(((opPop Var)::Opcodes), VarTable, (op1::Q)) =
interpret1(Opcodes, setvar(VarTable, Var, op1), Q)) /\
(interpret1((opAdd::Opcodes), VarTable, []) =
interpret1(Opcodes, VarTable, [Empty])) /\
(interpret1((opAdd::Opcodes), VarTable, [_]) =
interpret1(Opcodes, VarTable, [Empty])) /\
(interpret1((opAdd::Opcodes), VarTable, ((Num val1)::(Num val2)::Q)) =
interpret1(Opcodes, VarTable, [Num(val1+val2)] ++ Q)) /\
(interpret1((opAdd::Opcodes), VarTable, (_::_::Q)) =
interpret1(Opcodes, VarTable, [Empty] ++ Q))`;
val interpret1_ind = fetch "-" "interpret1_ind";
val interpret_def = Define `
(interpret(Opcodes) = interpret1(Opcodes, [], []))`;
(*******************************************PROOF*******************************************)
g `!prog p state1 state2.
(p = compile prog) /\ (interpret(p) = state1) /\ (evaluate(prog) = state2) ==> (state1 = state2)`;
e (SIMP_TAC std_ss [compile_def, interpret_def, evaluate_def]);
e (recInduct compile1_ind);
e (FULL_SIMP_TAC std_ss [compile1_def, interpret1_def, evaluate1_def]);
e (GEN_TAC);
e (Induct_on `Program`);
e (RW_TAC std_ss [compile1_def, evaluate1_def, interpret1_def]);
e (Induct_on `Exp`);
e (GEN_TAC);
e (SIMP_TAC list_ss [setvar_def]);
Parse.hide "o";
e (Cases_on `$o` THEN RW_TAC list_ss [evalexp_def, compexp_def, setvar_def, getvar_def, interpret1_def]);
e (RW_TAC list_ss [compexp_def, evalexp_def, evaladd_def]);
e (FULL_SIMP_TAC list_ss []);
e (Induct_on `Exp`);
e GEN_TAC;
e (Induct_on `Exp'`);
e GEN_TAC;
e (RW_TAC list_ss [evalexp_def]);
e (Cases_on `$o`);
e (Cases_on `o'` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o'` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o'` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (RW_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `$o` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `Exp'`);
e (Cases_on `Exp''`);
e (Cases_on `o'`);
e (Cases_on `o''` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o''` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o''` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o'`);
e (Cases_on `a`);
e (Cases_on `a0`);
e (Cases_on `o''` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o''` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o''` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o'`);
e (Cases_on `a`);
e (Cases_on `a0'`);
e (Cases_on `o'`);
e (Cases_on `o''` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o''` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o''` THEN FULL_SIMP_TAC list_ss [evalexp_def, getvar_def, interpret1_def, setvar_def, compexp_def, evaladd_def]);
e (Cases_on `o'`);
e (Cases_on `a`);
e (Cases_on `a0`);
(*--------------------------Lemma: recursive proof of interpret1()--------------------------*)
g `!X Y V Q. interpret1(X ++ Y::Prog, V, Q) = interpret1(Y::Prog,interpret1(X, V, Q), Q)`;
e (RW_TAC list_ss []);
e (Induct_on `X`);
e (RW_TAC list_ss [interpret1_def]);
e (Cases_on `h`);
e (Cases_on `o'` THEN RW_TAC list_ss [interpret1_def, getvar_def, setvar_def]);
| |
My effort was to convert the tiny ML program to a HOL program. Parse.hide "o";
load "stringLib";
type_abbrev("ID", Type`:string`);
Hol_datatype `operand = Num of num | Empty`;
Hol_datatype `opcode = opAdd | opPush of operand`;
Hol_datatype `arith_exp = Term of operand |Add of arith_exp => arith_exp`;
Hol_datatype `statement = Assign of ID => arith_exp`;
val interpAdd_def = Define `
(interpAdd(Num(x), Num(y)) = Num(x+y)) /\
(interpAdd(_, _) = Empty)`;
val interpExp_def = Define `
(interpExp(Term(Empty)) = Empty) /\
(interpExp(Term(Num(r))) = Num(r)) /\
(interpExp(Add A B) = interpAdd(interpExp(A), interpExp(B)))`;
val interpExp_ind = fetch "-" "interpExp_ind";
val compExp_def = Define `
(compExp(Term(Empty)) = [opPush(Empty)]) /\
(compExp(Term(Num(r))) = [opPush(Num(r))]) /\
(compExp(Add A B) = compExp(A) ++ compExp(B) ++ [opAdd])`;
val evaluate_def = Define `
(evaluate((opPush(Empty)::Opcodes), Q) = evaluate(Opcodes, Q)) /\
(evaluate((opPush(Num Val)::Opcodes), Q) = evaluate(Opcodes, [(Num Val)] ++ Q)) /\
(evaluate((opAdd::Opcodes), val1::val2::Q) = evaluate(Opcodes, [interpAdd(val1, val2)] ++ Q)) /\
(* (evaluate((opAdd::Opcodes), ((Num val1)::(Num val2)::Q)) = evaluate(Opcodes, [Num(val1+val2)] ++ Q)) /\*)
(* (evaluate((_::Opcodes), (_::_::Q)) = evaluate(Opcodes, [Empty] ++ Q)) /\*)
(evaluate((_::Opcodes), [_]) = evaluate(Opcodes, [Empty])) /\
(evaluate((_::Opcodes), []) = evaluate(Opcodes, [Empty])) /\
(evaluate([], top::Q) = top) /\
(evaluate([], []) = Empty)`;
val evaluate_ind = fetch "-" "evaluate_ind";
(*----------------------------------------------------------------------------*)
val comp_ss = list_ss ++ rewrites [interpAdd_def, interpExp_def, compExp_def, evaluate_def];
g `!oplist prog. (oplist = compExp prog) ==> (evaluate(oplist, []) = interpExp(prog))`;
e (FULL_SIMP_TAC comp_ss []);
e Induct;
e (Cases_on `$o` THEN FULL_SIMP_TAC comp_ss []);
e (RW_TAC comp_ss []);
g `evaluate(A ++ [opAdd], []) = evaluate([opAdd] ++ [evaluate(A, [])], [])`;
g `!prog oplist op. (oplist = compExp prog) /\ (op::L = oplist) ==> ~(op = opAdd)`;
e (Induct_on `prog` THEN FULL_SIMP_TAC comp_ss []);
e (Cases_on `$o` THEN RW_TAC comp_ss []);
g `!p p'. Add(p p') ==> | |
With Konrad's significant help, we came up with this final tiny ML program HOL program. Parse.hide "o";
load "stringLib";
type_abbrev("ID", Type`:string`);
Hol_datatype `operand = Num of num | Empty`;
Hol_datatype `opcode = opAdd | opPush of operand`;
Hol_datatype `arith_exp = Term of operand | Add of arith_exp => arith_exp`;
Hol_datatype `statement = Assign of ID => arith_exp`;
val interpAdd_def = Define `
(interpAdd(Num(x), Num(y)) = Num(x+y)) /\
(interpAdd(_, _) = Empty)`;
val interpExp_def = Define `
(interpExp(Term(Empty)) = Empty) /\
(interpExp(Term(Num(r))) = Num(r)) /\
(interpExp(Add A B) = interpAdd(interpExp(A), interpExp(B)))`;
val interpExp_ind = fetch "-" "interpExp_ind";
val compExp_def = Define `
(compExp(Term(Empty)) = [opPush(Empty)]) /\
(compExp(Term(Num(r))) = [opPush(Num(r))]) /\
(compExp(Add A B) = compExp(A) ++ compExp(B) ++ [opAdd])`;
val evaluate_def = Define `
(evaluate((opPush(Empty)::Opcodes), Q) = evaluate(Opcodes, Q)) /\
(evaluate((opPush(Num Val)::Opcodes), Q) = evaluate(Opcodes, [(Num Val)] ++ Q)) /\
(evaluate((opAdd::Opcodes), val1::val2::Q) = evaluate(Opcodes, [interpAdd(val1, val2)] ++ Q)) /\
(* (evaluate((opAdd::Opcodes), ((Num val1)::(Num val2)::Q)) = evaluate(Opcodes, [Num(val1+val2)] ++ Q)) /\*)
(* (evaluate((_::Opcodes), (_::_::Q)) = evaluate(Opcodes, [Empty] ++ Q)) /\*)
(evaluate((_::Opcodes), [_]) = evaluate(Opcodes, [Empty])) /\
(evaluate((_::Opcodes), []) = evaluate(Opcodes, [Empty])) /\
(evaluate([], top::Q) = top) /\
(evaluate([], []) = Empty)`;
val evaluate_ind = fetch "-" "evaluate_ind";
(*----------------------------------------------------------------------------*)
val comp_ss = list_ss ++ rewrites [interpAdd_def, interpExp_def, compExp_def, evaluate_def];
g `!oplist prog. (oplist = compExp prog) ==> (evaluate(oplist, []) = interpExp(prog))`;
e (FULL_SIMP_TAC comp_ss []);
e Induct;
e (Cases_on `$o` THEN FULL_SIMP_TAC comp_ss []);
e (RW_TAC comp_ss []);
g `evaluate(A ++ [opAdd], []) = evaluate([opAdd] ++ [evaluate(A, [])], [])`;
g `!prog oplist op. (oplist = compExp prog) /\ (op::L = oplist) ==> ~(op = opAdd)`;
e (Induct_on `prog` THEN FULL_SIMP_TAC comp_ss []);
e (Cases_on `$o` THEN RW_TAC comp_ss []);
load "stringLib";
open listTheory;
map hide ["o", "C"];
Hol_datatype `aexp = Var of string | Const of num | Add of aexp => aexp`;
Hol_datatype `atom = V of string | C of num`;
Hol_datatype `opcode = opAdd | opPush of atom`;
val evalExp_def =
Define
`(evalExp env (Var s) = env s :num) /\
(evalExp env (Const n) = n) /\
(evalExp env (Add e1 e2) = evalExp env e1 + evalExp env e2)`;
val compExp_def =
Define
`(compExp (Var s) = [opPush (V s)]) /\
(compExp (Const n) = [opPush (C n)]) /\
(compExp (Add e1 e2) = compExp e2 ++ compExp e1 ++ [opAdd])`;
val Int_def =
Define
`(Int env [] stk = stk) /\
(Int env (opPush(V s)::opcodes) stk = Int env opcodes (env s :: stk)) /\
(Int env (opPush(C n)::opcodes) stk = Int env opcodes (n :: stk)) /\
(Int env (opAdd::opcodes) (v1::v2::stk) = Int env opcodes (v1+v2::stk))`;
val Int_ind = fetch "-" "Int_ind";
val comp_ss = list_ss ++ rewrites [evalExp_def, compExp_def, Int_def];
(*---------------------------------------------------------------------------*)
(* Lemmas *)
(*---------------------------------------------------------------------------*)
val compExp_not_empty = Q.prove
(`!e. ~NULL (compExp e)`,
Induct THEN RW_TAC comp_ss [] THEN
Cases_on `compExp e'` THEN FULL_SIMP_TAC comp_ss []);
val NOT_NULL = Q.prove
(`!l. ~NULL l ==> ?h t. l = h::t`,
Cases THEN RW_TAC list_ss []);
val NULL_EMPTY_LEM = Q.prove
(`!l. NULL l = (l=[])`,
Cases THEN RW_TAC list_ss []);
val compExp_hd_not_Add = Q.prove
(`!e. ~(HD (compExp e) = opAdd)`,
Induct THEN RW_TAC comp_ss [] THEN
`?h t. compExp e' = h::t` by METIS_TAC [compExp_not_empty, NOT_NULL] THEN
POP_ASSUM SUBST_ALL_TAC THEN FULL_SIMP_TAC comp_ss []);
val THE_LEMMA = Q.prove
(`!e env stk rst.
Int env (compExp e ++ rst) stk =
Int env rst (evalExp env e::stk)`,
Induct THEN RW_TAC comp_ss [] THEN
ASM_REWRITE_TAC [GSYM APPEND_ASSOC] THEN
RW_TAC comp_ss []);
val Correctness = Q.prove
(`!e env stk h stk'.
(Int env (compExp e) stk = h::stk') ==> (h = evalExp env e)`,
Induct THEN RW_TAC comp_ss []
THEN RULE_ASSUM_TAC (REWRITE_RULE [GSYM APPEND_ASSOC])
THEN FULL_SIMP_TAC comp_ss [THE_LEMMA]);
| |
| Copyright © 2001-2006 Intelligent Algorithmic Solutions and Sean Walton | |