16 datatype ('a,'v)expr = Cex 'v |
16 datatype ('a,'v)expr = Cex 'v |
17 | Vex 'a |
17 | Vex 'a |
18 | Bex "'v binop" "('a,'v)expr" "('a,'v)expr"; |
18 | Bex "'v binop" "('a,'v)expr" "('a,'v)expr"; |
19 |
19 |
20 text{*\noindent |
20 text{*\noindent |
21 The three constructors represent constants, variables and the combination of |
21 The three constructors represent constants, variables and the application of |
22 two subexpressions with a binary operation. |
22 a binary operation to two subexpressions. |
23 |
23 |
24 The value of an expression w.r.t.\ an environment that maps variables to |
24 The value of an expression w.r.t.\ an environment that maps variables to |
25 values is easily defined: |
25 values is easily defined: |
26 *} |
26 *} |
27 |
27 |
28 consts value :: "('a \\<Rightarrow> 'v) \\<Rightarrow> ('a,'v)expr \\<Rightarrow> 'v"; |
28 consts value :: "('a,'v)expr \\<Rightarrow> ('a \\<Rightarrow> 'v) \\<Rightarrow> 'v"; |
29 primrec |
29 primrec |
30 "value env (Cex v) = v" |
30 "value (Cex v) env = v" |
31 "value env (Vex a) = env a" |
31 "value (Vex a) env = env a" |
32 "value env (Bex f e1 e2) = f (value env e1) (value env e2)"; |
32 "value (Bex f e1 e2) env = f (value e1 env) (value e2 env)"; |
33 |
33 |
34 text{* |
34 text{* |
35 The stack machine has three instructions: load a constant value onto the |
35 The stack machine has three instructions: load a constant value onto the |
36 stack, load the contents of a certain address onto the stack, and apply a |
36 stack, load the contents of a certain address onto the stack, and apply a |
37 binary operation to the two topmost elements of the stack, replacing them by |
37 binary operation to the two topmost elements of the stack, replacing them by |
41 datatype ('a,'v) instr = Const 'v |
41 datatype ('a,'v) instr = Const 'v |
42 | Load 'a |
42 | Load 'a |
43 | Apply "'v binop"; |
43 | Apply "'v binop"; |
44 |
44 |
45 text{* |
45 text{* |
46 The execution of the stack machine is modelled by a function \isa{exec} |
46 The execution of the stack machine is modelled by a function |
47 that takes a store (modelled as a function from addresses to values, just |
47 \isa{exec} that takes a list of instructions, a store (modelled as a |
48 like the environment for evaluating expressions), a stack (modelled as a |
48 function from addresses to values, just like the environment for |
49 list) of values, and a list of instructions, and returns the stack at the end |
49 evaluating expressions), and a stack (modelled as a list) of values, |
50 of the execution---the store remains unchanged: |
50 and returns the stack at the end of the execution---the store remains |
|
51 unchanged: |
51 *} |
52 *} |
52 |
53 |
53 consts exec :: "('a\\<Rightarrow>'v) \\<Rightarrow> 'v list \\<Rightarrow> ('a,'v)instr list \\<Rightarrow> 'v list"; |
54 consts exec :: "('a,'v)instr list \\<Rightarrow> ('a\\<Rightarrow>'v) \\<Rightarrow> 'v list \\<Rightarrow> 'v list"; |
54 primrec |
55 primrec |
55 "exec s vs [] = vs" |
56 "exec [] s vs = vs" |
56 "exec s vs (i#is) = (case i of |
57 "exec (i#is) s vs = (case i of |
57 Const v \\<Rightarrow> exec s (v#vs) is |
58 Const v \\<Rightarrow> exec is s (v#vs) |
58 | Load a \\<Rightarrow> exec s ((s a)#vs) is |
59 | Load a \\<Rightarrow> exec is s ((s a)#vs) |
59 | Apply f \\<Rightarrow> exec s ( (f (hd vs) (hd(tl vs)))#(tl(tl vs)) ) is)"; |
60 | Apply f \\<Rightarrow> exec is s ((f (hd vs) (hd(tl vs)))#(tl(tl vs))))"; |
60 |
61 |
61 text{*\noindent |
62 text{*\noindent |
62 Recall that \isa{hd} and \isa{tl} |
63 Recall that \isa{hd} and \isa{tl} |
63 return the first element and the remainder of a list. |
64 return the first element and the remainder of a list. |
64 Because all functions are total, \isa{hd} is defined even for the empty |
65 Because all functions are total, \isa{hd} is defined even for the empty |
79 |
80 |
80 text{* |
81 text{* |
81 Now we have to prove the correctness of the compiler, i.e.\ that the |
82 Now we have to prove the correctness of the compiler, i.e.\ that the |
82 execution of a compiled expression results in the value of the expression: |
83 execution of a compiled expression results in the value of the expression: |
83 *} |
84 *} |
84 theorem "exec s [] (comp e) = [value s e]"; |
85 theorem "exec (comp e) s [] = [value e s]"; |
85 (*<*)oops;(*>*) |
86 (*<*)oops;(*>*) |
86 text{*\noindent |
87 text{*\noindent |
87 This theorem needs to be generalized to |
88 This theorem needs to be generalized to |
88 *} |
89 *} |
89 |
90 |
90 theorem "\\<forall>vs. exec s vs (comp e) = (value s e) # vs"; |
91 theorem "\\<forall>vs. exec (comp e) s vs = (value e s) # vs"; |
91 |
92 |
92 txt{*\noindent |
93 txt{*\noindent |
93 which is proved by induction on \isa{e} followed by simplification, once |
94 which is proved by induction on \isa{e} followed by simplification, once |
94 we have the following lemma about executing the concatenation of two |
95 we have the following lemma about executing the concatenation of two |
95 instruction sequences: |
96 instruction sequences: |
96 *} |
97 *} |
97 (*<*)oops;(*>*) |
98 (*<*)oops;(*>*) |
98 lemma exec_app[simp]: |
99 lemma exec_app[simp]: |
99 "\\<forall>vs. exec s vs (xs@ys) = exec s (exec s vs xs) ys"; |
100 "\\<forall>vs. exec (xs@ys) s vs = exec ys s (exec xs s vs)"; |
100 |
101 |
101 txt{*\noindent |
102 txt{*\noindent |
102 This requires induction on \isa{xs} and ordinary simplification for the |
103 This requires induction on \isa{xs} and ordinary simplification for the |
103 base cases. In the induction step, simplification leaves us with a formula |
104 base cases. In the induction step, simplification leaves us with a formula |
104 that contains two \isa{case}-expressions over instructions. Thus we add |
105 that contains two \isa{case}-expressions over instructions. Thus we add |
111 also be modified in the same way \isa{simp} can. Thus the proof can be |
112 also be modified in the same way \isa{simp} can. Thus the proof can be |
112 rewritten as |
113 rewritten as |
113 *} |
114 *} |
114 (*<*) |
115 (*<*) |
115 lemmas [simp del] = exec_app; |
116 lemmas [simp del] = exec_app; |
116 lemma [simp]: "\\<forall>vs. exec s vs (xs@ys) = exec s (exec s vs xs) ys"; |
117 lemma [simp]: "\\<forall>vs. exec (xs@ys) s vs = exec ys s (exec xs s vs)"; |
117 (*>*) |
118 (*>*) |
118 apply(induct_tac xs, auto split: instr.split).; |
119 apply(induct_tac xs, auto split: instr.split).; |
119 |
120 |
120 text{*\noindent |
121 text{*\noindent |
121 Although this is more compact, it is less clear for the reader of the proof. |
122 Although this is more compact, it is less clear for the reader of the proof. |
122 |
123 |
123 We could now go back and prove \isa{exec s [] (comp e) = [value s e]} |
124 We could now go back and prove \isa{exec (comp e) s [] = [value e s]} |
124 merely by simplification with the generalized version we just proved. |
125 merely by simplification with the generalized version we just proved. |
125 However, this is unnecessary because the generalized version fully subsumes |
126 However, this is unnecessary because the generalized version fully subsumes |
126 its instance. |
127 its instance. |
127 *} |
128 *} |
128 (*<*) |
129 (*<*) |
129 theorem "\\<forall>vs. exec s vs (comp e) = (value s e) # vs"; |
130 theorem "\\<forall>vs. exec (comp e) s vs = (value e s) # vs"; |
130 apply(induct_tac e, auto).; |
131 apply(induct_tac e, auto).; |
131 end |
132 end |
132 (*>*) |
133 (*>*) |