1
|
open Format
|
2
|
open LustreSpec
|
3
|
open Machine_code
|
4
|
open Corelang
|
5
|
open C_backend_common
|
6
|
open C_backend_spec
|
7
|
open Utils
|
8
|
open Types
|
9
|
|
10
|
let fullExists = true
|
11
|
|
12
|
let rec list_to_partial l = match l with
|
13
|
| [] -> [[]]
|
14
|
| _::q -> l::(list_to_partial q)
|
15
|
|
16
|
|
17
|
(* Print a function call/declaration in acsl *)
|
18
|
let pp_acsl_fun name fmt args =
|
19
|
fprintf fmt "%s(@[<v>%a@])"
|
20
|
name
|
21
|
(Utils.fprintf_list ~sep:",@ " (fun fmt f-> f fmt)) args
|
22
|
|
23
|
(* Print an invariant call/decl in acsl *)
|
24
|
let pp_acsl_fun_init name self inst fmt mem =
|
25
|
let arg = fun fmt-> (match inst, mem with
|
26
|
| x, None -> fprintf fmt "%a %s" pp_machine_memtype_name name self
|
27
|
| "", Some "" -> fprintf fmt "%s" self
|
28
|
| "", Some m -> fprintf fmt "\\at(*%s, %s)" self m
|
29
|
| x, Some "" -> fprintf fmt "%s.%s" self inst
|
30
|
| x, Some m -> fprintf fmt "\\at(%s->%s, %s)" self inst m)
|
31
|
in
|
32
|
pp_acsl_fun ("init_"^name) fmt [arg]
|
33
|
|
34
|
|
35
|
let preprocess_acsl_instr calls outputs instr =
|
36
|
match instr with
|
37
|
| MStep ([i0], i, vl) when Basic_library.is_internal_fun i && (not (List.mem i0 outputs)) ->
|
38
|
Some (i0, Fun (i, vl))
|
39
|
| MStep ([i0], i, vl) when (not (Basic_library.is_internal_fun i)) && (node_name (fst (List.assoc i calls)) = "_arrow") && (not (List.mem i0 outputs)) ->
|
40
|
assert (List.length vl == 2);
|
41
|
Some (i0, Fun ("arrow_"^i, vl))
|
42
|
| MLocalAssign (i,v) when not (List.mem i outputs) ->
|
43
|
Some (i, v)
|
44
|
| _ -> None
|
45
|
|
46
|
|
47
|
let pp_cast fmt = function
|
48
|
| Types.Tbool -> fprintf fmt "(_Bool)"
|
49
|
| Types.Treal -> fprintf fmt "(double)"
|
50
|
| Types.Tint -> fprintf fmt "(int)"
|
51
|
| _ -> assert false
|
52
|
|
53
|
let getFunType i args =
|
54
|
match i, args with
|
55
|
| "ite", [v1; v2; v3] -> v2
|
56
|
| "uminus", [v] -> v
|
57
|
| "not", [v] -> v
|
58
|
| "impl", [v1; v2] -> v1
|
59
|
| "=", [v1; v2] -> Types.Tbool
|
60
|
| "mod", [v1; v2] -> v1
|
61
|
| "xor", [v1; v2] -> v1
|
62
|
| _, [v1; v2] -> v1
|
63
|
| _ -> assert false
|
64
|
|
65
|
let rec get_val_type v =
|
66
|
match v with
|
67
|
| Cst _
|
68
|
| LocalVar _
|
69
|
| StateVar _-> Machine_code.get_val_type v
|
70
|
| Fun (n, vl) -> getFunType n (List.map get_val_type vl)
|
71
|
| Array _
|
72
|
| Access _
|
73
|
| Power _ -> assert false
|
74
|
|
75
|
let get_var_type t = (Types.repr t.var_type).Types.tdesc
|
76
|
|
77
|
(* Print a machine instruction in acsl for transition lemma *)
|
78
|
let rec pp_acsl_instr_assert init vars instances calls self pointer fmt instr =
|
79
|
let mem1 = if init then self else ("\\at(*"^self^", Pre)") in
|
80
|
let mem2 = if init then self else ("(*"^self^")") in
|
81
|
match instr with
|
82
|
| MReset i ->
|
83
|
let (node, static) = List.assoc i calls in
|
84
|
assert (List.length static == 0);
|
85
|
if node_name node = "_arrow" then
|
86
|
fprintf fmt "(%s.%s._reg._first==1)" self i
|
87
|
else
|
88
|
pp_acsl_fun_init (node_name node) self i fmt (Some "")
|
89
|
| MLocalAssign (i,v) ->
|
90
|
(match i.var_type.tdesc with Tbool -> fprintf fmt "((!%a) == (!%a))" | _ -> fprintf fmt "(%a == %a)")
|
91
|
(pp_acsl_var_read pointer) i
|
92
|
(pp_acsl_val mem1 (pp_acsl_var_read pointer)) v
|
93
|
| MStateAssign (i,v) ->
|
94
|
(match i.var_type.tdesc with Tbool -> fprintf fmt "((!%a) == (!%a))" | _ -> fprintf fmt "(%a == %a)")
|
95
|
(pp_acsl_val mem2 (pp_acsl_var_read pointer)) (StateVar i)
|
96
|
(pp_acsl_val mem1 (pp_acsl_var_read pointer)) v
|
97
|
| MStep ([i0], i, vl) when Basic_library.is_internal_fun i ->
|
98
|
pp_acsl_instr_assert init vars calls instances self pointer fmt (MLocalAssign (i0, Fun (i, vl)))
|
99
|
| MStep ([i0], i, [x;y]) when (not (Basic_library.is_internal_fun i)) && (node_name (fst (List.assoc i calls)) = "_arrow") ->
|
100
|
fprintf fmt "(%a==(%s.%s._reg._first?(%a):(%a))) && (%s.%s._reg._first==0)"
|
101
|
(pp_acsl_var_read pointer) i0
|
102
|
mem1 i
|
103
|
(pp_acsl_val mem1 (pp_acsl_var_read [])) x
|
104
|
(pp_acsl_val mem1 (pp_acsl_var_read [])) y
|
105
|
mem2 i
|
106
|
| MStep (il, i, vl) ->
|
107
|
let pp_val fmt x = (match get_val_type x with Types.Tbool -> fprintf fmt "((%a)?1:0)" | _ -> fprintf fmt "%a") (pp_acsl_val mem1 (pp_acsl_var_read [])) x in
|
108
|
pp_acsl_fun ("Ctrans_"^(node_name (fst (List.assoc i calls)))) fmt
|
109
|
((List.map (fun x fmt-> fprintf fmt "%a %a" pp_cast (get_val_type x) pp_val x) vl)@
|
110
|
(List.map (fun x fmt-> fprintf fmt "%a" (*pp_cast (get_var_type x)*) (pp_acsl_var_read []) x) il)@
|
111
|
(try ignore(List.assoc i instances);[(fun fmt->fprintf fmt "%s.%s" mem1 i);(fun fmt->fprintf fmt "%s.%s" mem2 i)] with Not_found -> []))
|
112
|
| MBranch (g,hl) -> assert false (*TODO: useless : ????
|
113
|
let t = fst (List.hd hl) in
|
114
|
if hl <> [] && (t = tag_true || t = tag_false) then
|
115
|
let tl = try List.assoc tag_true hl with Not_found -> [] in
|
116
|
let el = try List.assoc tag_false hl with Not_found -> [] in
|
117
|
fprintf fmt "((%a)?(%a%s):(%a%s))"
|
118
|
(pp_acsl_val mem1 (pp_acsl_var_read pointer)) g
|
119
|
(Utils.fprintf_list ~sep:"&& " (pp_acsl_instr init vars calls self pointer)) tl
|
120
|
(if List.length tl == 0 then "1" else "")
|
121
|
(Utils.fprintf_list ~sep:"&& " (pp_acsl_instr init vars calls self pointer)) el
|
122
|
(if List.length el == 0 then "1" else "")
|
123
|
else assert false*)
|
124
|
|
125
|
(* Print all machine instructions in acsl for transition lemma *)
|
126
|
let pp_acsl_instrs_assert init outputs self pointer instances calls vars fmt instrs =
|
127
|
fprintf fmt " ensures %a;"
|
128
|
(Utils.fprintf_list ~sep:";@, ensures " (pp_acsl_instr_assert init vars instances calls self (pointer@outputs)))
|
129
|
instrs
|
130
|
|
131
|
(* Print a machine instruction in acsl for transition lemma *)
|
132
|
let rec pp_acsl_instr init vars instances calls self pointer fmt instr =
|
133
|
let mem1 = if init then self else (self^"1") in
|
134
|
let mem2 = if init then self else (self^"2") in
|
135
|
match instr with
|
136
|
| MReset i ->
|
137
|
let (node, static) = List.assoc i calls in
|
138
|
assert (List.length static == 0);
|
139
|
if node_name node = "_arrow" then
|
140
|
fprintf fmt "(%s.%s._reg._first==1)" self i
|
141
|
else
|
142
|
pp_acsl_fun_init (node_name node) self i fmt (Some "")
|
143
|
| MLocalAssign (i,v) ->
|
144
|
(match i.var_type.tdesc with Tbool -> fprintf fmt "((!%a) == (!%a))" | _ -> fprintf fmt "(%a == %a)")
|
145
|
(pp_acsl_var_read pointer) i
|
146
|
(pp_acsl_val mem1 (pp_acsl_var_read pointer)) v
|
147
|
| MStateAssign (i,v) ->
|
148
|
(match i.var_type.tdesc with Tbool -> fprintf fmt "((!%a) == (!%a))" | _ -> fprintf fmt "(%a == %a)")
|
149
|
(pp_acsl_val mem2 (pp_acsl_var_read pointer)) (StateVar i)
|
150
|
(pp_acsl_val mem1 (pp_acsl_var_read pointer)) v
|
151
|
| MStep ([i0], i, vl) when Basic_library.is_internal_fun i ->
|
152
|
pp_acsl_instr init vars calls instances self pointer fmt (MLocalAssign (i0, Fun (i, vl)))
|
153
|
| MStep ([i0], i, [x;y]) when (not (Basic_library.is_internal_fun i)) && (node_name (fst (List.assoc i calls)) = "_arrow") ->
|
154
|
fprintf fmt "(%a==(%s1.%s._reg._first?(%a):(%a))) && (%s2.%s._reg._first==0)"
|
155
|
(pp_acsl_var_read pointer) i0
|
156
|
self i
|
157
|
(pp_acsl_val mem1 (pp_acsl_var_read [])) x
|
158
|
(pp_acsl_val mem1 (pp_acsl_var_read [])) y
|
159
|
self i
|
160
|
| MStep (il, i, vl) ->
|
161
|
let pp_val fmt x = (match get_val_type x with Types.Tbool -> fprintf fmt "%a" | _ -> fprintf fmt "%a") (pp_acsl_val mem1 (pp_acsl_var_read [])) x in
|
162
|
pp_acsl_fun ("Ctrans_"^(node_name (fst (List.assoc i calls)))) fmt
|
163
|
((List.map (fun x fmt-> fprintf fmt "%a %a" pp_cast (get_val_type x) pp_val x) vl)@
|
164
|
(List.map (fun x fmt-> fprintf fmt "%a" (*pp_cast (get_var_type x)*) (pp_acsl_var_read []) x) il)@
|
165
|
(try ignore(List.assoc i instances);[(fun fmt->fprintf fmt "%s1.%s" self i);(fun fmt->fprintf fmt "%s2.%s" self i)] with Not_found -> []))
|
166
|
| MBranch (g,hl) -> assert false (*TODO: useless : ????
|
167
|
let t = fst (List.hd hl) in
|
168
|
if hl <> [] && (t = tag_true || t = tag_false) then
|
169
|
let tl = try List.assoc tag_true hl with Not_found -> [] in
|
170
|
let el = try List.assoc tag_false hl with Not_found -> [] in
|
171
|
fprintf fmt "((%a)?(%a%s):(%a%s))"
|
172
|
(pp_acsl_val mem1 (pp_acsl_var_read pointer)) g
|
173
|
(Utils.fprintf_list ~sep:"&& " (pp_acsl_instr init vars calls self pointer)) tl
|
174
|
(if List.length tl == 0 then "1" else "")
|
175
|
(Utils.fprintf_list ~sep:"&& " (pp_acsl_instr init vars calls self pointer)) el
|
176
|
(if List.length el == 0 then "1" else "")
|
177
|
else assert false*)
|
178
|
|
179
|
(* Print all machine instructions in acsl for transition lemma *)
|
180
|
let pp_acsl_instrs init outputs self pointer instances calls vars fmt instrs =
|
181
|
if List.length instrs == 0 then fprintf fmt "\\true" else
|
182
|
let handle (locals, instrs) i =
|
183
|
match preprocess_acsl_instr calls outputs i with
|
184
|
| None -> (locals, i::instrs)
|
185
|
| Some l -> (l::locals, instrs)
|
186
|
in
|
187
|
let pp_let fmt (i, v) =
|
188
|
match v with
|
189
|
| Fun (s, [x;y]) when String.length s >= 6 && String.sub s 0 6 = "arrow_" ->
|
190
|
let var = String.sub s 6 (String.length s - 6) in
|
191
|
fprintf fmt "\\let %a = %s1.%s._reg._first?%a:%a; (%s2.%s._reg._first==0) &&"
|
192
|
(pp_acsl_var_read pointer) i
|
193
|
self var
|
194
|
(pp_acsl_val (self^"1") (pp_acsl_var_read [])) x
|
195
|
(pp_acsl_val (self^"1") (pp_acsl_var_read [])) y
|
196
|
self var
|
197
|
| _ ->
|
198
|
fprintf fmt "\\let %a = %a;"
|
199
|
(pp_acsl_var_read pointer) i
|
200
|
(pp_acsl_val (self^"1") (pp_acsl_var_read pointer)) v
|
201
|
in
|
202
|
let (locals, instrs) = if fullExists then ([], instrs) else List.fold_left handle ([], []) instrs in
|
203
|
fprintf fmt "%a@,%a"
|
204
|
(Utils.fprintf_list ~sep:"@," pp_let)
|
205
|
(List.rev locals)
|
206
|
(Utils.fprintf_list ~sep:" &&@," (pp_acsl_instr init vars instances calls self pointer))
|
207
|
instrs
|
208
|
|
209
|
(* Take a dependance and print it for invariant predicate *)
|
210
|
(*
|
211
|
let pp_acsl_dep self instances fmt = function
|
212
|
| Dep_Var s -> fprintf fmt "%s2._reg.%s == %s1._reg.%s" self s self s
|
213
|
| Dep_Node s ->
|
214
|
pp_acsl_fun ("inv_"^(node_name (fst (List.assoc s instances)))) fmt [fun fmt->fprintf fmt "%s1.%s" self i];
|
215
|
fprintf fmt "&&@, %t == %t" (pp_acsl_at self s)
|
216
|
(pp_acsl_at self s)
|
217
|
*)
|
218
|
|
219
|
(*
|
220
|
Require Why3.
|
221
|
intros.
|
222
|
unfold P_trans_AltitudeControl.
|
223
|
repeat split.
|
224
|
why3 "Z3" timelimit 10.
|
225
|
why3 "Z3" timelimit 10.
|
226
|
why3 "Z3" timelimit 10.
|
227
|
why3 "Z3" timelimit 10.
|
228
|
why3 "Z3" timelimit 10.
|
229
|
why3 "Z3" timelimit 10.
|
230
|
why3 "Z3" timelimit 10.
|
231
|
why3 "Z3" timelimit 10.
|
232
|
why3 "Z3" timelimit 10.
|
233
|
why3 "Z3" timelimit 10.
|
234
|
why3 "Z3" timelimit 10.
|
235
|
why3 "Z3" timelimit 10.
|
236
|
why3 "Z3" timelimit 10.
|
237
|
why3 "Z3" timelimit 10.
|
238
|
why3 "Z3" timelimit 10.
|
239
|
why3 "Z3" timelimit 10.
|
240
|
why3 "Z3" timelimit 10.
|
241
|
why3 "Z3" timelimit 10.
|
242
|
assert (a_9 = F_AltitudeControl_mem_ni_1 a_6).
|
243
|
why3 "Z3" timelimit 10.
|
244
|
assert (a_10 = F_AltitudeControl_mem_ni_1 a_7).
|
245
|
unfold F_AltitudeControl_mem_ni_1.
|
246
|
unfold a_7.
|
247
|
unfold Load_S_AltitudeControl_mem.
|
248
|
unfold a_10.
|
249
|
unfold a_8.
|
250
|
unfold havoc in H36.
|
251
|
unfold get.
|
252
|
clear.
|
253
|
rewrite <- H48.
|
254
|
rewrite <- H49.
|
255
|
apply H47.
|
256
|
*)
|
257
|
|
258
|
(* Print a transition call/decl in acsl *)
|
259
|
let pp_acsl_fun_trans infos pre name inputs outputs suffix flag_output self flag_mem locals fmt existential =
|
260
|
let (locals, existential) = (*([], match existential with None -> None | Some x -> Some []) else*)
|
261
|
match infos with
|
262
|
| None -> (locals, existential)
|
263
|
| Some (instrs, calls) ->
|
264
|
let nonlocals = List.fold_left (fun l x-> match preprocess_acsl_instr calls outputs x with | Some (i, _) -> i::l | None -> l) [] instrs in
|
265
|
(
|
266
|
(if not fullExists then List.filter (fun x-> not (List.mem x nonlocals)) else fun x -> x) locals,
|
267
|
match existential with None -> None | Some existential -> Some ((if not fullExists then List.filter (fun x-> not (List.mem x nonlocals)) else fun x -> x) existential)
|
268
|
)
|
269
|
in
|
270
|
let mems = function 1 -> "Pre" | 2 -> "Here" | _ -> assert false in
|
271
|
let pp_self_read =
|
272
|
if flag_mem then fun i fmt-> (match i with 1 -> fprintf fmt "\\at(*%s, Pre)" self | 2 -> fprintf fmt "(*%s)" self | _ -> assert false)
|
273
|
else fun i fmt-> fprintf fmt "%s%i" self (match suffix with None -> i | Some s -> s+i-1)
|
274
|
in
|
275
|
let (pp_var, pp_self) =
|
276
|
match existential with
|
277
|
| None -> (pp_acsl_var_decl, (fun i fmt-> fprintf fmt "%a %s%i" pp_machine_memtype_name name self i))
|
278
|
| Some ex -> (if List.length ex != 0 then fprintf fmt "\\exists %a;@," (Utils.fprintf_list ~sep:";@,\\exists " pp_acsl_var_decl) ex);
|
279
|
(pp_acsl_var_read (if flag_output then outputs else []), pp_self_read)
|
280
|
in
|
281
|
let pp_vars = List.map (fun x fmt-> match suffix with None-> pp_var fmt x | Some i -> fprintf fmt "%a%i" pp_var x (i+1)) in
|
282
|
(pp_acsl_fun (pre^"trans_"^name)) fmt
|
283
|
((pp_vars (inputs@outputs))@(if not (self = "") then [pp_self 1;pp_self 2] else [])@(pp_vars locals))
|
284
|
|
285
|
(* Print an invariant call/decl in acsl *)
|
286
|
let pp_acsl_fun_inv depth name self fmt mem =
|
287
|
let arg = fun fmt-> (match mem with
|
288
|
| None -> fprintf fmt "%a %s%i" pp_machine_memtype_name name self depth
|
289
|
| Some "" -> fprintf fmt "%s" self
|
290
|
| Some "Here" -> fprintf fmt "*%s" self
|
291
|
| Some m -> fprintf fmt "\\at(*%s, %s)" self m)
|
292
|
in
|
293
|
pp_acsl_fun ("inv_"^name) fmt [arg]
|
294
|
|
295
|
(* Print an invariant call/decl in acsl *)
|
296
|
let pp_acsl_inv depth name inputs outputs self fmt spec =
|
297
|
let rec iter base x = function
|
298
|
| i when i = base-1 -> []
|
299
|
| i -> (i, x)::(iter base x (i-1))
|
300
|
in
|
301
|
let rec iterList base = function
|
302
|
| [] -> []
|
303
|
| t::q -> (iter base t depth)@(iterList base q)
|
304
|
in
|
305
|
let trans_pred fmt i =
|
306
|
fprintf fmt "%a" (pp_acsl_fun_trans None "C" name inputs outputs (Some i) false self false []) (Some [])
|
307
|
in
|
308
|
let pp_eexpr_expr self i j fmt ee =
|
309
|
fprintf fmt "spec_%i(%a, %s%i)" ee.muid (Utils.fprintf_list ~sep:", " (fun fmt x-> fprintf fmt "%a%i" (pp_acsl_var_read []) x j)) ee.mmstep_logic.step_inputs self i
|
310
|
in
|
311
|
let spec_pred cor preds fmt i =
|
312
|
let j = if cor then i + 1 else i in
|
313
|
fprintf fmt "(%a)" (Utils.fprintf_list ~sep:"&&@," (pp_eexpr_expr self i j)) preds
|
314
|
in
|
315
|
let aux fmt base =
|
316
|
let selfs = iter base self (depth-1) in
|
317
|
let ios = iterList (base + 1) (inputs@outputs) in
|
318
|
(if List.length selfs == 0 && List.length ios == 0 then
|
319
|
fprintf fmt "(%a%t%a%t%t)"
|
320
|
else
|
321
|
fprintf fmt "(\\exists %a%t%a;@,%a%t%a%t%t)"
|
322
|
(Utils.fprintf_list ~sep:", " (fun fmt (i, x)-> fprintf fmt "%a %s%i" pp_machine_memtype_name name self i)) selfs
|
323
|
(Utils.pp_final_char_if_non_empty ", " (iter base self (depth-1)))
|
324
|
(Utils.fprintf_list ~sep:", " (fun fmt (i, x)-> fprintf fmt "%a%i" pp_acsl_var_decl x i)) ios
|
325
|
)
|
326
|
(Utils.fprintf_list ~sep:"&&@," (fun fmt (i, f)-> fprintf fmt "%a" f i)) (iter base trans_pred (depth-1))
|
327
|
(Utils.pp_final_char_if_non_empty "&&@," (iter base trans_pred (depth-1)))
|
328
|
(Utils.fprintf_list ~sep:"&&@," (fun fmt (i, f)-> fprintf fmt "%a" f i)) (iter base (spec_pred true spec.m_requires) (depth-1))
|
329
|
(Utils.pp_final_char_if_non_empty "&&@," (iter base (spec_pred true spec.m_requires) (depth-1)))
|
330
|
(fun fmt->
|
331
|
if base == 0 then
|
332
|
Utils.fprintf_list ~sep:"&&@," (fun fmt (i, f)-> fprintf fmt "%a" f i) fmt (iter (base+1) (spec_pred false spec.m_ensures) depth)
|
333
|
else
|
334
|
pp_acsl_fun_init name (self^(string_of_int base)) "" fmt (Some "")
|
335
|
)
|
336
|
in
|
337
|
Utils.fprintf_list ~sep:"||@," (fun fmt (i, f)-> fprintf fmt "%a" f i) fmt (iter 0 aux depth)
|
338
|
|
339
|
(* Print the invariant lemma *)
|
340
|
let pp_acsl_lem_inv depth name inputs outputs self fmt spec =
|
341
|
let pp_eexpr_expr self j fmt ee =
|
342
|
fprintf fmt "spec_%i(%a, %s%i)" ee.muid (Utils.fprintf_list ~sep:", " (pp_acsl_var_read [])) ee.mmstep_logic.step_inputs self j
|
343
|
in
|
344
|
fprintf fmt "\\forall %a %s1, %s2, %a;@,%a==>@,%a==>@,%a%t%a"
|
345
|
pp_machine_memtype_name name self self
|
346
|
(Utils.fprintf_list ~sep:", " pp_acsl_var_decl) (inputs@outputs)
|
347
|
(pp_acsl_fun_inv depth name (self^"1")) (Some "")
|
348
|
(pp_acsl_fun_trans None "C" name inputs outputs None false self false []) (Some [])
|
349
|
(Utils.fprintf_list ~sep:"==>@," (pp_eexpr_expr self 1)) spec.m_requires
|
350
|
(Utils.pp_final_char_if_non_empty "==>@," spec.m_requires)
|
351
|
(pp_acsl_fun_inv depth name (self^"2")) (Some "")
|
352
|
|
353
|
(* Print lemma init *)
|
354
|
let pp_acsl_lem_init k depth name inputs outputs self fmt spec =
|
355
|
let rec iter base x = function
|
356
|
| i when i = base-1 -> []
|
357
|
| i -> (i, x)::(iter base x (i-1))
|
358
|
in
|
359
|
let rec iterList base = function
|
360
|
| [] -> []
|
361
|
| t::q -> (iter base t depth)@(iterList base q)
|
362
|
in
|
363
|
let trans_pred fmt i =
|
364
|
fprintf fmt "%a" (pp_acsl_fun_trans None "C" name inputs outputs (Some i) false self false []) (Some [])
|
365
|
in
|
366
|
let spec_pred fmt i =
|
367
|
let pp_eexpr_expr self j fmt ee =
|
368
|
fprintf fmt "spec_%i(%a, %s%i)" ee.muid (Utils.fprintf_list ~sep:", " (fun fmt x-> fprintf fmt "%a%i" (pp_acsl_var_read []) x i)) ee.mmstep_logic.step_inputs self j
|
369
|
in
|
370
|
fprintf fmt "%a%t(%a)"
|
371
|
(Utils.fprintf_list ~sep:"==>@," ((fun fmt (w, x)-> fprintf fmt "%a"
|
372
|
(Utils.fprintf_list ~sep:"==>@," (pp_eexpr_expr self (w))) spec.m_requires
|
373
|
))) (iter k None (depth -1))
|
374
|
(Utils.pp_final_char_if_non_empty "==>@," spec.m_requires)
|
375
|
(Utils.fprintf_list ~sep:"&&@," (pp_eexpr_expr self (i))) spec.m_ensures
|
376
|
in
|
377
|
let aux fmt base =
|
378
|
let selfs = iter base self (depth) in
|
379
|
let ios = iterList (base + 1) (inputs@outputs) in
|
380
|
(if List.length selfs == 0 && List.length ios == 0 then
|
381
|
fprintf fmt "(%a%t%t)"
|
382
|
else
|
383
|
fprintf fmt "\\forall %a%t%a;@,%a%t%t"
|
384
|
(Utils.fprintf_list ~sep:", " (fun fmt (i, x)-> fprintf fmt "%a %s%i" pp_machine_memtype_name name self i)) selfs
|
385
|
(Utils.pp_final_char_if_non_empty ", " (iter base self (depth-1)))
|
386
|
(Utils.fprintf_list ~sep:", " (fun fmt (i, x)-> fprintf fmt "%a%i" pp_acsl_var_decl x i)) ios
|
387
|
)
|
388
|
(Utils.fprintf_list ~sep:"==>@," (fun fmt (i, f)-> fprintf fmt "%a" f i)) (iter base trans_pred (depth-1))
|
389
|
(Utils.pp_final_char_if_non_empty "==>@," (iter base trans_pred (depth-1)))
|
390
|
(fun fmt->
|
391
|
pp_acsl_fun_init name (self^(string_of_int base)) "" fmt (Some "")
|
392
|
)
|
393
|
in
|
394
|
fprintf fmt "%a ==> %a" aux k spec_pred depth
|
395
|
|
396
|
(* Print the spec lemma *)
|
397
|
let pp_acsl_lem_spec depth name inputs outputs self fmt spec =
|
398
|
let pp_eexpr_expr self j fmt ee =
|
399
|
fprintf fmt "spec_%i(%a, %s%i)" ee.muid (Utils.fprintf_list ~sep:", " (pp_acsl_var_read [])) ee.mmstep_logic.step_inputs self j
|
400
|
in
|
401
|
fprintf fmt "\\forall %a %s1, %s2, %a;@,%a==>@,%a==>@,%a%t%a"
|
402
|
pp_machine_memtype_name name self self
|
403
|
(Utils.fprintf_list ~sep:", " pp_acsl_var_decl) (inputs@outputs)
|
404
|
(pp_acsl_fun_inv depth name (self^"1")) (Some "")
|
405
|
(pp_acsl_fun_trans None "C" name inputs outputs None false self false []) (Some [])
|
406
|
(Utils.fprintf_list ~sep:"==>@," (pp_eexpr_expr self 1)) spec.m_requires
|
407
|
(Utils.pp_final_char_if_non_empty "==>@," spec.m_requires)
|
408
|
(Utils.fprintf_list ~sep:"&&@," (pp_eexpr_expr self 2)) spec.m_ensures
|
409
|
|
410
|
let getDepth m =
|
411
|
try (
|
412
|
match (List.assoc ["k"] (List.flatten (List.map (fun x-> x.annots) m.mannot))).eexpr_qfexpr.expr_desc with
|
413
|
| (Expr_const (Const_int k)) -> k
|
414
|
| _ -> 0
|
415
|
) with Not_found -> 0
|
416
|
|
417
|
(* Get the instructions from acsl spec effect *)
|
418
|
let get_instrs_effect spec =
|
419
|
let effects = spec.m_requires@spec.m_ensures@
|
420
|
(List.fold_left
|
421
|
(fun accu (_,assumes, ensures) -> assumes@ensures@accu)
|
422
|
[] spec.m_behaviors)
|
423
|
in
|
424
|
let effects = List.filter (fun ee -> ee.mmstep_effects.step_instrs <> []) effects in
|
425
|
List.flatten (List.map (fun e -> e.mmstep_effects.step_instrs) effects)
|
426
|
|
427
|
let get_instrs_effect_init spec =
|
428
|
let effects = spec.m_requires@spec.m_ensures@
|
429
|
(List.fold_left
|
430
|
(fun accu (_,assumes, ensures) -> assumes@ensures@accu)
|
431
|
[] spec.m_behaviors)
|
432
|
in
|
433
|
|
434
|
let effects = List.filter (fun ee -> ee.mminit <> []) effects in
|
435
|
List.flatten (List.map (fun e -> e.mminit) effects)
|
436
|
|
437
|
module Make =
|
438
|
functor (SpecArg: SPECARG) ->
|
439
|
struct
|
440
|
|
441
|
open SpecArg
|
442
|
|
443
|
module Spec = Make(SpecArg)
|
444
|
|
445
|
let init m = Spec.init m
|
446
|
|
447
|
module HdrMod = struct
|
448
|
|
449
|
(* Print all the proof stuff *)
|
450
|
let pp_acsl_def_trans stateless fmt m =
|
451
|
let name = m.mname.node_id in
|
452
|
let inputs = m.mstep.step_inputs in
|
453
|
let outputs = m.mstep.step_outputs in
|
454
|
let locals = m.mstep.step_locals in
|
455
|
let memory = m.mmemory in
|
456
|
let vars = inputs@outputs@locals@memory in
|
457
|
let depth = getDepth m in
|
458
|
let instrs = match m.mspec with None -> [] | Some spec -> get_instrs_effect (Spec.get_spec m.mname) in
|
459
|
let instrs_init = match m.mspec with None -> [] | Some spec -> get_instrs_effect_init (Spec.get_spec m.mname) in
|
460
|
let induction = (not stateless) && (getDepth m != 0) in
|
461
|
if m.mname.node_id <> arrow_id then (
|
462
|
let self = if stateless then "" else mk_self m in
|
463
|
fprintf fmt "/*@@ @[<v 3>predicate %a =@;%a;@]@;*/@."
|
464
|
(pp_acsl_fun_trans (Some (m.mstep.step_instrs, m.mcalls)) "" name inputs outputs None false self false locals) None
|
465
|
(pp_acsl_instrs false outputs self [] m.minstances m.mcalls vars) (m.mstep.step_instrs@instrs);
|
466
|
fprintf fmt "/*@@ @[<v 3>predicate %a =@;%a;@]@;*/@."
|
467
|
(pp_acsl_fun_trans None "C" name inputs outputs None false self false []) None
|
468
|
(pp_acsl_fun_trans (Some (m.mstep.step_instrs, m.mcalls)) "" name inputs outputs None false self false locals) (Some locals);
|
469
|
(if not stateless then fprintf fmt "/*@@ @[<v 3>predicate %a =@;%a;@]@;*/@."
|
470
|
(pp_acsl_fun_init name self "") None
|
471
|
(pp_acsl_instrs true [] self [] m.minstances m.mcalls vars) (m.minit@instrs_init));
|
472
|
if induction then (
|
473
|
match m.mspec with None -> () | Some spec -> (
|
474
|
let spec = (Spec.get_spec m.mname) in
|
475
|
fprintf fmt "/*@@ @[<v 3>predicate %a =@;%a;@]@;*/@." (pp_acsl_fun_inv depth name self) None (pp_acsl_inv depth name inputs outputs self) spec;
|
476
|
for i = 0 to depth-1 do
|
477
|
fprintf fmt "/*@@ @[<v 3>lemma inv_init_%i_%s : @;%a;@]@;*/@." (depth-i) name (pp_acsl_lem_init i depth name inputs outputs self) spec;
|
478
|
done;
|
479
|
fprintf fmt "/*@@ @[<v 3>lemma inv_spec_%s : @;%a;@]@;*/@." name (pp_acsl_lem_spec depth name inputs outputs self) spec;
|
480
|
fprintf fmt "/*@@ @[<v 3>lemma inv_inv_%s : @;%a;@]@;*/@." name (pp_acsl_lem_inv depth name inputs outputs self) spec
|
481
|
)
|
482
|
))
|
483
|
let _print_machine_decl_step_fun_prefix stateless fmt m =
|
484
|
let self = mk_self m in
|
485
|
let induction = (not stateless) && (getDepth m != 0) in
|
486
|
let pre_inv = fun fmt -> fprintf fmt "requires %a;@," (pp_acsl_fun_inv (getDepth m) m.mname.node_id self) (Some "Here") in
|
487
|
let post_inv = fun fmt -> fprintf fmt "ensures %a;@," (pp_acsl_fun_inv (getDepth m) m.mname.node_id self) (Some "Here") in
|
488
|
let post_trans = fun fmt -> fprintf fmt "ensures %a;@," (pp_acsl_fun_trans None "C" m.mname.node_id m.mstep.step_inputs m.mstep.step_outputs None true (if stateless then "" else self) true []) (Some []) in
|
489
|
let pre = match m.mspec with
|
490
|
| Some _ when induction -> pre_inv
|
491
|
| _ -> fun fmt -> ()
|
492
|
in
|
493
|
let post = match m.mspec with
|
494
|
| Some _ when induction -> fun fmt -> fprintf fmt "%t%t" post_inv post_trans
|
495
|
| _ -> post_trans
|
496
|
in
|
497
|
Spec.HdrMod._print_machine_decl_step_fun_prefix stateless pre post fmt m
|
498
|
|
499
|
let has_spec_mem m = Spec.HdrMod.has_spec_mem m
|
500
|
let pp_registers_struct fmt m = Spec.HdrMod.pp_registers_struct fmt m
|
501
|
let print_machine_decl_prefix fmt m =
|
502
|
let mems = Machine_code.get_mems m machines in
|
503
|
fprintf fmt "%a%a"
|
504
|
Spec.HdrMod.print_machine_decl_prefix m
|
505
|
(pp_acsl_def_trans (List.length mems == 0)) m
|
506
|
let print_machine_decl_step_fun_prefix fmt m = _print_machine_decl_step_fun_prefix false fmt m
|
507
|
|
508
|
let print_machine_decl_init_fun_prefix fmt m =
|
509
|
let self = mk_self m in
|
510
|
let post fmt =
|
511
|
fprintf fmt "ensures %a;@." (pp_acsl_fun_init m.mname.node_id self "") (Some "Here");
|
512
|
match m.mspec with
|
513
|
| Some _ when getDepth m != 0 ->
|
514
|
fprintf fmt "ensures %a;@." (pp_acsl_fun_inv (getDepth m) m.mname.node_id self) (Some "Here")
|
515
|
| _ -> ()
|
516
|
|
517
|
in
|
518
|
Spec.HdrMod._print_machine_decl_init_fun_prefix (fun fmt-> ()) post fmt m
|
519
|
|
520
|
let print_machine_decl_stateless_fun_prefix fmt m = _print_machine_decl_step_fun_prefix true fmt m
|
521
|
|
522
|
let print_global_decl fmt = fprintf fmt "/*@@ @[<v 3>lemma missing: \\forall _Bool x; (x != 0) <==> (((int) x) != 0);*/@."
|
523
|
end
|
524
|
|
525
|
module SrcMod =
|
526
|
struct
|
527
|
let print_step_code_prefix stateless fmt m =
|
528
|
let inputs = m.mstep.step_inputs in
|
529
|
let outputs = m.mstep.step_outputs in
|
530
|
let locals = m.mstep.step_locals in
|
531
|
let mems = Machine_code.get_mems m machines in
|
532
|
let self = if List.length mems == 0 then "" else mk_self m in
|
533
|
fprintf fmt "/*@@ensures %a;@,%a*/@,{@,"
|
534
|
(pp_acsl_fun_trans None "C" m.mname.node_id m.mstep.step_inputs m.mstep.step_outputs None true (if stateless then "" else self) true []) (Some [])
|
535
|
(C_backend_spec.pp_assigns [] stateless machines) m
|
536
|
let print_step_code_midfix stateless fmt m =
|
537
|
let inputs = m.mstep.step_inputs in
|
538
|
let outputs = m.mstep.step_outputs in
|
539
|
let locals = m.mstep.step_locals in
|
540
|
let mems = Machine_code.get_mems m machines in
|
541
|
let self = if List.length mems == 0 then "" else mk_self m in
|
542
|
let instrs = match m.mspec with None -> [] | Some spec -> get_instrs_effect (Spec.get_spec m.mname) in
|
543
|
let memory = m.mmemory in
|
544
|
let vars = inputs@outputs@locals@memory in
|
545
|
let filtered_existencials = (if fullExists then
|
546
|
let nonlocals = List.fold_left (fun l x-> match preprocess_acsl_instr m.mcalls outputs x with | Some (i, _) -> i::l | None -> l) [] m.mstep.step_instrs in
|
547
|
List.filter (fun x-> not (List.mem x nonlocals))else fun x -> x) locals
|
548
|
in
|
549
|
Format.fprintf fmt "@,/* Asserting trans predicate: locals are [%a] */@,"
|
550
|
(fprintf_list ~sep:", " Printers.pp_var) filtered_existencials;
|
551
|
(Utils.fprintf_list ~sep:"@,"
|
552
|
(fun fmt x ->
|
553
|
fprintf fmt "/*@@ensures %a;@,%a*/@,{@,"
|
554
|
(pp_acsl_fun_trans
|
555
|
(Some (m.mstep.step_instrs, m.mcalls))
|
556
|
"" (* no predicate prefix *)
|
557
|
m.mname.node_id
|
558
|
inputs
|
559
|
outputs
|
560
|
None
|
561
|
true
|
562
|
self
|
563
|
true
|
564
|
locals
|
565
|
)
|
566
|
(Some x)
|
567
|
(C_backend_spec.pp_assigns (List.map (fun x fmt-> Printers.pp_var_name fmt x) locals) stateless machines) m)
|
568
|
)
|
569
|
fmt (list_to_partial filtered_existencials);
|
570
|
fprintf fmt "/*@@%a@,%a*/ {"
|
571
|
(pp_acsl_instrs_assert false outputs self [] m.minstances m.mcalls vars) (m.mstep.step_instrs@instrs)
|
572
|
(C_backend_spec.pp_assigns (List.map (fun x fmt-> Printers.pp_var_name fmt x) locals) stateless machines) m
|
573
|
|
574
|
let print_step_code_postfix stateless fmt m =
|
575
|
let inputs = m.mstep.step_inputs in
|
576
|
let outputs = m.mstep.step_outputs in
|
577
|
let locals = m.mstep.step_locals in
|
578
|
let memory = m.mmemory in
|
579
|
let vars = inputs@outputs@locals@memory in
|
580
|
let mems = Machine_code.get_mems m machines in
|
581
|
let self = if List.length mems == 0 then "" else mk_self m in
|
582
|
Spec.SrcMod.print_step_code_postfix stateless fmt m;
|
583
|
|
584
|
let filtered_existencials = (if fullExists then
|
585
|
let nonlocals = List.fold_left (fun l x-> match preprocess_acsl_instr m.mcalls outputs x with | Some (i, _) -> i::l | None -> l) [] m.mstep.step_instrs in
|
586
|
List.filter (fun x-> not (List.mem x nonlocals)) else fun x -> x) locals
|
587
|
in
|
588
|
|
589
|
for i = 0 to List.length filtered_existencials + 2 do
|
590
|
fprintf fmt "}"
|
591
|
done
|
592
|
|
593
|
let print_init_code_postfix fmt m = Spec.SrcMod.print_init_code_postfix fmt m
|
594
|
end
|
595
|
|
596
|
module MakefileMod =
|
597
|
struct
|
598
|
let other_targets fmt basename nodename dependencies = Spec.MakefileMod.other_targets fmt basename nodename dependencies
|
599
|
end
|
600
|
|
601
|
module MainMod =
|
602
|
struct
|
603
|
let print_while_prefix fmt m =
|
604
|
(match m.mspec with
|
605
|
| Some _ when getDepth m != 0 -> fprintf fmt "/*@@ loop invariant %a;*/@," (pp_acsl_fun_inv (getDepth m) m.mname.node_id "main_mem") (Some "")
|
606
|
| _ -> ()
|
607
|
);
|
608
|
end
|
609
|
|
610
|
module CoqMod =
|
611
|
struct
|
612
|
|
613
|
let repeat n fmt x =
|
614
|
for i = 0 to n - 1 do
|
615
|
fprintf fmt "%s" x
|
616
|
done
|
617
|
|
618
|
let pp_intro_hyp fmt k =
|
619
|
fprintf fmt "(*nb: %i*)\nintros " k;
|
620
|
repeat (k-1) fmt "[? ";
|
621
|
fprintf fmt "?";
|
622
|
repeat (k-1) fmt "]";
|
623
|
fprintf fmt ".\n"
|
624
|
|
625
|
let pp_choose nbcase fmt k =
|
626
|
fprintf fmt "(*choose case %i/%i*)\n" (k+1) nbcase;
|
627
|
repeat k fmt "right.\n";
|
628
|
(if k != nbcase - 1 then fprintf fmt "left.\n")
|
629
|
|
630
|
let pp_intros_exists fmt =
|
631
|
fprintf fmt "repeat eapply ex_intro.\n"
|
632
|
|
633
|
let pp_split fmt k =
|
634
|
fprintf fmt "(*nb goals: %i(split one less)*)\n" k;
|
635
|
repeat (k-1) fmt "split.\nFocus 2.\n"
|
636
|
|
637
|
let pp_eassumption fmt k =
|
638
|
repeat k fmt "eassumption.\n"
|
639
|
|
640
|
|
641
|
let pp_apply_lem_init fmt k =
|
642
|
fprintf fmt "eapply (Q_inv_init_%i_AltitudeControl).\n" k;
|
643
|
let nbgoals = k+1+k+2 in
|
644
|
for i = 0 to k-1 do
|
645
|
fprintf fmt "Focus %i.\n" (nbgoals-i);
|
646
|
fprintf fmt "eassumption.\n";
|
647
|
done;
|
648
|
for i = 1 to nbgoals-k do
|
649
|
fprintf fmt "eassumption.\n";
|
650
|
done
|
651
|
|
652
|
let pp_apply_inv_spec fmt name =
|
653
|
fprintf fmt "eapply Q_inv_spec_%s.\n" name;
|
654
|
fprintf fmt "Focus 5.\n";
|
655
|
for i = 1 to 5 do
|
656
|
fprintf fmt "eassumption.\n"
|
657
|
done
|
658
|
|
659
|
let pp_case nbgoals1 nbgoals2 nbgoals3 nbintro nbcase case_hyp case_goal fmt name =
|
660
|
let nbgoals = nbgoals1 + nbgoals2 + nbgoals3 in
|
661
|
if case_hyp != nbcase - 1 then (
|
662
|
fprintf fmt "intros h.\n";
|
663
|
fprintf fmt "elim h;clear h.\n"
|
664
|
);
|
665
|
pp_intro_hyp fmt nbintro;
|
666
|
pp_choose nbcase fmt case_goal;
|
667
|
pp_intros_exists fmt;
|
668
|
pp_split fmt nbgoals;
|
669
|
pp_eassumption fmt nbgoals3;
|
670
|
(
|
671
|
if case_hyp == nbcase -2 then
|
672
|
for i = 0 to case_goal - 1 do
|
673
|
pp_apply_lem_init fmt (case_goal - i)
|
674
|
done
|
675
|
else (if case_hyp == nbcase -1 then
|
676
|
(pp_apply_inv_spec fmt name;
|
677
|
for i = 1 to nbgoals2 - 1 do
|
678
|
fprintf fmt "eassumption.\n"
|
679
|
done)
|
680
|
else
|
681
|
())
|
682
|
);
|
683
|
pp_eassumption fmt nbgoals1
|
684
|
|
685
|
let pp_code_inv_inv m fmt name =
|
686
|
let inputs = m.mstep.step_inputs in
|
687
|
let outputs = m.mstep.step_outputs in
|
688
|
let locals = m.mstep.step_locals in
|
689
|
let memory = m.mmemory in
|
690
|
let vars = inputs@outputs@locals@memory in
|
691
|
let depth = getDepth m in
|
692
|
let nbcase = depth + 1 in
|
693
|
let spec = (Spec.get_spec m.mname) in
|
694
|
fprintf fmt "intros.\n";
|
695
|
fprintf fmt "generalize H2.\n";
|
696
|
fprintf fmt "unfold P_inv_%s.\n" name;
|
697
|
let computeAnd k = (
|
698
|
1*k + (*mems*)
|
699
|
(List.length spec.m_requires)*k + (*pre*)
|
700
|
(if k == nbcase -1 then 0 else 1), (*init*)
|
701
|
(if k == nbcase -1 then (List.length spec.m_ensures) else 0)*k, (*post*)
|
702
|
1*k (*trans*)
|
703
|
) in
|
704
|
for case_hyp = 0 to nbcase - 1 do
|
705
|
let case_goal = min (case_hyp+1) (nbcase -1) in
|
706
|
let (nbgoals1, nbgoals2, nbgoals3) = computeAnd case_goal in
|
707
|
let (nbhyp1, nbhyp2, nbhyp3) = computeAnd case_hyp in
|
708
|
let vars = ((List.length inputs) + (List.length outputs) + 1)*case_hyp in
|
709
|
let nbintro = vars + nbhyp1 + nbhyp2 + nbhyp3 in
|
710
|
fprintf fmt "(*Case %i/%i -> %i/%i*)\n" (case_hyp+1) nbcase (case_goal+1) nbcase;
|
711
|
fprintf fmt "(*nb var and hyps in case hyp: %i+%i+%i+%i*)\n" vars nbhyp1 nbhyp2 nbhyp3;
|
712
|
fprintf fmt "(*nb goals in case goal : %i+%i+%i*)\n" nbgoals1 nbgoals2 nbgoals3;
|
713
|
pp_case nbgoals1 nbgoals2 nbgoals3 nbintro nbcase case_hyp case_goal fmt name
|
714
|
done
|
715
|
|
716
|
let pp_code_inv fmt name =
|
717
|
fprintf fmt "intros.\n";
|
718
|
fprintf fmt "eapply Q_inv_inv_%s.\n" name;
|
719
|
fprintf fmt "Focus 4.\n";
|
720
|
fprintf fmt "eassumption.\n";
|
721
|
fprintf fmt "eassumption.\n";
|
722
|
fprintf fmt "eassumption.\n";
|
723
|
fprintf fmt "eassumption.\n"
|
724
|
|
725
|
(*
|
726
|
fprintf fmt "intros;\n";
|
727
|
fprintf fmt "eapply Q_inv_inv_%s;" name;
|
728
|
fprintf fmt "match goal with | |- context [P_Ctrans_%s]=> eassumption | _ => idtac end;\n" name;
|
729
|
fprintf fmt "intuition;\n";
|
730
|
fprintf fmt "(match goal with";
|
731
|
fprintf fmt " | |- context [if ?t then _ else _] => destruct t\n";
|
732
|
fprintf fmt " | _ => idtac\n";
|
733
|
fprintf fmt " end);hnf;try omega;intuition.\n"
|
734
|
*)
|
735
|
|
736
|
let pp_coq_goal name goalname code fmt =
|
737
|
fprintf fmt "Goal %t.\nProof.\n%aQed.\n\n" (fun fmt-> fprintf fmt goalname name) code name
|
738
|
|
739
|
let pp_coq stateless fmt m =
|
740
|
match m.mspec with
|
741
|
| Some _ ->
|
742
|
let name = m.mname.node_id in
|
743
|
if name <> arrow_id then (
|
744
|
pp_coq_goal name "typed_%s_step_post" pp_code_inv fmt;
|
745
|
pp_coq_goal name "typed_ref_%s_step_post" pp_code_inv fmt;
|
746
|
pp_coq_goal name "typed_lemma_inv_inv_%s" (pp_code_inv_inv m) fmt
|
747
|
)
|
748
|
| _ -> ()
|
749
|
|
750
|
end
|
751
|
|
752
|
end
|
753
|
(* Local Variables: *)
|
754
|
(* compile-command:"make -C ../../.." *)
|
755
|
(* End: *)
|