1 (* *********************************************************************)
3 (* The Compcert verified compiler *)
5 (* Xavier Leroy, INRIA Paris-Rocquencourt *)
7 (* Copyright Institut National de Recherche en Informatique et en *)
8 (* Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the GNU General Public License as published by *)
10 (* the Free Software Foundation, either version 2 of the License, or *)
11 (* (at your option) any later version. This file is also distributed *)
12 (* under the terms of the INRIA Non-Commercial License Agreement. *)
14 (* *********************************************************************)
16 (** Pretty-printer for Csyntax *)
22 let name_unop = function
28 let name_binop = function
46 let name_inttype sz sg =
48 | I8, Signed -> "signed char"
49 | I8, Unsigned -> "unsigned char"
50 | I16, Signed -> "short"
51 | I16, Unsigned -> "unsigned short"
52 | I32, Signed -> "int"
53 | I32, Unsigned -> "unsigned int"
55 let name_floattype sz =
60 (* Collecting the names and fields of structs and unions *)
62 module StructUnionSet = Set.Make(struct
63 type t = string * (ident*ctype) list
64 let compare (n1, _ : t) (n2, _ : t) = compare n1 n2
67 let struct_unions = ref StructUnionSet.empty
69 let register_struct_union id fld =
70 struct_unions := StructUnionSet.add (id, fld) !struct_unions
72 (* Declarator (identifier + type) *)
75 if id = "" then "" else " " ^ id
77 let parenthesize_if_pointer id =
78 if String.length id > 0 && id.[0] = '*' then "(" ^ id ^ ")" else id
80 let rec name_cdecl id ty =
83 "void" ^ name_optid id
85 name_inttype sz sg ^ name_optid id
87 name_floattype sz ^ name_optid id
89 name_cdecl ("*" ^ id) t
92 (sprintf "%s[%ld]" (parenthesize_if_pointer id) (Int32.of_int n))
94 | Tfunction(args, res) ->
95 let b = Buffer.create 20 in
97 then Buffer.add_string b "(*)"
98 else Buffer.add_string b (parenthesize_if_pointer id);
99 Buffer.add_char b '(';
100 begin match args with
102 Buffer.add_string b "void"
104 let rec add_args first = function
107 if not first then Buffer.add_string b ", ";
108 Buffer.add_string b (name_cdecl "" t1);
112 Buffer.add_char b ')';
113 name_cdecl (Buffer.contents b) res
114 | Tstruct(name, fld) ->
116 | Tunion(name, fld) ->
123 let name_type ty = name_cdecl "" ty
127 let parenthesis_level (Expr (e, ty)) =
130 | Econst_float _ -> 0
135 | Ebinop(op, _, _) ->
137 | Oand | Oor | Oxor -> 75
138 | Oeq | One | Olt | Ogt | Ole | Oge -> 70
139 | Oadd | Osub | Oshl | Oshr -> 60
140 | Omul | Odiv | Omod -> 40
143 | Econdition(_, _, _) -> 80
144 | Eandbool(_, _) -> 80
145 | Eorbool(_, _) -> 80
149 | Ecall (_,_,_) -> 20
151 let rec print_expr p (Expr (eb, ty) as e) =
152 let level = parenthesis_level e in
155 fprintf p "%ld" (Int32.of_int n)
161 fprintf p "%s%a" (name_unop op) print_expr_prec (level, e1)
162 | Ederef (Expr (Ebinop(Oadd, e1, e2), _)) ->
163 fprintf p "@[<hov 2>%a@,[%a]@]"
164 print_expr_prec (level, e1)
165 print_expr_prec (level, e2)
166 | Ederef (Expr (Efield(e1, id), _)) ->
167 fprintf p "%a->%s" print_expr_prec (level, e1) id
169 fprintf p "*%a" print_expr_prec (level, e)
171 fprintf p "&%a" print_expr_prec (level, e)
172 | Ebinop(op, e1, e2) ->
173 fprintf p "@[<hov 0>%a@ %s %a@]"
174 print_expr_prec (level, e1)
176 print_expr_prec (level, e2)
178 fprintf p "@[<hov 2>(%s)@,%a@]"
180 print_expr_prec (level, e1)
181 | Econdition(e1, e2, e3) ->
182 fprintf p "@[<hov 0>%a@ ? %a@ : %a@]"
183 print_expr_prec (level, e1)
184 print_expr_prec (level, e2)
185 print_expr_prec (level, e3)
186 | Eandbool(e1, e2) ->
187 fprintf p "@[<hov 0>%a@ && %a@]"
188 print_expr_prec (level, e1)
189 print_expr_prec (level, e2)
191 fprintf p "@[<hov 0>%a@ || %a@]"
192 print_expr_prec (level, e1)
193 print_expr_prec (level, e2)
195 fprintf p "sizeof(%s)" (name_type ty)
197 fprintf p "%a.%s" print_expr_prec (level, e1) id
199 fprintf p "(/* %s */ %a)" lbl print_expr e1
200 | Ecall (f, arg, e) ->
201 fprintf p "(%s(%a), %a)" f print_expr arg print_expr e
203 and print_expr_prec p (context_prec, e) =
204 let this_prec = parenthesis_level e in
205 if this_prec >= context_prec
206 then fprintf p "(%a)" print_expr e
209 let rec print_expr_list p (first, el) =
213 if not first then fprintf p ",@ ";
215 print_expr_list p (false, et)
217 let rec print_stmt p s =
220 fprintf p "/*skip*/;"
222 fprintf p "@[<hv 2>%a =@ %a;@]" print_expr e1 print_expr e2
223 | Scall(None, e1, el) ->
224 fprintf p "@[<hv 2>%a@,(@[<hov 0>%a@]);@]"
226 print_expr_list (true, el)
227 | Scall(Some lhs, e1, el) ->
228 fprintf p "@[<hv 2>%a =@ %a@,(@[<hov 0>%a@]);@]"
231 print_expr_list (true, el)
232 | Ssequence(s1, s2) ->
233 fprintf p "%a@ %a" print_stmt s1 print_stmt s2
234 | Sifthenelse(e, s1, Sskip) ->
235 fprintf p "@[<v 2>if (%a) {@ %a@;<0 -2>}@]"
238 | Sifthenelse(e, s1, s2) ->
239 fprintf p "@[<v 2>if (%a) {@ %a@;<0 -2>} else {@ %a@;<0 -2>}@]"
244 fprintf p "@[<v 2>while (%a) {@ %a@;<0 -2>}@]"
248 fprintf p "@[<v 2>do {@ %a@;<0 -2>} while(%a);@]"
251 | Sfor(s_init, e, s_iter, s_body) ->
252 fprintf p "@[<v 2>for (@[<hv 0>%a;@ %a;@ %a) {@]@ %a@;<0 -2>}@]"
253 print_stmt_for s_init
255 print_stmt_for s_iter
260 fprintf p "continue;"
261 | Sswitch(e, cases) ->
262 fprintf p "@[<v 2>switch (%a) {@ %a@;<0 -2>}@]"
267 | Sreturn (Some e) ->
268 fprintf p "return %a;" print_expr e
270 fprintf p "%s:@ %a" lbl print_stmt s1
272 fprintf p "goto %s;" lbl
274 fprintf p "%s:@ %a" lbl print_stmt s1
276 and print_cases p cases =
281 fprintf p "@[<v 2>default:@ %a@]" print_stmt s
282 | LScase(lbl, Sskip, rem) ->
283 fprintf p "case %ld:@ %a"
286 | LScase(lbl, s, rem) ->
287 fprintf p "@[<v 2>case %ld:@ %a@]@ %a"
292 and print_stmt_for p s =
295 fprintf p "/*nothing*/"
297 fprintf p "%a = %a" print_expr e1 print_expr e2
298 | Ssequence(s1, s2) ->
299 fprintf p "%a, %a" print_stmt_for s1 print_stmt_for s2
300 | Scall(None, e1, el) ->
301 fprintf p "@[<hv 2>%a@,(@[<hov 0>%a@])@]"
303 print_expr_list (true, el)
304 | Scall(Some lhs, e1, el) ->
305 fprintf p "@[<hv 2>%a =@ %a@,(@[<hov 0>%a@])@]"
308 print_expr_list (true, el)
310 fprintf p "({ %a })" print_stmt s
312 let name_function_parameters fun_name params =
313 let b = Buffer.create 20 in
314 Buffer.add_string b fun_name;
315 Buffer.add_char b '(';
316 begin match params with
318 Buffer.add_string b "void"
320 let rec add_params first = function
323 if not first then Buffer.add_string b ", ";
324 Buffer.add_string b (name_cdecl id ty);
325 add_params false rem in
326 add_params true params
328 Buffer.add_char b ')';
331 let print_function p id f =
333 (name_cdecl (name_function_parameters id f.fn_params)
335 fprintf p "@[<v 2>{@ ";
338 fprintf p "%s;@ " (name_cdecl id ty))
340 print_stmt p f.fn_body;
341 fprintf p "@;<0 -2>}@]@ @ "
343 let print_fundef p (id, fd) =
345 | External(_, args, res) ->
346 fprintf p "extern %s;@ @ "
347 (name_cdecl id (Tfunction(args, res)))
349 print_function p id f
351 let string_of_init id =
352 let b = Buffer.create (List.length id) in
353 let add_init = function
355 if n >= 32 && n <= 126 && n <> Char.code '\"' && n <> Char.code '\\'
356 then Buffer.add_char b (Char.chr n)
357 else Buffer.add_string b (Printf.sprintf "\\%03o" n)
360 in List.iter add_init id; Buffer.contents b
362 let chop_last_nul id =
363 match List.rev id with
364 | Init_int8 0 :: tl -> List.rev tl
367 let print_init p = function
368 | Init_int8 n -> fprintf p "%ld,@ " (Int32.of_int n)
369 | Init_int16 n -> fprintf p "%ld,@ " (Int32.of_int n)
370 | Init_int32 n -> fprintf p "%ld,@ " (Int32.of_int n)
371 | Init_float32 n -> fprintf p "%F,@ " n
372 | Init_float64 n -> fprintf p "%F,@ " n
373 | Init_space n -> fprintf p "/* skip %ld, */@ " (Int32.of_int n)
374 | Init_addrof(symb, ofs) ->
375 let ofs = Int32.of_int ofs in
377 then fprintf p "&%s,@ " symb
378 else fprintf p "(void *)((char *)&%s + %ld),@ " symb ofs
380 let print_init1 p = function
381 | Init_int8 n -> fprintf p "%ld" (Int32.of_int n)
382 | Init_int16 n -> fprintf p "%ld" (Int32.of_int n)
383 | Init_int32 n -> fprintf p "%ld" (Int32.of_int n)
384 | Init_float32 n -> fprintf p "%F" n
385 | Init_float64 n -> fprintf p "%F" n
386 | Init_space n -> fprintf p "/* skip %ld */" (Int32.of_int n)
387 | Init_addrof(symb, ofs) ->
388 let ofs = Int32.of_int ofs in
390 then fprintf p "&%s" symb
391 else fprintf p "(void *)((char *)&%s + %ld)" symb ofs
393 let match_string_literal s pos =
394 let s_len = String.length s - 1 in
395 let prefix = "__stringlit_" in
396 let len_prefix = String.length prefix in
398 && String.sub s 0 len_prefix = prefix &&
399 match Misc.LexingExt.lex_num s len_prefix with
401 | Some (pos, pos', v) -> pos' = String.length s - 1
403 let print_globvar p (((id, init), ty)) =
406 fprintf p "extern %s;@ @ "
412 fprintf p "@[<hov 2>%s = %a;@]@ @ "
413 (name_cdecl id ty) print_init1 init
415 fprintf p "@[<hov 2>%s = "
417 if match_string_literal id 0
418 && List.for_all (function Init_int8 _ -> true | _ -> false) init
420 fprintf p "\"%s\"" (string_of_init (chop_last_nul init))
423 List.iter (print_init p) init;
428 (* Collect struct and union types *)
430 let rec collect_type = function
434 | Tpointer t -> collect_type t
435 | Tarray(t, n) -> collect_type t
436 | Tfunction(args, res) -> collect_type_list args; collect_type res
437 | Tstruct(id, fld) -> register_struct_union id fld; collect_fields fld
438 | Tunion(id, fld) -> register_struct_union id fld; collect_fields fld
441 and collect_type_list = function
443 | hd::tl -> collect_type hd; collect_type_list tl
445 and collect_fields = function
447 | (id, hd)::tl -> collect_type hd; collect_fields tl
449 let rec collect_expr (Expr(ed, ty)) =
452 | Econst_float f -> ()
454 | Eunop(op, e1) -> collect_expr e1
455 | Ederef e -> collect_expr e
456 | Eaddrof e -> collect_expr e
457 | Ebinop(op, e1, e2) -> collect_expr e1; collect_expr e2
458 | Ecast(ty, e1) -> collect_type ty; collect_expr e1
459 | Econdition(e1, e2, e3) -> collect_expr e1; collect_expr e2; collect_expr e3
460 | Eandbool(e1, e2) -> collect_expr e1; collect_expr e2
461 | Eorbool(e1, e2) -> collect_expr e1; collect_expr e2
462 | Esizeof ty -> collect_type ty
463 | Efield(e1, id) -> collect_expr e1
464 | Ecost(_, e) -> collect_expr e
465 | Ecall(_, arg, e) -> collect_expr arg; collect_expr e
467 let rec collect_expr_list = function
469 | hd :: tl -> collect_expr hd; collect_expr_list tl
471 let rec collect_stmt = function
473 | Sassign(e1, e2) -> collect_expr e1; collect_expr e2
474 | Scall(None, e1, el) -> collect_expr e1; collect_expr_list el
475 | Scall(Some lhs, e1, el) -> collect_expr lhs; collect_expr e1; collect_expr_list el
476 | Ssequence(s1, s2) -> collect_stmt s1; collect_stmt s2
477 | Sifthenelse(e, s1, s2) -> collect_expr e; collect_stmt s1; collect_stmt s2
478 | Swhile(e, s) -> collect_expr e; collect_stmt s
479 | Sdowhile(e, s) -> collect_stmt s; collect_expr e
480 | Sfor(s_init, e, s_iter, s_body) ->
481 collect_stmt s_init; collect_expr e;
482 collect_stmt s_iter; collect_stmt s_body
485 | Sswitch(e, cases) -> collect_expr e; collect_cases cases
487 | Sreturn (Some e) -> collect_expr e
488 | Slabel(lbl, s) -> collect_stmt s
490 | Scost (_,s1) -> collect_stmt s1
492 and collect_cases = function
493 | LSdefault s -> collect_stmt s
494 | LScase(lbl, s, rem) -> collect_stmt s; collect_cases rem
496 let collect_function f =
497 collect_type f.fn_return;
498 List.iter (fun ((id, ty)) -> collect_type ty) f.fn_params;
499 List.iter (fun ((id, ty)) -> collect_type ty) f.fn_vars;
500 collect_stmt f.fn_body
502 let collect_fundef ((id, fd)) =
504 | External(_, args, res) -> collect_type_list args; collect_type res
505 | Internal f -> collect_function f
507 let collect_globvar (((id, init), ty)) =
510 let collect_program p =
511 List.iter collect_globvar p.prog_vars;
512 List.iter collect_fundef p.prog_funct
514 let declare_struct_or_union p (name, fld) =
515 fprintf p "%s;@ @ " name
517 let print_struct_or_union p (name, fld) =
518 fprintf p "@[<v 2>%s {" name;
519 let rec print_fields = function
522 fprintf p "@ %s;" (name_cdecl id ty);
525 fprintf p "@;<0 -2>};@]@ "
527 let print_program_2 p prog =
528 struct_unions := StructUnionSet.empty;
529 collect_program prog;
531 StructUnionSet.iter (declare_struct_or_union p) !struct_unions;
532 StructUnionSet.iter (print_struct_or_union p) !struct_unions;
533 List.iter (print_globvar p) prog.prog_vars;
534 List.iter (print_fundef p) prog.prog_funct;
537 let print_program prog =
538 print_program_2 str_formatter prog;
539 flush_str_formatter ()
541 let string_of_ctype = name_type
543 let print_expression e =
544 print_expr str_formatter e;
545 flush_str_formatter ()
547 let print_statement s =
548 print_stmt str_formatter s;
549 flush_str_formatter ()
551 let print_ctype_prot = name_type
553 let print_ctype_def = function
554 | Tstruct (name, fld) | Tunion (name, fld) ->
555 let f_fld s (id, t) = s ^ " " ^ (print_ctype_prot t) ^ " " ^ id ^ ";\n" in
556 let s_fld = List.fold_left f_fld "" in
557 name ^ " {\n" ^ (s_fld fld) ^ "};\n"
558 | _ -> "" (* no definition associated to the other types *)
560 let string_of_unop = name_unop
562 let string_of_binop = name_binop