1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
(**{1 CTask backend} *)
open Format
type cfg = {
state_var_name: string;
recvd_ev_name: string;
globals_name: string;
mutable show_models: bool;
}
let cfg = {
state_var_name = "state";
recvd_ev_name = "received";
globals_name = "globals";
show_models = false;
}
module type CTASK = sig
module Static: Static.T
module G: Guest.CTASK
exception Error of string * string
val output: dir:string -> Static.t -> string list
end
module Make (Static: Static.T)
(Guest: Guest.CTASK with module Syntax = Static.Syntax.Guest)
: CTASK with module Static = Static =
struct
module Static = Static
module G = Guest
module Cmodel = Cmodel.Make(Static)
exception Error of string * string
let output_files = ref ([] : string list)
let need_globals m = m.Static.types <> [] || m.Static.fns <> [] || m.Static.csts <> []
let pp_action tab fmt a =
let open Static.Syntax in
match a.Annot.desc with
| Emit id -> fprintf fmt "%snotify_ev(%a);\n" tab Ident.pp id
| Assign (lval, expr) -> fprintf fmt "%s%a = %a;\n" tab Guest.pp_lval lval G.pp_expr expr
let pp_transition tab is_first src fmt (_,{Annot.desc=ev,guards;_},acts,q',_) =
match guards with
| [] ->
List.iter (pp_action tab fmt) acts;
if q' <> src then fprintf fmt "%s%s = %a;\n" tab cfg.state_var_name Ident.pp q'
| _ ->
fprintf fmt "%s%sif ( %a ) {\n"
tab
(if is_first then "" else "else ")
(Ext.List.pp_h ~sep:" && " G.pp_expr) guards;
List.iter (pp_action (tab ^ " ") fmt) acts;
if q' <> src then fprintf fmt "%s %s = %a;\n" tab cfg.state_var_name Ident.pp q';
fprintf fmt "%s }\n" tab
let pp_ev_transition tab src fmt (ev,ts) =
fprintf fmt "%scase %a:\n" tab Ident.pp ev;
Ext.List.iter_fst (fun is_first t -> pp_transition (tab^" ") is_first src fmt t) ts;
fprintf fmt "%sbreak;@." (tab^" ")
let pp_transitions src after evs fmt tss =
if after then fprintf fmt " else {\n";
let tab = if after then " " else " " in
begin match tss with
[] -> ()
| [ev,ts] ->
fprintf fmt "%swait_ev(%a);\n" tab Ident.pp ev;
Ext.List.iter_fst (fun is_first t -> pp_transition tab is_first src fmt t) ts
| _ ->
fprintf fmt "%s%s = wait_evs(%a);\n" tab cfg.recvd_ev_name (Ext.List.pp_h ~sep:"," Ident.pp) evs;
fprintf fmt "%sswitch ( %s ) {\n" tab cfg.recvd_ev_name;
List.iter (pp_ev_transition (tab^" ") src fmt) tss;
fprintf fmt "%s }\n" tab
end;
if after then fprintf fmt " }\n"
let pp_output_valuation fmt (o,e) =
fprintf fmt " %a = %a;\n" Ident.pp o G.pp_expr e
let pp_single_state m fmt Cmodel.{ st_src=q; st_sensibility_list=evs; st_transitions=tss } =
List.iter (pp_output_valuation fmt) (List.assoc q m.Cmodel.c_states);
pp_transitions q false evs fmt tss
let pp_state_case m fmt Cmodel.{ st_src=q; st_sensibility_list=evs; st_transitions=tss } =
fprintf fmt " case %a:\n" Ident.pp q;
List.iter (pp_output_valuation fmt) (List.assoc q m.Cmodel.c_states);
pp_transitions q false evs fmt tss;
fprintf fmt " break;\n"
let pp_state m fmt Cmodel.{ st_src=q; st_sensibility_list=evs; st_transitions=tss } =
pp_transitions q false evs fmt tss
let dump_model fname m =
let open Cmodel in
let oc = open_out fname in
let ocf = formatter_of_out_channel oc in
let modname = String.capitalize_ascii (Ident.to_string m.c_name) in
fprintf ocf "task %s%a(\n"
modname
(Ext.List.pp_opt ~lr:("<",">") ~sep:"," G.pp_typed_symbol) m.c_params;
List.iter (fun io -> fprintf ocf " in %a;\n" G.pp_typed_symbol io) m.c_inps;
List.iter (fun io -> fprintf ocf " out %a;\n" G.pp_typed_symbol io) m.c_outps;
List.iter (fun io -> fprintf ocf " inout %a;\n" G.pp_typed_symbol io) m.c_inouts;
fprintf ocf " )\n";
fprintf ocf "{\n";
List.iter (fun io -> fprintf ocf " %a;\n" G.pp_typed_symbol io) m.c_vars;
if List.length m.c_states > 1 then
fprintf ocf " enum { %a } %s = %a;\n"
(Ext.List.pp_h ~sep:"," Ident.pp) (List.map fst m.c_states)
cfg.state_var_name
Ident.pp (fst m.c_init);
if List.exists (function c -> List.length c.st_sensibility_list > 1) m.c_body then
fprintf ocf " event %s;\n" cfg.recvd_ev_name;
List.iter (pp_action " " ocf) (snd m.c_init);
fprintf ocf " while ( 1 ) {\n";
begin match m.c_body with
[] -> ()
| [q] -> pp_single_state m ocf q
| qs ->
fprintf ocf " switch ( %s ) {\n" cfg.state_var_name;
List.iter (pp_state_case m ocf) m.c_body;
fprintf ocf " }\n"
end;
fprintf ocf " }\n";
fprintf ocf "};@.";
output_files := fname :: !output_files;
close_out oc
let dump_fsm ?(prefix="") ?(dir="./ctask") f =
let c = Cmodel.of_fsm_model f.Static.model in
let prefix = match prefix with "" -> Ident.to_string f.name | p -> p in
dump_model (dir ^ "/" ^ prefix ^ ".c") c
let dump_fsm_model ?(prefix="") ?(dir="./ctask") m =
let c = Cmodel.of_fsm_model m in
let prefix = match prefix with "" -> Ident.to_string m.Annot.desc.Cmodel.Static.Syntax.name | p -> p in
dump_model (dir ^ "/" ^ prefix ^ ".c") c
let dump_fun_decl fmt { Annot.desc = f; _ } =
let open Static.Syntax in
let pp_f_arg fmt (n,t) = fprintf fmt "%a %a" G.pp_type_expr t Ident.pp n in
Format.fprintf fmt "%a %a(%a);\n"
G.pp_type_expr f.ff_res
Ident.pp f.ff_name
(Ext.List.pp_h ~sep:"," pp_f_arg) f.ff_args
let dump_fun_impl fmt { Annot.desc = f; _ } =
let open Static.Syntax in
let pp_f_arg fmt (n,t) = fprintf fmt "%a %a" G.pp_type_expr t Ident.pp n in
Format.fprintf fmt "%a %a(%a) { return %a; }\n"
G.pp_type_expr f.ff_res
Ident.pp f.ff_name
(Ext.List.pp_h ~sep:"," pp_f_arg) f.ff_args
G.pp_expr f.ff_body
let dump_cst_decl fmt { Annot.desc = c; _ } =
let open Static.Syntax in
Format.fprintf fmt "extern %a;\n" G.pp_typed_symbol (c.cc_name,c.cc_typ)
let dump_cst_impl fmt { Annot.desc = c; _ } =
let open Static.Syntax in
Format.fprintf fmt "%a = %a;\n" G.pp_typed_symbol (c.cc_name,c.cc_typ) G.pp_expr c.cc_val
let dump_globals_intf dir prefix s =
let open Static in
let fname = dir ^ "/" ^ prefix ^ ".h" in
let oc = open_out fname in
let ocf = formatter_of_out_channel oc in
fprintf ocf "#ifndef _%s_h\n" cfg.globals_name;
fprintf ocf "#define _%s_h\n\n" cfg.globals_name;
List.iter (fun td -> Format.fprintf ocf "%a\n" G.pp_type_decl td) s.types;
List.iter (dump_fun_decl ocf) s.fns;
List.iter (dump_cst_decl ocf) s.csts;
fprintf ocf "#endif@.";
output_files := fname :: !output_files;
close_out oc
let dump_globals_impl dir prefix s =
let open Static in
let fname = dir ^ "/" ^ prefix ^ ".c" in
let oc = open_out fname in
let ocf = formatter_of_out_channel oc in
fprintf ocf "#include \"%s.h\"\n\n" prefix;
List.iter (dump_fun_impl ocf) s.fns;
List.iter (dump_cst_impl ocf) s.csts;
fprintf ocf "@.";
output_files := fname :: !output_files;
close_out oc
let dump_globals ?(name="") ?(dir="./ctask") s =
let open Static in
let prefix = match name with "" -> cfg.globals_name | p -> p in
dump_globals_intf dir prefix s;
if s.fns <> [] || s.csts <> [] then dump_globals_impl dir prefix s
let output ~dir s =
output_files := [];
if cfg.show_models then
List.iter (dump_fsm_model ~dir) s.Static.models;
if need_globals s then dump_globals ~dir s;
List.iter (dump_fsm ~dir) s.Static.fsms;
!output_files
end