Commit | Line | Data |
---|---|---|
0708f913 | 1 | (* Yoann Padioleau |
ae4735db C |
2 | * |
3 | * Copyright (C) 2010, University of Copenhagen DIKU and INRIA. | |
0708f913 C |
4 | * Copyright (C) 2006, 2007 Ecole des Mines de Nantes |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License (GPL) | |
8 | * version 2 as published by the Free Software Foundation. | |
ae4735db | 9 | * |
0708f913 C |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * file license.txt for more details. | |
14 | *) | |
34e49164 C |
15 | open Common |
16 | ||
17 | open Ast_c | |
18 | open Control_flow_c | |
19 | ||
20 | open Ograph_extended | |
21 | open Oassoc | |
22 | open Oassocb | |
23 | ||
708f4980 C |
24 | module Lib = Lib_parsing_c |
25 | ||
26 | (*****************************************************************************) | |
27 | (* Wrappers *) | |
28 | (*****************************************************************************) | |
29 | let pr2, pr2_once = Common.mk_pr2_wrappers Flag_parsing_c.verbose_cfg | |
34e49164 C |
30 | |
31 | (*****************************************************************************) | |
32 | (* todo?: compute target level with goto (but rare that different I think) | |
ae4735db | 33 | * ver1: just do init, |
34e49164 | 34 | * ver2: compute depth of label (easy, intercept compound in the visitor) |
ae4735db | 35 | * |
34e49164 C |
36 | * checktodo: after a switch, need check that all the st in the |
37 | * compound start with a case: ? | |
ae4735db | 38 | * |
34e49164 C |
39 | * checktodo: how ensure that when we call aux_statement recursivly, we |
40 | * pass it xi_lbl and not just auxinfo ? how enforce that ? | |
41 | * in fact we must either pass a xi_lbl or a newxi | |
ae4735db | 42 | * |
34e49164 C |
43 | * todo: can have code (and so nodes) in many places, in the size of an |
44 | * array, in the init of initializer, but also in StatementExpr, ... | |
ae4735db | 45 | * |
34e49164 C |
46 | * todo?: steal code from CIL ? (but seems complicated ... again) *) |
47 | (*****************************************************************************) | |
48 | ||
485bce71 C |
49 | (*****************************************************************************) |
50 | (* Types *) | |
51 | (*****************************************************************************) | |
52 | ||
ae4735db | 53 | type error = |
34e49164 C |
54 | | DeadCode of Common.parse_info option |
55 | | CaseNoSwitch of Common.parse_info | |
56 | | OnlyBreakInSwitch of Common.parse_info | |
708f4980 | 57 | | WeirdSwitch of Common.parse_info |
34e49164 C |
58 | | NoEnclosingLoop of Common.parse_info |
59 | | GotoCantFindLabel of string * Common.parse_info | |
60 | | NoExit of Common.parse_info | |
61 | | DuplicatedLabel of string | |
62 | | NestedFunc | |
63 | | ComputedGoto | |
91eba41f | 64 | | Define of Common.parse_info |
34e49164 C |
65 | |
66 | exception Error of error | |
67 | ||
68 | (*****************************************************************************) | |
69 | (* Helpers *) | |
70 | (*****************************************************************************) | |
71 | ||
ae4735db | 72 | let add_node node labels nodestr g = |
34e49164 | 73 | g#add_node (Control_flow_c.mk_node node labels [] nodestr) |
ae4735db | 74 | let add_bc_node node labels parent_labels nodestr g = |
34e49164 | 75 | g#add_node (Control_flow_c.mk_node node labels parent_labels nodestr) |
ae4735db | 76 | let add_arc_opt (starti, nodei) g = |
34e49164 C |
77 | starti +> do_option (fun starti -> g#add_arc ((starti, nodei), Direct)) |
78 | ||
79 | ||
ae4735db | 80 | let lbl_0 = [] |
34e49164 C |
81 | |
82 | let pinfo_of_ii ii = Ast_c.get_opi (List.hd ii).Ast_c.pinfo | |
83 | ||
84 | ||
85 | ||
86 | (*****************************************************************************) | |
87 | (* Contextual information passed in aux_statement *) | |
88 | (*****************************************************************************) | |
89 | ||
90 | (* Sometimes have a continue/break and we must know where we must jump. | |
ae4735db C |
91 | * |
92 | * ctl_brace: The node list in context_info record the number of '}' at the | |
34e49164 C |
93 | * context point, for instance at the switch point. So that when deeper, |
94 | * we can compute the difference between the number of '}' from root to | |
ae4735db | 95 | * the context point to close the good number of '}' . For instance |
34e49164 C |
96 | * where there is a 'continue', we must close only until the for. |
97 | *) | |
98 | type context_info = | |
ae4735db | 99 | | NoInfo |
34e49164 C |
100 | | LoopInfo of nodei * nodei (* start, end *) * node list * int list |
101 | | SwitchInfo of nodei * nodei (* start, end *) * node list * int list | |
102 | ||
ae4735db | 103 | (* for the Compound case I need to do different things depending if |
34e49164 C |
104 | * the compound is the compound of the function definition, the compound of |
105 | * a switch, so this type allows to specify this and enable to factorize | |
106 | * code for the Compound | |
107 | *) | |
ae4735db | 108 | and compound_caller = |
34e49164 C |
109 | FunctionDef | Statement | Switch of (nodei -> xinfo -> xinfo) |
110 | ||
ae4735db C |
111 | (* other information used internally in ast_to_flow and passed recursively *) |
112 | and xinfo = { | |
34e49164 C |
113 | |
114 | ctx: context_info; (* cf above *) | |
115 | ctx_stack: context_info list; | |
116 | ||
117 | (* are we under a ifthen[noelse]. Used for ErrorExit *) | |
ae4735db | 118 | under_ifthen: bool; |
34e49164 C |
119 | compound_caller: compound_caller; |
120 | ||
121 | (* does not change recursively. Some kind of globals. *) | |
ae4735db | 122 | labels_assoc: (string, nodei) oassoc; |
34e49164 C |
123 | exiti: nodei option; |
124 | errorexiti: nodei option; | |
125 | ||
126 | (* ctl_braces: the nodei list is to handle current imbrication depth. | |
ae4735db C |
127 | * It contains the must-close '}'. |
128 | * update: now it is instead a node list. | |
34e49164 C |
129 | *) |
130 | braces: node list; | |
131 | ||
132 | (* ctl: *) | |
ae4735db | 133 | labels: int list; |
34e49164 C |
134 | } |
135 | ||
136 | ||
137 | let initial_info = { | |
ae4735db | 138 | ctx = NoInfo; |
34e49164 C |
139 | ctx_stack = []; |
140 | under_ifthen = false; | |
141 | compound_caller = Statement; | |
142 | braces = []; | |
ae4735db | 143 | labels = []; |
34e49164 C |
144 | |
145 | (* don't change when recurse *) | |
146 | labels_assoc = new oassocb []; | |
147 | exiti = None; | |
148 | errorexiti = None; | |
ae4735db | 149 | } |
34e49164 C |
150 | |
151 | ||
152 | (*****************************************************************************) | |
153 | (* (Semi) Globals, Julia's style. *) | |
154 | (*****************************************************************************) | |
155 | (* global graph *) | |
ae4735db | 156 | let g = ref (new ograph_mutable) |
34e49164 C |
157 | |
158 | let counter_for_labels = ref 0 | |
159 | let counter_for_braces = ref 0 | |
160 | ||
161 | (* For switch we use compteur too (or pass int ref) cos need know order of the | |
ae4735db | 162 | * case if then later want to go from CFG to (original) AST. |
34e49164 C |
163 | * update: obsolete now I think |
164 | *) | |
165 | let counter_for_switch = ref 0 | |
166 | ||
167 | ||
168 | (*****************************************************************************) | |
169 | (* helpers *) | |
170 | (*****************************************************************************) | |
171 | ||
ae4735db C |
172 | (* alt: do via a todo list, so can do all in one pass (but more complex) |
173 | * todo: can also count the depth level and associate it to the node, for | |
174 | * the ctl_braces: | |
34e49164 | 175 | *) |
ae4735db | 176 | let compute_labels_and_create_them st = |
34e49164 C |
177 | |
178 | (* map C label to index number in graph *) | |
179 | let (h: (string, nodei) oassoc ref) = ref (new oassocb []) in | |
180 | ||
181 | begin | |
ae4735db C |
182 | st +> Visitor_c.vk_statement { Visitor_c.default_visitor_c with |
183 | Visitor_c.kstatement = (fun (k, bigf) st -> | |
708f4980 | 184 | match Ast_c.unwrap_st st with |
ae4735db | 185 | | Labeled (Ast_c.Label (name, _st)) -> |
708f4980 | 186 | let ii = Ast_c.get_ii_st_take_care st in |
34e49164 C |
187 | (* at this point I put a lbl_0, but later I will put the |
188 | * good labels. *) | |
b1b2de81 | 189 | let s = Ast_c.str_of_name name in |
ae4735db | 190 | let newi = !g +> add_node (Label (st,name, ((),ii))) lbl_0 (s^":") |
b1b2de81 | 191 | in |
34e49164 C |
192 | begin |
193 | (* the C label already exists ? *) | |
194 | if (!h#haskey s) then raise (Error (DuplicatedLabel s)); | |
195 | h := !h#add (s, newi); | |
196 | (* not k _st !!! otherwise in lbl1: lbl2: i++; we miss lbl2 *) | |
ae4735db | 197 | k st; |
34e49164 | 198 | end |
708f4980 | 199 | | _st -> k st |
34e49164 C |
200 | ) |
201 | }; | |
202 | !h; | |
203 | end | |
204 | ||
205 | ||
206 | (* ctl_braces: *) | |
ae4735db C |
207 | let insert_all_braces xs starti = |
208 | xs +> List.fold_left (fun acc node -> | |
209 | (* Have to build a new node (clone), cos cant share it. | |
34e49164 C |
210 | * update: This is now done by the caller. The clones are in xs. |
211 | *) | |
212 | let newi = !g#add_node node in | |
213 | !g#add_arc ((acc, newi), Direct); | |
214 | newi | |
215 | ) starti | |
216 | ||
217 | (*****************************************************************************) | |
218 | (* Statement *) | |
219 | (*****************************************************************************) | |
220 | ||
221 | (* Take in a (optional) start node, return an (optional) end node. | |
ae4735db | 222 | * |
34e49164 | 223 | * history: |
ae4735db | 224 | * |
34e49164 C |
225 | * ver1: old code was returning an nodei, but goto has no end, so |
226 | * aux_statement should return nodei option. | |
ae4735db | 227 | * |
34e49164 C |
228 | * ver2: old code was taking a nodei, but should also take nodei |
229 | * option. | |
ae4735db | 230 | * |
34e49164 C |
231 | * ver3: deadCode detection. What is dead code ? When there is no |
232 | * starti to start from ? So make starti an option too ? Si on arrive | |
233 | * sur un label: au moment d'un deadCode, on peut verifier les | |
234 | * predecesseurs de ce label, auquel cas si y'en a, ca veut dire | |
235 | * qu'en fait c'est pas du deadCode et que donc on peut se permettre | |
236 | * de partir d'un starti à None. Mais si on a xx; goto far:; near: | |
237 | * yy; zz; far: goto near:. Bon ca doit etre un cas tres tres rare, | |
238 | * mais a cause de notre parcours, on va rejeter ce programme car au | |
239 | * moment d'arriver sur near: on n'a pas encore de predecesseurs pour | |
240 | * ce label. De meme, meme le cas simple ou la derniere instruction | |
241 | * c'est un return, alors ca va generer un DeadCode :( | |
ae4735db | 242 | * |
34e49164 C |
243 | * So make a first pass where dont launch exn at all. Create nodes, |
244 | * if starti is None then dont add arc. Then make a second pass that | |
245 | * just checks that all nodes (except enter) have predecessors. | |
246 | * So make starti an option too. So type is now | |
ae4735db | 247 | * |
34e49164 | 248 | * nodei option -> statement -> nodei option. |
ae4735db C |
249 | * |
250 | * todo?: if the pb is at a fake node, then try first successos that | |
251 | * is non fake. | |
252 | * | |
34e49164 C |
253 | * ver4: because of special needs of coccinelle, need pass more info, cf |
254 | * type additionnal_info defined above. | |
ae4735db | 255 | * |
34e49164 C |
256 | * - to complete (break, continue (and enclosing loop), switch (and |
257 | * associated case, casedefault)) we need to pass additionnal info. | |
258 | * The start/exit when enter in a loop, to know the current 'for'. | |
ae4735db | 259 | * |
34e49164 | 260 | * - to handle the braces, need again pass additionnal info. |
ae4735db | 261 | * |
34e49164 | 262 | * - need pass the labels. |
ae4735db | 263 | * |
34e49164 | 264 | * convention: xi for the auxinfo passed recursively |
ae4735db | 265 | * |
34e49164 C |
266 | *) |
267 | ||
ae4735db | 268 | let rec (aux_statement: (nodei option * xinfo) -> statement -> nodei option) = |
34e49164 C |
269 | fun (starti, xi) stmt -> |
270 | ||
271 | if not !Flag_parsing_c.label_strategy_2 | |
272 | then incr counter_for_labels; | |
ae4735db C |
273 | |
274 | let lbl = | |
275 | if !Flag_parsing_c.label_strategy_2 | |
276 | then xi.labels | |
34e49164 C |
277 | else xi.labels @ [!counter_for_labels] |
278 | in | |
279 | ||
280 | (* Normally the new auxinfo to pass recursively to the next aux_statement. | |
281 | * But in some cases we add additionnal stuff in which case we don't use | |
282 | * this 'xi_lbl' but a 'newxi' specially built. | |
283 | *) | |
ae4735db | 284 | let xi_lbl = |
34e49164 C |
285 | if !Flag_parsing_c.label_strategy_2 |
286 | then { xi with | |
287 | compound_caller = Statement; | |
288 | } | |
ae4735db C |
289 | else { xi with |
290 | labels = xi.labels @ [ !counter_for_labels ]; | |
34e49164 | 291 | compound_caller = Statement; |
ae4735db | 292 | } |
34e49164 | 293 | in |
708f4980 C |
294 | let ii = Ast_c.get_ii_st_take_care stmt in |
295 | ||
ae4735db | 296 | (* ------------------------- *) |
708f4980 | 297 | match Ast_c.unwrap_st stmt with |
34e49164 C |
298 | |
299 | (* coupling: the Switch case copy paste parts of the Compound case *) | |
951c7801 | 300 | | Ast_c.Compound statxs -> |
34e49164 C |
301 | (* flow_to_ast: *) |
302 | let (i1, i2) = tuple_of_list2 ii in | |
303 | ||
304 | (* ctl_braces: *) | |
305 | incr counter_for_braces; | |
306 | let brace = !counter_for_braces in | |
307 | ||
308 | let s1 = "{" ^ i_to_s brace in | |
309 | let s2 = "}" ^ i_to_s brace in | |
310 | ||
311 | let lbl = match xi.compound_caller with | |
312 | | FunctionDef -> xi.labels (* share label with function header *) | |
313 | | Statement -> xi.labels @ [!counter_for_labels] | |
314 | | Switch _ -> xi.labels | |
315 | in | |
ae4735db | 316 | |
34e49164 | 317 | let newi = !g +> add_node (SeqStart (stmt, brace, i1)) lbl s1 in |
1b9ae606 | 318 | let endnode = mk_node (SeqEnd (brace, i2)) lbl [] s2 in |
34e49164 C |
319 | let endnode_dup = mk_fake_node (SeqEnd (brace, i2)) lbl [] s2 in |
320 | (* | |
321 | let _endnode_dup = | |
322 | mk_node (SeqEnd (brace, Ast_c.fakeInfo())) lbl [] s2 in | |
323 | *) | |
324 | ||
325 | let newxi = { xi_lbl with braces = endnode_dup:: xi_lbl.braces } in | |
326 | ||
327 | let newxi = match xi.compound_caller with | |
ae4735db | 328 | | Switch todo_in_compound -> |
34e49164 C |
329 | (* note that side effect in todo_in_compound *) |
330 | todo_in_compound newi newxi | |
331 | | FunctionDef | Statement -> newxi | |
332 | in | |
333 | ||
334 | !g +> add_arc_opt (starti, newi); | |
951c7801 | 335 | let finishi = Some newi in |
34e49164 | 336 | |
951c7801 | 337 | aux_statement_list finishi (xi, newxi) statxs |
34e49164 C |
338 | |
339 | (* braces: *) | |
ae4735db | 340 | +> Common.fmap (fun finishi -> |
34e49164 | 341 | (* subtil: not always return a Some. |
951c7801 | 342 | * Note that if finishi is None, alors forcement ca veut dire |
ae4735db | 343 | * qu'il y'a eu un return (ou goto), et donc forcement les |
34e49164 C |
344 | * braces auront au moins ete crée une fois, et donc flow_to_ast |
345 | * marchera. | |
346 | * Sauf si le goto revient en arriere ? mais dans ce cas | |
347 | * ca veut dire que le programme boucle. Pour qu'il boucle pas | |
348 | * il faut forcement au moins un return. | |
349 | *) | |
350 | let endi = !g#add_node endnode in | |
951c7801 C |
351 | if xi.compound_caller = Statement |
352 | then | |
5427db06 C |
353 | (* Problem! This edge is only created if the block does not |
354 | have return on all execution paths. *) | |
951c7801 C |
355 | (let afteri = !g +> add_node AfterNode lbl "[after]" in |
356 | !g#add_arc ((newi, afteri), Direct); | |
357 | !g#add_arc ((afteri, endi), Direct)); | |
358 | !g#add_arc ((finishi, endi), Direct); | |
ae4735db C |
359 | endi |
360 | ) | |
34e49164 C |
361 | |
362 | ||
ae4735db C |
363 | (* ------------------------- *) |
364 | | Labeled (Ast_c.Label (name, st)) -> | |
b1b2de81 | 365 | let s = Ast_c.str_of_name name in |
34e49164 C |
366 | let ilabel = xi.labels_assoc#find s in |
367 | let node = mk_node (unwrap (!g#nodes#find ilabel)) lbl [] (s ^ ":") in | |
368 | !g#replace_node (ilabel, node); | |
369 | !g +> add_arc_opt (starti, ilabel); | |
370 | aux_statement (Some ilabel, xi_lbl) st | |
371 | ||
372 | ||
ae4735db | 373 | | Jump (Ast_c.Goto name) -> |
708f4980 | 374 | let s = Ast_c.str_of_name name in |
34e49164 | 375 | (* special_cfg_ast: *) |
b1b2de81 C |
376 | let newi = !g +> add_node (Goto (stmt, name, ((),ii))) lbl ("goto "^s^":") |
377 | in | |
34e49164 C |
378 | !g +> add_arc_opt (starti, newi); |
379 | ||
951c7801 C |
380 | if !Flag_parsing_c.no_gotos |
381 | then Some newi | |
382 | else | |
383 | begin | |
ae4735db C |
384 | let ilabel = |
385 | try xi.labels_assoc#find s | |
386 | with Not_found -> | |
387 | (* jump vers ErrorExit a la place ? | |
388 | * pourquoi tant de "cant jump" ? pas detecté par gcc ? | |
34e49164 | 389 | *) |
951c7801 C |
390 | raise (Error (GotoCantFindLabel (s, pinfo_of_ii ii))) |
391 | in | |
ae4735db | 392 | (* !g +> add_arc_opt (starti, ilabel); |
951c7801 | 393 | * todo: special_case: suppose that always goto to toplevel of |
ae4735db | 394 | * function, hence the Common.init |
951c7801 C |
395 | * todo?: can perhaps report when a goto is not a classic error_goto ? |
396 | * that is when it does not jump to the toplevel of the function. | |
397 | *) | |
398 | let newi = insert_all_braces (Common.list_init xi.braces) newi in | |
399 | !g#add_arc ((newi, ilabel), Direct); | |
400 | None | |
401 | end | |
ae4735db C |
402 | |
403 | | Jump (Ast_c.GotoComputed e) -> | |
34e49164 | 404 | raise (Error (ComputedGoto)) |
ae4735db C |
405 | |
406 | (* ------------------------- *) | |
407 | | Ast_c.ExprStatement opte -> | |
34e49164 | 408 | (* flow_to_ast: old: when opte = None, then do not add in CFG. *) |
ae4735db | 409 | let s = |
34e49164 C |
410 | match opte with |
411 | | None -> "empty;" | |
ae4735db | 412 | | Some e -> |
708f4980 | 413 | (match Ast_c.unwrap_expr e with |
ae4735db | 414 | | FunCall (e, _args) -> |
708f4980 | 415 | (match Ast_c.unwrap_expr e with |
ae4735db | 416 | | Ident namef -> |
708f4980 C |
417 | Ast_c.str_of_name namef ^ "(...)" |
418 | | _ -> "statement" | |
419 | ) | |
ae4735db | 420 | | Assignment (e1, SimpleAssign, e2) -> |
708f4980 C |
421 | (match Ast_c.unwrap_expr e1 with |
422 | | Ident namevar -> | |
423 | Ast_c.str_of_name namevar ^ " = ... ;" | |
ae4735db | 424 | | RecordAccess(e, field) -> |
708f4980 | 425 | (match Ast_c.unwrap_expr e with |
ae4735db | 426 | | Ident namevar -> |
708f4980 C |
427 | let sfield = Ast_c.str_of_name field in |
428 | Ast_c.str_of_name namevar ^ "." ^ sfield ^ " = ... ;" | |
429 | | _ -> "statement" | |
430 | ) | |
431 | | _ -> "statement" | |
432 | ) | |
34e49164 | 433 | | _ -> "statement" |
708f4980 | 434 | ) |
34e49164 C |
435 | in |
436 | let newi = !g +> add_node (ExprStatement (stmt, (opte, ii))) lbl s in | |
437 | !g +> add_arc_opt (starti, newi); | |
438 | Some newi | |
34e49164 | 439 | |
ae4735db C |
440 | |
441 | (* ------------------------- *) | |
708f4980 C |
442 | | Selection (Ast_c.If (e, st1, st2)) -> |
443 | ||
444 | let iist2 = Ast_c.get_ii_st_take_care st2 in | |
445 | (match Ast_c.unwrap_st st2 with | |
ae4735db | 446 | | Ast_c.ExprStatement (None) when null iist2 -> |
951c7801 | 447 | (* sometime can have ExprStatement None but it is a if-then-else, |
34e49164 | 448 | * because something like if() xx else ; |
ae4735db | 449 | * so must force to have [] in the ii associated with ExprStatement |
34e49164 | 450 | *) |
ae4735db | 451 | |
34e49164 C |
452 | let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in |
453 | let ii = [i1;i2;i3] in | |
454 | (* starti -> newi ---> newfakethen -> ... -> finalthen --> lasti | |
455 | * | | | |
456 | * |-> newfakeelse -> ... -> finalelse -| | |
457 | * update: there is now also a link directly to lasti. | |
ae4735db | 458 | * |
34e49164 C |
459 | * because of CTL, now do different things if we are in a ifthen or |
460 | * ifthenelse. | |
461 | *) | |
462 | let newi = !g +> add_node (IfHeader (stmt, (e, ii))) lbl ("if") in | |
463 | !g +> add_arc_opt (starti, newi); | |
464 | let newfakethen = !g +> add_node TrueNode lbl "[then]" in | |
465 | let newfakeelse = !g +> add_node FallThroughNode lbl "[fallthrough]" in | |
466 | let afteri = !g +> add_node AfterNode lbl "[after]" in | |
467 | let lasti = !g +> add_node (EndStatement (Some iifakeend)) lbl "[endif]" | |
468 | in | |
469 | ||
470 | (* for ErrorExit heuristic *) | |
471 | let newxi = { xi_lbl with under_ifthen = true; } in | |
472 | ||
473 | !g#add_arc ((newi, newfakethen), Direct); | |
474 | !g#add_arc ((newi, newfakeelse), Direct); | |
475 | !g#add_arc ((newi, afteri), Direct); | |
476 | !g#add_arc ((afteri, lasti), Direct); | |
477 | !g#add_arc ((newfakeelse, lasti), Direct); | |
478 | ||
479 | let finalthen = aux_statement (Some newfakethen, newxi) st1 in | |
480 | !g +> add_arc_opt (finalthen, lasti); | |
481 | Some lasti | |
482 | ||
ae4735db | 483 | | _unwrap_st2 -> |
34e49164 C |
484 | (* starti -> newi ---> newfakethen -> ... -> finalthen --> lasti |
485 | * | | | |
486 | * |-> newfakeelse -> ... -> finalelse -| | |
487 | * update: there is now also a link directly to lasti. | |
488 | *) | |
ae4735db | 489 | let (iiheader, iielse, iifakeend) = |
34e49164 C |
490 | match ii with |
491 | | [i1;i2;i3;i4;i5] -> [i1;i2;i3], i4, i5 | |
abad11c5 | 492 | | _ -> raise (Impossible 62) |
34e49164 C |
493 | in |
494 | let newi = !g +> add_node (IfHeader (stmt, (e, iiheader))) lbl "if" in | |
495 | !g +> add_arc_opt (starti, newi); | |
496 | let newfakethen = !g +> add_node TrueNode lbl "[then]" in | |
497 | let newfakeelse = !g +> add_node FalseNode lbl "[else]" in | |
498 | let elsenode = !g +> add_node (Else iielse) lbl "else" in | |
499 | ||
500 | ||
501 | !g#add_arc ((newi, newfakethen), Direct); | |
502 | !g#add_arc ((newi, newfakeelse), Direct); | |
503 | ||
504 | !g#add_arc ((newfakeelse, elsenode), Direct); | |
505 | ||
506 | let finalthen = aux_statement (Some newfakethen, xi_lbl) st1 in | |
507 | let finalelse = aux_statement (Some elsenode, xi_lbl) st2 in | |
508 | ||
ae4735db | 509 | (match finalthen, finalelse with |
34e49164 | 510 | | (None, None) -> None |
ae4735db C |
511 | | _ -> |
512 | let lasti = | |
34e49164 | 513 | !g +> add_node (EndStatement(Some iifakeend)) lbl "[endif]" in |
ae4735db | 514 | let afteri = |
34e49164 C |
515 | !g +> add_node AfterNode lbl "[after]" in |
516 | !g#add_arc ((newi, afteri), Direct); | |
517 | !g#add_arc ((afteri, lasti), Direct); | |
518 | begin | |
519 | !g +> add_arc_opt (finalthen, lasti); | |
520 | !g +> add_arc_opt (finalelse, lasti); | |
521 | Some lasti | |
522 | end) | |
ae4735db C |
523 | ) |
524 | ||
525 | (* ------------------------- *) | |
526 | | Selection (Ast_c.Switch (e, st)) -> | |
34e49164 | 527 | let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in |
1b9ae606 | 528 | |
34e49164 C |
529 | let ii = [i1;i2;i3] in |
530 | ||
531 | (* The newswitchi is for the labels to know where to attach. | |
532 | * The newendswitch (endi) is for the 'break'. *) | |
ae4735db | 533 | let newswitchi= |
1b9ae606 | 534 | !g +> add_node (SwitchHeader(stmt,(e,ii))) lbl "switch" in |
ae4735db | 535 | let newendswitch = |
34e49164 C |
536 | !g +> add_node (EndStatement (Some iifakeend)) lbl "[endswitch]" in |
537 | ||
538 | !g +> add_arc_opt (starti, newswitchi); | |
539 | ||
540 | (* call compound case. Need special info to pass to compound case | |
541 | * because we need to build a context_info that need some of the | |
542 | * information build inside the compound case: the nodei of { | |
543 | *) | |
ae4735db | 544 | let finalthen = |
708f4980 | 545 | match Ast_c.unwrap_st st with |
ae4735db | 546 | | Ast_c.Compound statxs -> |
708f4980 C |
547 | |
548 | let statxs = Lib.stmt_elems_of_sequencable statxs in | |
ae4735db | 549 | |
34e49164 C |
550 | (* todo? we should not allow to match a stmt that corresponds |
551 | * to a compound of a switch, so really SeqStart (stmt, ...) | |
552 | * here ? so maybe should change the SeqStart labeling too. | |
553 | * So need pass a todo_in_compound2 function. | |
554 | *) | |
ae4735db C |
555 | let todo_in_compound newi newxi = |
556 | let newxi' = { newxi with | |
34e49164 C |
557 | ctx = SwitchInfo (newi(*!!*), newendswitch, xi.braces, lbl); |
558 | ctx_stack = newxi.ctx::newxi.ctx_stack | |
559 | } | |
560 | in | |
ae4735db C |
561 | !g#add_arc ((newswitchi, newi), Direct); |
562 | (* new: if have not a default case, then must add an edge | |
34e49164 | 563 | * between start to end. |
ae4735db | 564 | * todo? except if the case[range] coverthe whole spectrum |
34e49164 | 565 | *) |
ae4735db | 566 | if not (statxs +> List.exists (fun x -> |
708f4980 C |
567 | match Ast_c.unwrap_st x with |
568 | | Labeled (Ast_c.Default _) -> true | |
569 | | _ -> false | |
34e49164 C |
570 | )) |
571 | then begin | |
ae4735db | 572 | (* when there is no default, then a valid path is |
34e49164 C |
573 | * from the switchheader to the end. In between we |
574 | * add a Fallthrough. | |
575 | *) | |
576 | ||
577 | let newafter = !g+>add_node FallThroughNode lbl "[switchfall]" | |
578 | in | |
579 | !g#add_arc ((newafter, newendswitch), Direct); | |
580 | !g#add_arc ((newswitchi, newafter), Direct); | |
581 | (* old: | |
582 | !g#add_arc ((newswitchi, newendswitch), Direct) +> adjust_g; | |
583 | *) | |
584 | end; | |
585 | newxi' | |
586 | in | |
fc1ad971 | 587 | let newxi = { xi_lbl with compound_caller = (* was xi *) |
ae4735db C |
588 | Switch todo_in_compound |
589 | } | |
34e49164 C |
590 | in |
591 | aux_statement (None (* no starti *), newxi) st | |
ae4735db C |
592 | | _x -> |
593 | (* apparently gcc allows some switch body such as | |
708f4980 C |
594 | * switch (i) case 0 : printf("here\n"); |
595 | * cf tests-bis/switch_no_body.c | |
596 | * but I don't think it's worthwile to handle | |
597 | * such pathological and rare case. Not worth | |
598 | * the complexity. Safe to assume a coumpound. | |
599 | *) | |
600 | raise (Error (WeirdSwitch (pinfo_of_ii [i1]))) | |
34e49164 C |
601 | in |
602 | !g +> add_arc_opt (finalthen, newendswitch); | |
603 | ||
604 | ||
605 | (* what if has only returns inside. We must try to see if the | |
ae4735db | 606 | * newendswitch has been used via a 'break;' or because no |
34e49164 C |
607 | * 'default:') |
608 | *) | |
ae4735db | 609 | let res = |
34e49164 | 610 | (match finalthen with |
ae4735db | 611 | | Some finalthen -> |
34e49164 C |
612 | |
613 | let afteri = !g +> add_node AfterNode lbl "[after]" in | |
614 | !g#add_arc ((newswitchi, afteri), Direct); | |
615 | !g#add_arc ((afteri, newendswitch), Direct); | |
616 | ||
617 | ||
618 | !g#add_arc ((finalthen, newendswitch), Direct); | |
619 | Some newendswitch | |
ae4735db | 620 | | None -> |
34e49164 C |
621 | if (!g#predecessors newendswitch)#null |
622 | then begin | |
623 | assert ((!g#successors newendswitch)#null); | |
624 | !g#del_node newendswitch; | |
625 | None | |
626 | end | |
627 | else begin | |
628 | ||
629 | let afteri = !g +> add_node AfterNode lbl "[after]" in | |
630 | !g#add_arc ((newswitchi, afteri), Direct); | |
631 | !g#add_arc ((afteri, newendswitch), Direct); | |
632 | ||
633 | ||
634 | Some newendswitch | |
635 | end | |
636 | ) | |
637 | in | |
638 | res | |
ae4735db | 639 | |
34e49164 | 640 | |
708f4980 | 641 | | Labeled (Ast_c.Case (_, _)) |
ae4735db | 642 | | Labeled (Ast_c.CaseRange (_, _, _)) -> |
34e49164 C |
643 | |
644 | incr counter_for_switch; | |
645 | let switchrank = !counter_for_switch in | |
ae4735db C |
646 | let node, st = |
647 | match Ast_c.get_st_and_ii stmt with | |
648 | | Labeled (Ast_c.Case (e, st)), ii -> | |
34e49164 | 649 | (Case (stmt, (e, ii))), st |
ae4735db | 650 | | Labeled (Ast_c.CaseRange (e, e2, st)), ii -> |
34e49164 | 651 | (CaseRange (stmt, ((e, e2), ii))), st |
abad11c5 | 652 | | _ -> raise (Impossible 63) |
34e49164 C |
653 | in |
654 | ||
655 | let newi = !g +> add_node node lbl "case:" in | |
656 | ||
ae4735db | 657 | (match Common.optionise (fun () -> |
34e49164 | 658 | (* old: xi.ctx *) |
ae4735db | 659 | (xi.ctx::xi.ctx_stack) +> Common.find_some (function |
34e49164 C |
660 | | SwitchInfo (a, b, c, _) -> Some (a, b, c) |
661 | | _ -> None | |
662 | )) | |
663 | with | |
ae4735db | 664 | | Some (startbrace, switchendi, _braces) -> |
34e49164 C |
665 | (* no need to attach to previous for the first case, cos would be |
666 | * redundant. *) | |
ae4735db | 667 | starti +> do_option (fun starti -> |
34e49164 | 668 | if starti <> startbrace |
ae4735db | 669 | then !g +> add_arc_opt (Some starti, newi); |
34e49164 C |
670 | ); |
671 | ||
672 | let s = ("[casenode] " ^ i_to_s switchrank) in | |
673 | let newcasenodei = !g +> add_node (CaseNode switchrank) lbl s in | |
674 | !g#add_arc ((startbrace, newcasenodei), Direct); | |
675 | !g#add_arc ((newcasenodei, newi), Direct); | |
676 | | None -> raise (Error (CaseNoSwitch (pinfo_of_ii ii))) | |
677 | ); | |
678 | aux_statement (Some newi, xi_lbl) st | |
34e49164 | 679 | |
ae4735db C |
680 | |
681 | | Labeled (Ast_c.Default st) -> | |
34e49164 C |
682 | incr counter_for_switch; |
683 | let switchrank = !counter_for_switch in | |
684 | ||
685 | let newi = !g +> add_node (Default(stmt, ((),ii))) lbl "case default:" in | |
686 | !g +> add_arc_opt (starti, newi); | |
687 | ||
688 | (match xi.ctx with | |
ae4735db | 689 | | SwitchInfo (startbrace, switchendi, _braces, _parent_lbl) -> |
34e49164 C |
690 | let s = ("[casenode] " ^ i_to_s switchrank) in |
691 | let newcasenodei = !g +> add_node (CaseNode switchrank) lbl s in | |
692 | !g#add_arc ((startbrace, newcasenodei), Direct); | |
693 | !g#add_arc ((newcasenodei, newi), Direct); | |
694 | | _ -> raise (Error (CaseNoSwitch (pinfo_of_ii ii))) | |
695 | ); | |
696 | aux_statement (Some newi, xi_lbl) st | |
697 | ||
698 | ||
699 | ||
700 | ||
701 | ||
702 | ||
ae4735db C |
703 | (* ------------------------- *) |
704 | | Iteration (Ast_c.While (e, st)) -> | |
34e49164 C |
705 | (* starti -> newi ---> newfakethen -> ... -> finalthen - |
706 | * |---|-----------------------------------| | |
ae4735db | 707 | * |-> newfakelse |
34e49164 C |
708 | *) |
709 | ||
710 | let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in | |
711 | let ii = [i1;i2;i3] in | |
712 | ||
713 | let newi = !g +> add_node (WhileHeader (stmt, (e,ii))) lbl "while" in | |
714 | !g +> add_arc_opt (starti, newi); | |
715 | let newfakethen = !g +> add_node InLoopNode lbl "[whiletrue]" in | |
716 | (* let newfakeelse = !g +> add_node FalseNode lbl "[endwhile]" in *) | |
951c7801 | 717 | let newafter = !g +> add_node LoopFallThroughNode lbl "[whilefall]" in |
ae4735db | 718 | let newfakeelse = |
34e49164 C |
719 | !g +> add_node (EndStatement (Some iifakeend)) lbl "[endwhile]" in |
720 | ||
721 | let newxi = { xi_lbl with | |
722 | ctx = LoopInfo (newi, newfakeelse, xi_lbl.braces, lbl); | |
723 | ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack | |
724 | } | |
725 | in | |
726 | ||
727 | !g#add_arc ((newi, newfakethen), Direct); | |
728 | !g#add_arc ((newafter, newfakeelse), Direct); | |
729 | !g#add_arc ((newi, newafter), Direct); | |
730 | let finalthen = aux_statement (Some newfakethen, newxi) st in | |
978fd7e5 C |
731 | !g +> add_arc_opt |
732 | (finalthen, if !Flag_parsing_c.no_loops then newafter else newi); | |
34e49164 C |
733 | Some newfakeelse |
734 | ||
ae4735db | 735 | |
34e49164 | 736 | (* This time, may return None, for instance if goto in body of dowhile |
ae4735db | 737 | * (whereas While cant return None). But if return None, certainly |
34e49164 C |
738 | * some deadcode. |
739 | *) | |
ae4735db | 740 | | Iteration (Ast_c.DoWhile (st, e)) -> |
34e49164 C |
741 | (* starti -> doi ---> ... ---> finalthen (opt) ---> whiletaili |
742 | * |--------- newfakethen ---------------| |---> newfakelse | |
743 | *) | |
ae4735db | 744 | let is_zero = |
34e49164 | 745 | match Ast_c.unwrap_expr e with |
708f4980 | 746 | | Constant (Int ("0",_)) -> true |
34e49164 C |
747 | | _ -> false |
748 | in | |
749 | ||
ae4735db | 750 | let (iido, iiwhiletail, iifakeend) = |
34e49164 C |
751 | match ii with |
752 | | [i1;i2;i3;i4;i5;i6] -> i1, [i2;i3;i4;i5], i6 | |
abad11c5 | 753 | | _ -> raise (Impossible 64) |
34e49164 C |
754 | in |
755 | let doi = !g +> add_node (DoHeader (stmt, iido)) lbl "do" in | |
756 | !g +> add_arc_opt (starti, doi); | |
757 | let taili = !g +> add_node (DoWhileTail (e, iiwhiletail)) lbl "whiletail" | |
758 | in | |
ae4735db | 759 | |
34e49164 C |
760 | |
761 | (*let newfakeelse = !g +> add_node FalseNode lbl "[enddowhile]" in *) | |
762 | let newafter = !g +> add_node FallThroughNode lbl "[dowhilefall]" in | |
ae4735db | 763 | let newfakeelse = |
34e49164 C |
764 | !g +> add_node (EndStatement (Some iifakeend)) lbl "[enddowhile]" in |
765 | ||
951c7801 C |
766 | let afteri = !g +> add_node AfterNode lbl "[after]" in |
767 | !g#add_arc ((doi,afteri), Direct); | |
768 | !g#add_arc ((afteri,newfakeelse), Direct); | |
769 | ||
34e49164 C |
770 | let newxi = { xi_lbl with |
771 | ctx = LoopInfo (taili, newfakeelse, xi_lbl.braces, lbl); | |
772 | ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack | |
773 | } | |
774 | in | |
775 | ||
951c7801 | 776 | if not is_zero && (not !Flag_parsing_c.no_loops) |
34e49164 C |
777 | then begin |
778 | let newfakethen = !g +> add_node InLoopNode lbl "[dowhiletrue]" in | |
ae4735db C |
779 | !g#add_arc ((taili, newfakethen), Direct); |
780 | !g#add_arc ((newfakethen, doi), Direct); | |
34e49164 C |
781 | end; |
782 | ||
783 | !g#add_arc ((newafter, newfakeelse), Direct); | |
784 | !g#add_arc ((taili, newafter), Direct); | |
785 | ||
786 | ||
ae4735db | 787 | let finalthen = aux_statement (Some doi, newxi) st in |
34e49164 | 788 | (match finalthen with |
ae4735db | 789 | | None -> |
34e49164 C |
790 | if (!g#predecessors taili)#null |
791 | then raise (Error (DeadCode (Some (pinfo_of_ii ii)))) | |
792 | else Some newfakeelse | |
ae4735db | 793 | | Some finali -> |
34e49164 C |
794 | !g#add_arc ((finali, taili), Direct); |
795 | Some newfakeelse | |
796 | ) | |
34e49164 C |
797 | |
798 | ||
ae4735db C |
799 | |
800 | | Iteration (Ast_c.For (e1opt, e2opt, e3opt, st)) -> | |
34e49164 C |
801 | let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in |
802 | let ii = [i1;i2;i3] in | |
803 | ||
ae4735db | 804 | let newi = |
34e49164 C |
805 | !g+>add_node(ForHeader(stmt,((e1opt,e2opt,e3opt),ii))) lbl "for" in |
806 | !g +> add_arc_opt (starti, newi); | |
807 | let newfakethen = !g +> add_node InLoopNode lbl "[fortrue]" in | |
808 | (*let newfakeelse = !g +> add_node FalseNode lbl "[endfor]" in*) | |
951c7801 | 809 | let newafter = !g +> add_node LoopFallThroughNode lbl "[forfall]" in |
ae4735db | 810 | let newfakeelse = |
34e49164 C |
811 | !g +> add_node (EndStatement (Some iifakeend)) lbl "[endfor]" in |
812 | ||
813 | let newxi = { xi_lbl with | |
ae4735db | 814 | ctx = LoopInfo (newi, newfakeelse, xi_lbl.braces, lbl); |
34e49164 C |
815 | ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack |
816 | } | |
817 | in | |
818 | ||
819 | !g#add_arc ((newi, newfakethen), Direct); | |
820 | !g#add_arc ((newafter, newfakeelse), Direct); | |
821 | !g#add_arc ((newi, newafter), Direct); | |
822 | let finalthen = aux_statement (Some newfakethen, newxi) st in | |
978fd7e5 | 823 | !g +> add_arc_opt |
951c7801 C |
824 | (finalthen, |
825 | if !Flag_parsing_c.no_loops then newafter else newi); | |
34e49164 C |
826 | Some newfakeelse |
827 | ||
828 | ||
829 | (* to generate less exception with the breakInsideLoop, analyse | |
830 | * correctly the loop deguisé comme list_for_each. Add a case ForMacro | |
831 | * in ast_c (and in lexer/parser), and then do code that imitates the | |
ae4735db C |
832 | * code for the For. |
833 | * update: the list_for_each was previously converted into Tif by the | |
34e49164 C |
834 | * lexer, now they are returned as Twhile so less pbs. But not perfect. |
835 | * update: now I recognize the list_for_each macro so no more problems. | |
836 | *) | |
ae4735db | 837 | | Iteration (Ast_c.MacroIteration (s, es, st)) -> |
34e49164 C |
838 | let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in |
839 | let ii = [i1;i2;i3] in | |
840 | ||
ae4735db | 841 | let newi = |
34e49164 C |
842 | !g+>add_node(MacroIterHeader(stmt,((s,es),ii))) lbl "foreach" in |
843 | !g +> add_arc_opt (starti, newi); | |
844 | let newfakethen = !g +> add_node InLoopNode lbl "[fortrue]" in | |
845 | (*let newfakeelse = !g +> add_node FalseNode lbl "[endfor]" in*) | |
951c7801 | 846 | let newafter = !g +> add_node LoopFallThroughNode lbl "[foreachfall]" in |
ae4735db | 847 | let newfakeelse = |
34e49164 C |
848 | !g +> add_node (EndStatement (Some iifakeend)) lbl "[endforeach]" in |
849 | ||
850 | let newxi = { xi_lbl with | |
ae4735db | 851 | ctx = LoopInfo (newi, newfakeelse, xi_lbl.braces, lbl); |
34e49164 C |
852 | ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack |
853 | } | |
854 | in | |
855 | ||
856 | !g#add_arc ((newi, newfakethen), Direct); | |
857 | !g#add_arc ((newafter, newfakeelse), Direct); | |
858 | !g#add_arc ((newi, newafter), Direct); | |
859 | let finalthen = aux_statement (Some newfakethen, newxi) st in | |
978fd7e5 | 860 | !g +> add_arc_opt |
951c7801 C |
861 | (finalthen, |
862 | if !Flag_parsing_c.no_loops then newafter else newi); | |
34e49164 C |
863 | Some newfakeelse |
864 | ||
865 | ||
866 | ||
ae4735db C |
867 | (* ------------------------- *) |
868 | | Jump ((Ast_c.Continue|Ast_c.Break) as x) -> | |
34e49164 C |
869 | let context_info = |
870 | match xi.ctx with | |
ae4735db | 871 | SwitchInfo (startbrace, loopendi, braces, parent_lbl) -> |
b1b2de81 | 872 | if x =*= Ast_c.Break |
34e49164 C |
873 | then xi.ctx |
874 | else | |
ae4735db C |
875 | (try |
876 | xi.ctx_stack +> Common.find_some (function | |
34e49164 C |
877 | LoopInfo (_,_,_,_) as c -> Some c |
878 | | _ -> None) | |
ae4735db | 879 | with Not_found -> |
34e49164 C |
880 | raise (Error (OnlyBreakInSwitch (pinfo_of_ii ii)))) |
881 | | LoopInfo (loopstarti, loopendi, braces, parent_lbl) -> xi.ctx | |
882 | | NoInfo -> raise (Error (NoEnclosingLoop (pinfo_of_ii ii))) in | |
883 | ||
884 | let parent_label = | |
885 | match context_info with | |
886 | LoopInfo (loopstarti, loopendi, braces, parent_lbl) -> parent_lbl | |
887 | | SwitchInfo (startbrace, loopendi, braces, parent_lbl) -> parent_lbl | |
abad11c5 | 888 | | NoInfo -> raise (Impossible 65) in |
34e49164 C |
889 | |
890 | (* flow_to_ast: *) | |
891 | let (node_info, string) = | |
892 | let parent_string = | |
893 | String.concat "," (List.map string_of_int parent_label) in | |
894 | (match x with | |
895 | | Ast_c.Continue -> | |
896 | (Continue (stmt, ((), ii)), | |
897 | Printf.sprintf "continue; [%s]" parent_string) | |
898 | | Ast_c.Break -> | |
899 | (Break (stmt, ((), ii)), | |
900 | Printf.sprintf "break; [%s]" parent_string) | |
abad11c5 | 901 | | _ -> raise (Impossible 66) |
34e49164 C |
902 | ) in |
903 | ||
904 | (* idea: break or continue records the label of its parent loop or | |
905 | switch *) | |
906 | let newi = !g +> add_bc_node node_info lbl parent_label string in | |
907 | !g +> add_arc_opt (starti, newi); | |
908 | ||
909 | (* let newi = some starti in *) | |
910 | ||
911 | (match context_info with | |
ae4735db C |
912 | | LoopInfo (loopstarti, loopendi, braces, parent_lbl) -> |
913 | let desti = | |
914 | (match x with | |
915 | | Ast_c.Break -> loopendi | |
951c7801 C |
916 | | Ast_c.Continue -> |
917 | (* if no loops, then continue behaves like break - just | |
918 | one iteration *) | |
ae4735db | 919 | if !Flag_parsing_c.no_loops then loopendi else loopstarti |
abad11c5 | 920 | | x -> raise (Impossible 67) |
34e49164 C |
921 | ) in |
922 | let difference = List.length xi.braces - List.length braces in | |
923 | assert (difference >= 0); | |
924 | let toend = take difference xi.braces in | |
925 | let newi = insert_all_braces toend newi in | |
926 | !g#add_arc ((newi, desti), Direct); | |
927 | None | |
928 | ||
929 | | SwitchInfo (startbrace, loopendi, braces, parent_lbl) -> | |
b1b2de81 | 930 | assert (x =*= Ast_c.Break); |
34e49164 C |
931 | let difference = List.length xi.braces - List.length braces in |
932 | assert (difference >= 0); | |
933 | let toend = take difference xi.braces in | |
934 | let newi = insert_all_braces toend newi in | |
935 | !g#add_arc ((newi, loopendi), Direct); | |
936 | None | |
abad11c5 | 937 | | NoInfo -> raise (Impossible 68) |
34e49164 C |
938 | ) |
939 | ||
ae4735db | 940 | | Jump ((Ast_c.Return | Ast_c.ReturnExpr _) as kind) -> |
34e49164 C |
941 | (match xi.exiti, xi.errorexiti with |
942 | | None, None -> raise (Error (NoExit (pinfo_of_ii ii))) | |
ae4735db | 943 | | Some exiti, Some errorexiti -> |
34e49164 C |
944 | |
945 | (* flow_to_ast: *) | |
ae4735db | 946 | let s = |
34e49164 C |
947 | match kind with |
948 | | Ast_c.Return -> "return" | |
949 | | Ast_c.ReturnExpr _ -> "return ..." | |
abad11c5 | 950 | | _ -> raise (Impossible 69) |
34e49164 | 951 | in |
ae4735db C |
952 | let newi = |
953 | !g +> add_node | |
34e49164 C |
954 | (match kind with |
955 | | Ast_c.Return -> Return (stmt, ((),ii)) | |
956 | | Ast_c.ReturnExpr e -> ReturnExpr (stmt, (e, ii)) | |
abad11c5 | 957 | | _ -> raise (Impossible 70) |
34e49164 C |
958 | ) |
959 | lbl s | |
960 | in | |
961 | !g +> add_arc_opt (starti, newi); | |
962 | let newi = insert_all_braces xi.braces newi in | |
963 | ||
964 | if xi.under_ifthen | |
965 | then !g#add_arc ((newi, errorexiti), Direct) | |
966 | else !g#add_arc ((newi, exiti), Direct) | |
967 | ; | |
968 | None | |
abad11c5 | 969 | | _ -> raise (Impossible 71) |
34e49164 C |
970 | ) |
971 | ||
972 | ||
ae4735db C |
973 | (* ------------------------- *) |
974 | | Ast_c.Decl decl -> | |
975 | let s = | |
34e49164 | 976 | match decl with |
ae4735db | 977 | | (Ast_c.DeclList |
b1b2de81 C |
978 | ([{v_namei = Some (name, _); v_type = typ; v_storage = sto}, _], _)) -> |
979 | "decl:" ^ Ast_c.str_of_name name | |
34e49164 C |
980 | | _ -> "decl_novar_or_multivar" |
981 | in | |
ae4735db | 982 | |
34e49164 C |
983 | let newi = !g +> add_node (Decl (decl)) lbl s in |
984 | !g +> add_arc_opt (starti, newi); | |
985 | Some newi | |
ae4735db C |
986 | |
987 | (* ------------------------- *) | |
988 | | Ast_c.Asm body -> | |
34e49164 C |
989 | let newi = !g +> add_node (Asm (stmt, ((body,ii)))) lbl "asm;" in |
990 | !g +> add_arc_opt (starti, newi); | |
991 | Some newi | |
992 | ||
ae4735db | 993 | | Ast_c.MacroStmt -> |
34e49164 C |
994 | let newi = !g +> add_node (MacroStmt (stmt, ((),ii))) lbl "macro;" in |
995 | !g +> add_arc_opt (starti, newi); | |
996 | Some newi | |
997 | ||
998 | ||
ae4735db C |
999 | (* ------------------------- *) |
1000 | | Ast_c.NestedFunc def -> | |
34e49164 | 1001 | raise (Error NestedFunc) |
34e49164 C |
1002 | |
1003 | ||
1004 | ||
485bce71 C |
1005 | |
1006 | ||
1007 | ||
ae4735db C |
1008 | |
1009 | and aux_statement_list starti (xi, newxi) statxs = | |
1010 | statxs | |
485bce71 C |
1011 | +> List.fold_left (fun starti statement_seq -> |
1012 | if !Flag_parsing_c.label_strategy_2 | |
1013 | then incr counter_for_labels; | |
ae4735db C |
1014 | |
1015 | let newxi' = | |
485bce71 | 1016 | if !Flag_parsing_c.label_strategy_2 |
ae4735db | 1017 | then { newxi with labels = xi.labels @ [ !counter_for_labels ] } |
485bce71 C |
1018 | else newxi |
1019 | in | |
1020 | ||
1021 | match statement_seq with | |
ae4735db | 1022 | | Ast_c.StmtElem statement -> |
485bce71 C |
1023 | aux_statement (starti, newxi') statement |
1024 | ||
ae4735db | 1025 | | Ast_c.CppDirectiveStmt directive -> |
485bce71 C |
1026 | pr2_once ("ast_to_flow: filter a directive"); |
1027 | starti | |
1028 | ||
ae4735db | 1029 | | Ast_c.IfdefStmt ifdef -> |
485bce71 C |
1030 | pr2_once ("ast_to_flow: filter a directive"); |
1031 | starti | |
1032 | ||
ae4735db | 1033 | | Ast_c.IfdefStmt2 (ifdefs, xxs) -> |
485bce71 C |
1034 | |
1035 | let (head, body, tail) = Common.head_middle_tail ifdefs in | |
1036 | ||
8babbc8f C |
1037 | let newi = |
1038 | !g +> add_node (IfdefHeader (head)) newxi'.labels "[ifdef]" in | |
1039 | let taili = | |
1040 | !g +> add_node (IfdefEndif (tail)) newxi'.labels "[endif]" in | |
1041 | (* do like for a close brace, see endi.{c,cocci} *) | |
1042 | let taili_dup = | |
1043 | mk_fake_node (IfdefEndif (tail)) newxi'.labels [] "[endif]" in | |
485bce71 C |
1044 | !g +> add_arc_opt (starti, newi); |
1045 | ||
ae4735db C |
1046 | let elsenodes = |
1047 | body +> List.map (fun elseif -> | |
1048 | let elsei = | |
485bce71 C |
1049 | !g +> add_node (IfdefElse (elseif)) newxi'.labels "[elseif]" in |
1050 | !g#add_arc ((newi, elsei), Direct); | |
1051 | elsei | |
1052 | ) in | |
1053 | ||
ae4735db C |
1054 | let _finalxs = |
1055 | Common.zip (newi::elsenodes) xxs +> List.map (fun (start_nodei, xs)-> | |
8babbc8f C |
1056 | (* not sure if this is correct... newxi seems to relate to |
1057 | the assigned level number *) | |
1058 | let newerxi = | |
1059 | { newxi with braces = taili_dup:: newxi.braces } in | |
ae4735db | 1060 | let finalthen = |
8babbc8f | 1061 | aux_statement_list (Some start_nodei) (newxi, newerxi) xs in |
485bce71 | 1062 | !g +> add_arc_opt (finalthen, taili); |
ae4735db | 1063 | ) |
485bce71 | 1064 | in |
951c7801 C |
1065 | |
1066 | (* | |
1067 | This is an attempt to let a statement metavariable match this | |
1068 | construct, but it doesn't work because #ifdef is not a statement. | |
1069 | Not sure if this is a good or bad thing, at least if there is no else | |
1070 | because then no statement might be there. | |
1071 | let afteri = !g +> add_node AfterNode newxi'.labels "[after]" in | |
1072 | !g#add_arc ((newi, afteri), Direct); | |
1073 | !g#add_arc ((afteri, taili), Direct); | |
1074 | *) | |
1075 | ||
485bce71 C |
1076 | Some taili |
1077 | ||
1078 | ) starti | |
1079 | ||
1080 | ||
34e49164 C |
1081 | (*****************************************************************************) |
1082 | (* Definition of function *) | |
1083 | (*****************************************************************************) | |
1084 | ||
1085 | let (aux_definition: nodei -> definition -> unit) = fun topi funcdef -> | |
1086 | ||
1087 | let lbl_start = [!counter_for_labels] in | |
1088 | ||
ae4735db C |
1089 | let ({f_name = namefuncs; |
1090 | f_type = functype; | |
1091 | f_storage= sto; | |
485bce71 C |
1092 | f_body= compound; |
1093 | f_attr= attrs; | |
91eba41f | 1094 | f_old_c_style = oldstyle; |
485bce71 | 1095 | }, ii) = funcdef in |
ae4735db C |
1096 | let iifunheader, iicompound = |
1097 | (match ii with | |
1098 | | ioparen::icparen::iobrace::icbrace::iifake::isto -> | |
1099 | ioparen::icparen::iifake::isto, | |
34e49164 | 1100 | [iobrace;icbrace] |
abad11c5 | 1101 | | _ -> raise (Impossible 72) |
34e49164 C |
1102 | ) |
1103 | in | |
1104 | ||
708f4980 | 1105 | let topstatement = Ast_c.mk_st (Ast_c.Compound compound) iicompound in |
34e49164 | 1106 | |
ae4735db C |
1107 | let headi = !g +> add_node |
1108 | (FunHeader ({ | |
b1b2de81 | 1109 | Ast_c.f_name = namefuncs; |
485bce71 C |
1110 | f_type = functype; |
1111 | f_storage = sto; | |
1112 | f_attr = attrs; | |
91eba41f C |
1113 | f_body = [] (* empty body *); |
1114 | f_old_c_style = oldstyle; | |
485bce71 | 1115 | }, iifunheader)) |
b1b2de81 | 1116 | lbl_start ("function " ^ Ast_c.str_of_name namefuncs) in |
34e49164 C |
1117 | let enteri = !g +> add_node Enter lbl_0 "[enter]" in |
1118 | let exiti = !g +> add_node Exit lbl_0 "[exit]" in | |
1119 | let errorexiti = !g +> add_node ErrorExit lbl_0 "[errorexit]" in | |
1120 | ||
1121 | !g#add_arc ((topi, headi), Direct); | |
1122 | !g#add_arc ((headi, enteri), Direct); | |
1123 | ||
1124 | (* ---------------------------------------------------------------- *) | |
1125 | (* todocheck: assert ? such as we have "consommer" tous les labels *) | |
ae4735db C |
1126 | let info = |
1127 | { initial_info with | |
34e49164 C |
1128 | labels = lbl_start; |
1129 | labels_assoc = compute_labels_and_create_them topstatement; | |
1130 | exiti = Some exiti; | |
1131 | errorexiti = Some errorexiti; | |
1132 | compound_caller = FunctionDef; | |
ae4735db | 1133 | } |
34e49164 C |
1134 | in |
1135 | ||
1136 | let lasti = aux_statement (Some enteri, info) topstatement in | |
1137 | !g +> add_arc_opt (lasti, exiti) | |
1138 | ||
1139 | (*****************************************************************************) | |
1140 | (* Entry point *) | |
1141 | (*****************************************************************************) | |
1142 | ||
ae4735db C |
1143 | (* Helpers for SpecialDeclMacro. |
1144 | * | |
34e49164 C |
1145 | * could also force the coccier to define |
1146 | * the toplevel macro statement as in @@ toplevel_declarator MACRO_PARAM;@@ | |
1147 | * and so I would not need this hack and instead I would to a cleaner | |
1148 | * match in cocci_vs_c_3.ml of a A.MacroTop vs B.MacroTop | |
ae4735db | 1149 | * |
708f4980 | 1150 | * todo: update: now I do what I just described, so can remove this code ? |
34e49164 C |
1151 | *) |
1152 | let specialdeclmacro_to_stmt (s, args, ii) = | |
1153 | let (iis, iiopar, iicpar, iiptvirg) = tuple_of_list4 ii in | |
b1b2de81 | 1154 | let ident = Ast_c.RegularName (s, [iis]) in |
708f4980 C |
1155 | let identfinal = Ast_c.mk_e (Ast_c.Ident (ident)) Ast_c.noii in |
1156 | let f = Ast_c.mk_e (Ast_c.FunCall (identfinal, args)) [iiopar;iicpar] in | |
1157 | let stmt = Ast_c.mk_st (Ast_c.ExprStatement (Some f)) [iiptvirg] in | |
34e49164 C |
1158 | stmt, (f, [iiptvirg]) |
1159 | ||
1160 | ||
1161 | ||
1b9ae606 | 1162 | let rec ast_to_control_flow e = |
34e49164 | 1163 | |
ae4735db | 1164 | (* globals (re)initialialisation *) |
34e49164 C |
1165 | g := (new ograph_mutable); |
1166 | counter_for_labels := 1; | |
1167 | counter_for_braces := 0; | |
1168 | counter_for_switch := 0; | |
1169 | ||
1170 | let topi = !g +> add_node TopNode lbl_0 "[top]" in | |
1171 | ||
ae4735db | 1172 | match e with |
1b9ae606 C |
1173 | | Ast_c.Namespace (defs, _) -> |
1174 | (* todo: incorporate the other defs *) | |
1175 | let rec loop defs = | |
1176 | match defs with | |
1177 | | [] -> None | |
1178 | | def :: defs -> | |
1179 | match ast_to_control_flow def with | |
1180 | | None -> loop defs | |
1181 | | x -> x in | |
1182 | loop defs | |
ae4735db | 1183 | | Ast_c.Definition ((defbis,_) as def) -> |
485bce71 C |
1184 | let _funcs = defbis.f_name in |
1185 | let _c = defbis.f_body in | |
34e49164 C |
1186 | (* if !Flag.show_misc then pr2 ("build info function " ^ funcs); *) |
1187 | aux_definition topi def; | |
1188 | Some !g | |
1189 | ||
ae4735db | 1190 | | Ast_c.Declaration _ |
485bce71 | 1191 | | Ast_c.CppTop (Ast_c.Include _) |
34e49164 | 1192 | | Ast_c.MacroTop _ |
ae4735db C |
1193 | -> |
1194 | let (elem, str) = | |
1195 | match e with | |
1196 | | Ast_c.Declaration decl -> | |
34e49164 | 1197 | (Control_flow_c.Decl decl), "decl" |
ae4735db | 1198 | | Ast_c.CppTop (Ast_c.Include inc) -> |
485bce71 | 1199 | (Control_flow_c.Include inc), "#include" |
ae4735db | 1200 | | Ast_c.MacroTop (s, args, ii) -> |
34e49164 C |
1201 | let (st, (e, ii)) = specialdeclmacro_to_stmt (s, args, ii) in |
1202 | (Control_flow_c.ExprStatement (st, (Some e, ii))), "macrotoplevel" | |
1203 | (*(Control_flow_c.MacroTop (s, args,ii), "macrotoplevel") *) | |
abad11c5 | 1204 | | _ -> raise (Impossible 73) |
34e49164 C |
1205 | in |
1206 | let ei = !g +> add_node elem lbl_0 str in | |
1207 | let endi = !g +> add_node EndNode lbl_0 "[end]" in | |
1208 | ||
1209 | !g#add_arc ((topi, ei),Direct); | |
1210 | !g#add_arc ((ei, endi),Direct); | |
1211 | Some !g | |
1212 | ||
ae4735db | 1213 | | Ast_c.CppTop (Ast_c.Define ((id,ii), (defkind, defval))) -> |
3a314143 C |
1214 | let s = |
1215 | match defkind with | |
1216 | Ast_c.Undef -> "#undef " ^ id | |
1217 | | _ -> "#define " ^ id in | |
34e49164 C |
1218 | let headeri = !g+>add_node (DefineHeader ((id, ii), defkind)) lbl_0 s in |
1219 | !g#add_arc ((topi, headeri),Direct); | |
1220 | ||
1221 | (match defval with | |
ae4735db | 1222 | | Ast_c.DefineExpr e -> |
34e49164 C |
1223 | let ei = !g +> add_node (DefineExpr e) lbl_0 "defexpr" in |
1224 | let endi = !g +> add_node EndNode lbl_0 "[end]" in | |
1225 | !g#add_arc ((headeri, ei) ,Direct); | |
1226 | !g#add_arc ((ei, endi) ,Direct); | |
ae4735db C |
1227 | |
1228 | | Ast_c.DefineType ft -> | |
34e49164 C |
1229 | let ei = !g +> add_node (DefineType ft) lbl_0 "deftyp" in |
1230 | let endi = !g +> add_node EndNode lbl_0 "[end]" in | |
1231 | !g#add_arc ((headeri, ei) ,Direct); | |
1232 | !g#add_arc ((ei, endi) ,Direct); | |
1233 | ||
ae4735db | 1234 | | Ast_c.DefineStmt st -> |
34e49164 C |
1235 | (* can have some return; inside the statement *) |
1236 | let exiti = !g +> add_node Exit lbl_0 "[exit]" in | |
1237 | let errorexiti = !g +> add_node ErrorExit lbl_0 "[errorexit]" in | |
1238 | let goto_labels = compute_labels_and_create_them st in | |
1239 | ||
1240 | let info = { initial_info with | |
1241 | labels_assoc = goto_labels; | |
1242 | exiti = Some exiti; | |
1243 | errorexiti = Some errorexiti; | |
ae4735db | 1244 | } |
34e49164 C |
1245 | in |
1246 | ||
1247 | let lasti = aux_statement (Some headeri , info) st in | |
ae4735db | 1248 | lasti +> do_option (fun lasti -> |
34e49164 C |
1249 | (* todo? if don't have a lasti ? no EndNode ? CTL will work ? *) |
1250 | let endi = !g +> add_node EndNode lbl_0 "[end]" in | |
1251 | !g#add_arc ((lasti, endi), Direct) | |
1252 | ) | |
34e49164 | 1253 | |
ae4735db C |
1254 | |
1255 | | Ast_c.DefineDoWhileZero ((st,_e), ii) -> | |
174d1640 C |
1256 | let goto_labels = compute_labels_and_create_them st in |
1257 | let info = { initial_info with | |
1258 | labels_assoc = goto_labels } in | |
1259 | ||
ae4735db | 1260 | let headerdoi = |
34e49164 C |
1261 | !g +> add_node (DefineDoWhileZeroHeader ((),ii)) lbl_0 "do0" in |
1262 | !g#add_arc ((headeri, headerdoi), Direct); | |
34e49164 | 1263 | let lasti = aux_statement (Some headerdoi , info) st in |
ae4735db | 1264 | lasti +> do_option (fun lasti -> |
34e49164 C |
1265 | let endi = !g +> add_node EndNode lbl_0 "[end]" in |
1266 | !g#add_arc ((lasti, endi), Direct) | |
1267 | ) | |
1268 | ||
ae4735db | 1269 | | Ast_c.DefineFunction def -> |
34e49164 C |
1270 | aux_definition headeri def; |
1271 | ||
ae4735db | 1272 | | Ast_c.DefineText (s, s_ii) -> |
91eba41f | 1273 | raise (Error(Define(pinfo_of_ii ii))) |
ae4735db | 1274 | | Ast_c.DefineEmpty -> |
34e49164 C |
1275 | let endi = !g +> add_node EndNode lbl_0 "[end]" in |
1276 | !g#add_arc ((headeri, endi),Direct); | |
ae4735db | 1277 | | Ast_c.DefineInit _ -> |
91eba41f | 1278 | raise (Error(Define(pinfo_of_ii ii))) |
abad11c5 C |
1279 | | Ast_c.DefineMulti sts -> (* christia: todo *) |
1280 | raise (Error(Define(pinfo_of_ii ii))) | |
ae4735db | 1281 | | Ast_c.DefineTodo -> |
91eba41f | 1282 | raise (Error(Define(pinfo_of_ii ii))) |
708f4980 C |
1283 | |
1284 | (* old: | |
ae4735db | 1285 | | Ast_c.DefineText (s, ii) -> |
708f4980 C |
1286 | let endi = !g +> add_node EndNode lbl_0 "[end]" in |
1287 | !g#add_arc ((headeri, endi),Direct); | |
ae4735db | 1288 | | Ast_c.DefineInit _ -> |
708f4980 C |
1289 | let endi = !g +> add_node EndNode lbl_0 "[end]" in |
1290 | !g#add_arc ((headeri, endi),Direct); | |
ae4735db | 1291 | | Ast_c.DefineTodo -> |
708f4980 C |
1292 | let endi = !g +> add_node EndNode lbl_0 "[end]" in |
1293 | !g#add_arc ((headeri, endi),Direct); | |
1294 | *) | |
34e49164 C |
1295 | ); |
1296 | ||
1297 | Some !g | |
ae4735db | 1298 | |
34e49164 C |
1299 | | _ -> None |
1300 | ||
1301 | ||
1302 | (*****************************************************************************) | |
1303 | (* CFG loop annotation *) | |
1304 | (*****************************************************************************) | |
1305 | ||
1306 | let annotate_loop_nodes g = | |
1307 | let firsti = Control_flow_c.first_node g in | |
1308 | ||
1309 | (* just for opti a little *) | |
ae4735db | 1310 | let already = Hashtbl.create 101 in |
34e49164 | 1311 | |
ae4735db | 1312 | g +> Ograph_extended.dfs_iter_with_path firsti (fun xi path -> |
34e49164 C |
1313 | Hashtbl.add already xi true; |
1314 | let succ = g#successors xi in | |
1315 | let succ = succ#tolist in | |
ae4735db | 1316 | succ +> List.iter (fun (yi,_edge) -> |
34e49164 C |
1317 | if Hashtbl.mem already yi && List.mem yi (xi::path) |
1318 | then | |
1319 | let node = g#nodes#find yi in | |
1320 | let ((node2, nodeinfo), nodestr) = node in | |
ae4735db | 1321 | let node' = ((node2, {nodeinfo with is_loop = true}), (nodestr ^ "*")) |
951c7801 | 1322 | in g#replace_node (yi, node'); |
34e49164 C |
1323 | ); |
1324 | ); | |
1325 | ||
1326 | ||
1327 | g | |
1328 | ||
1329 | ||
1330 | (*****************************************************************************) | |
1331 | (* CFG checks *) | |
1332 | (*****************************************************************************) | |
1333 | ||
1334 | (* the second phase, deadcode detection. Old code was raising DeadCode if | |
1335 | * lasti = None, but maybe not. In fact if have 2 return in the then | |
ae4735db C |
1336 | * and else of an if ? |
1337 | * | |
34e49164 C |
1338 | * alt: but can assert that at least there exist |
1339 | * a node to exiti, just check #pred of exiti. | |
ae4735db C |
1340 | * |
1341 | * Why so many deadcode in Linux ? Ptet que le label est utilisé | |
34e49164 | 1342 | * mais dans le corps d'une macro et donc on le voit pas :( |
ae4735db | 1343 | * |
34e49164 | 1344 | *) |
ae4735db | 1345 | let deadcode_detection g = |
34e49164 | 1346 | |
ae4735db | 1347 | g#nodes#iter (fun (k, node) -> |
34e49164 | 1348 | let pred = g#predecessors k in |
ae4735db | 1349 | if pred#null then |
34e49164 | 1350 | (match unwrap node with |
ae4735db | 1351 | (* old: |
34e49164 | 1352 | * | Enter -> () |
ae4735db | 1353 | * | EndStatement _ -> pr2 "deadcode sur fake node, pas grave"; |
34e49164 C |
1354 | *) |
1355 | | TopNode -> () | |
1356 | | FunHeader _ -> () | |
1357 | | ErrorExit -> () | |
1358 | | Exit -> () (* if have 'loop: if(x) return; i++; goto loop' *) | |
1359 | | SeqEnd _ -> () (* todo?: certaines '}' deviennent orphelins *) | |
ae4735db | 1360 | | x -> |
34e49164 | 1361 | (match Control_flow_c.extract_fullstatement node with |
ae4735db | 1362 | | Some st -> |
708f4980 C |
1363 | let ii = Ast_c.get_ii_st_take_care st in |
1364 | raise (Error (DeadCode (Some (pinfo_of_ii ii)))) | |
0708f913 | 1365 | | _ -> pr2 "CFG: orphelin nodes, maybe something weird happened" |
34e49164 C |
1366 | ) |
1367 | ) | |
1368 | ) | |
1369 | ||
1370 | (*------------------------------------------------------------------------*) | |
1371 | (* special_cfg_braces: the check are really specific to the way we | |
1372 | * have build our control_flow, with the { } in the graph so normally | |
1373 | * all those checks here are useless. | |
ae4735db | 1374 | * |
34e49164 C |
1375 | * ver1: to better error reporting, to report earlier the message, pass |
1376 | * the list of '{' (containing morover a brace_identifier) instead of | |
ae4735db | 1377 | * just the depth. |
34e49164 C |
1378 | *) |
1379 | ||
1380 | let (check_control_flow: cflow -> unit) = fun g -> | |
1381 | ||
1382 | let nodes = g#nodes in | |
1383 | let starti = first_node g in | |
1384 | let visited = ref (new oassocb []) in | |
1385 | ||
1386 | let print_trace_error xs = pr2 "PB with flow:"; Common.pr2_gen xs; in | |
1387 | ||
ae4735db | 1388 | let rec dfs (nodei, (* Depth depth,*) startbraces, trace) = |
34e49164 | 1389 | let trace2 = nodei::trace in |
ae4735db C |
1390 | if !visited#haskey nodei |
1391 | then | |
34e49164 C |
1392 | (* if loop back, just check that go back to a state where have same depth |
1393 | number *) | |
1394 | let (*(Depth depth2)*) startbraces2 = !visited#find nodei in | |
1395 | if (*(depth = depth2)*) startbraces <> startbraces2 | |
ae4735db C |
1396 | then |
1397 | begin | |
1398 | pr2 (sprintf "PB with flow: the node %d has not same braces count" | |
1399 | nodei); | |
1400 | print_trace_error trace2 | |
34e49164 | 1401 | end |
ae4735db | 1402 | else |
34e49164 C |
1403 | let children = g#successors nodei in |
1404 | let _ = visited := !visited#add (nodei, (* Depth depth*) startbraces) in | |
1405 | ||
1406 | (* old: good, but detect a missing } too late, only at the end | |
ae4735db | 1407 | let newdepth = |
34e49164 C |
1408 | (match fst (nodes#find nodei) with |
1409 | | StartBrace i -> Depth (depth + 1) | |
1410 | | EndBrace i -> Depth (depth - 1) | |
1411 | | _ -> Depth depth | |
ae4735db | 1412 | ) |
34e49164 C |
1413 | in |
1414 | *) | |
ae4735db | 1415 | let newdepth = |
34e49164 C |
1416 | (match unwrap (nodes#find nodei), startbraces with |
1417 | | SeqStart (_,i,_), xs -> i::xs | |
ae4735db C |
1418 | | SeqEnd (i,_), j::xs -> |
1419 | if i =|= j | |
34e49164 | 1420 | then xs |
ae4735db C |
1421 | else |
1422 | begin | |
1423 | pr2 (sprintf ("PB with flow: not corresponding match between }%d and excpeted }%d at node %d") i j nodei); | |
1424 | print_trace_error trace2; | |
1425 | xs | |
34e49164 | 1426 | end |
ae4735db | 1427 | | SeqEnd (i,_), [] -> |
34e49164 | 1428 | pr2 (sprintf "PB with flow: too much } at }%d " i); |
ae4735db | 1429 | print_trace_error trace2; |
34e49164 C |
1430 | [] |
1431 | | _, xs -> xs | |
ae4735db | 1432 | ) |
34e49164 C |
1433 | in |
1434 | ||
ae4735db | 1435 | |
b1b2de81 | 1436 | if null children#tolist |
ae4735db | 1437 | then |
34e49164 C |
1438 | if (* (depth = 0) *) startbraces <> [] |
1439 | then print_trace_error trace2 | |
ae4735db C |
1440 | else |
1441 | children#tolist +> List.iter (fun (nodei,_) -> | |
34e49164 C |
1442 | dfs (nodei, newdepth, trace2) |
1443 | ) | |
1444 | in | |
1445 | ||
1446 | dfs (starti, (* Depth 0*) [], []) | |
1447 | ||
1448 | (*****************************************************************************) | |
1449 | (* Error report *) | |
1450 | (*****************************************************************************) | |
1451 | ||
ae4735db C |
1452 | let report_error error = |
1453 | let error_from_info info = | |
34e49164 C |
1454 | Common.error_message_short info.file ("", info.charpos) |
1455 | in | |
1456 | match error with | |
ae4735db | 1457 | | DeadCode infoopt -> |
34e49164 C |
1458 | (match infoopt with |
1459 | | None -> pr2 "FLOW: deadcode detected, but cant trace back the place" | |
1460 | | Some info -> pr2 ("FLOW: deadcode detected: " ^ error_from_info info) | |
1461 | ) | |
ae4735db | 1462 | | CaseNoSwitch info -> |
34e49164 | 1463 | pr2 ("FLOW: case without corresponding switch: " ^ error_from_info info) |
ae4735db | 1464 | | OnlyBreakInSwitch info -> |
34e49164 | 1465 | pr2 ("FLOW: only break are allowed in switch: " ^ error_from_info info) |
ae4735db | 1466 | | WeirdSwitch info -> |
708f4980 | 1467 | pr2 ("FLOW: weird switch: " ^ error_from_info info) |
ae4735db | 1468 | | NoEnclosingLoop (info) -> |
34e49164 C |
1469 | pr2 ("FLOW: can't find enclosing loop: " ^ error_from_info info) |
1470 | | GotoCantFindLabel (s, info) -> | |
1471 | pr2 ("FLOW: cant jump to " ^ s ^ ": because we can't find this label") | |
ae4735db | 1472 | | NoExit info -> |
34e49164 | 1473 | pr2 ("FLOW: can't find exit or error exit: " ^ error_from_info info) |
ae4735db | 1474 | | DuplicatedLabel s -> |
708f4980 | 1475 | pr2 ("FLOW: duplicate label " ^ s) |
ae4735db | 1476 | | NestedFunc -> |
34e49164 | 1477 | pr2 ("FLOW: not handling yet nested function") |
ae4735db | 1478 | | ComputedGoto -> |
34e49164 | 1479 | pr2 ("FLOW: not handling computed goto yet") |
91eba41f C |
1480 | | Define info -> |
1481 | pr2 ("Unsupported form of #define: " ^ error_from_info info) |