let pp_metrics ppf cabs_visitor =
  (* Compute the metrics from the informations gathered by the visitor. *)
  let operator_tbl = cabs_visitor#get_operator_tbl () in
  let operand_tbl = cabs_visitor#get_operand_tbl () in
  let distinct_operators, total_operators = compute_operators operator_tbl
  and distinct_operands, total_operands = compute_operands operand_tbl in
  let program_length = total_operands +. total_operators in
  let vocabulary_size = distinct_operands +. distinct_operators in
  let log2 x = (Pervasives.log x) /. (Pervasives.log 2.0) in
  let program_volume = program_length *. (log2 vocabulary_size) in
  let difficulty_level =
    (distinct_operators /. 2.) *. (total_operands /. distinct_operands) in
  let program_level = 1. /. difficulty_level in
  let effort_to_implement = program_volume *. difficulty_level in
  let time_to_implement = effort_to_implement /. 18. in
  let bugs_delivered = (effort_to_implement ** (2./.3.)) /. 3000. in
  let minutes = (int_of_float time_to_implement) / 60 in
  let hours, minutes = minutes / 60, minutes mod 60 in

  let dummy_cst cst =
    { expr_loc = (Lexing.dummy_pos, Lexing.dummy_pos);
      expr_node = CONSTANT cst;
    }
  and simple_pp_htbl ppf htbl =
    Hashtbl.iter (fun k v -> Format.fprintf ppf "%s: %d@ " k v) htbl in
  (* Halstead metrics' bugs delivered statistics is said to be underapproximated
     for C. Hence the "lower bound" commentary on the output next to "bugs
     delivered".
  *)

  Format.fprintf ppf
    "@[<v 0>Halstead metrics@ ----------------@ Distinct operators: %d@ Total operators: %d@ Distinct operands: %d@ Total operands: %d@ Program length: %d@ Vocabulary size: %d@ Program volume: %.2f@ Difficulty level: %.2f@ Program level: %.2f@ Effort to implement: %.2f@ Time to implement (s): %.2f  (%dh %dmin)@ Bugs delivered (lower bound): %.2f@ @ Global statistics (Halstead)@ ----------------------------@ @[<v 2>** Operators@ %a%a%a%a@]@ @[<v 2>** Operands @ %a%a@]@ @]"
    (int_of_float distinct_operators)
    (int_of_float total_operators)
    (int_of_float distinct_operands)
    (int_of_float total_operands)
    (int_of_float program_length)
    (int_of_float vocabulary_size)
    program_volume difficulty_level
    program_level effort_to_implement time_to_implement
    hours minutes
    bugs_delivered
    (* Operators table *)
    simple_pp_htbl operator_tbl.reserved_tbl
    simple_pp_htbl operator_tbl.otherop_tbl
    simple_pp_htbl operator_tbl.knownop_tbl
    (fun ppf htbl ->
      Hashtbl.iter
        (fun k v ->
          Format.fprintf ppf "%a: %d@ " Cprint.print_type_spec k v) htbl)
    operator_tbl.tspec_tbl
    simple_pp_htbl operand_tbl.var_tbl
    (fun ppf htbl ->
      Hashtbl.iter
        (fun k v ->
          Format.fprintf ppf "%a: %d@ " Cprint.print_expression (dummy_cst k) v)
        htbl)
    operand_tbl.cst_tbl;