2024-11-21 18:30:19 +01:00
|
|
|
module type PrintableType = sig
|
|
|
|
|
type t
|
|
|
|
|
val pp : out_channel -> t -> unit
|
2025-01-27 16:28:23 +01:00
|
|
|
val pp_list : out_channel -> t list -> unit
|
2024-11-21 18:30:19 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let globalIdNode = ref 0;
|
|
|
|
|
|
|
|
|
|
module Node = struct
|
|
|
|
|
type t = {
|
2024-12-12 16:37:36 +01:00
|
|
|
id: int;
|
2024-11-21 18:30:19 +01:00
|
|
|
}
|
|
|
|
|
let compare a b = compare a.id b.id
|
|
|
|
|
|
|
|
|
|
let create () =
|
|
|
|
|
globalIdNode := !globalIdNode + 1;
|
2024-12-12 16:37:36 +01:00
|
|
|
{id = !globalIdNode;}
|
2024-11-21 18:30:19 +01:00
|
|
|
end
|
|
|
|
|
|
2024-12-02 00:45:24 +01:00
|
|
|
module NodeMap = struct
|
|
|
|
|
include Map.Make(Node)
|
|
|
|
|
|
2025-01-11 20:32:11 +01:00
|
|
|
(* adds the input to the tail of the list for the associated node *)
|
2024-12-02 00:45:24 +01:00
|
|
|
let add_to_list_last x data m =
|
|
|
|
|
let add = function None -> Some [data]
|
|
|
|
|
| Some l -> Some (l @ [data]) in
|
|
|
|
|
update x add m
|
|
|
|
|
end
|
|
|
|
|
|
2024-11-21 18:30:19 +01:00
|
|
|
module NodeSet = Set.Make(Node)
|
|
|
|
|
|
2024-12-12 16:37:36 +01:00
|
|
|
type 'a cfginternal = {
|
|
|
|
|
empty: bool;
|
|
|
|
|
nodes: NodeSet.t;
|
|
|
|
|
edges: (Node.t * (Node.t option)) NodeMap.t;
|
2025-01-27 16:28:23 +01:00
|
|
|
reverse_edges: (Node.t list) NodeMap.t;
|
|
|
|
|
input_val: int option;
|
|
|
|
|
input_output_var: (string * string) option;
|
2024-12-12 16:37:36 +01:00
|
|
|
initial: Node.t option;
|
|
|
|
|
terminal: Node.t option;
|
|
|
|
|
content: 'a list NodeMap.t;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-21 18:30:19 +01:00
|
|
|
module type C = sig
|
|
|
|
|
type elt
|
2024-12-12 16:37:36 +01:00
|
|
|
type t = elt cfginternal
|
2024-11-21 18:30:19 +01:00
|
|
|
|
2024-11-27 20:18:30 +01:00
|
|
|
val empty : t
|
2024-11-21 18:30:19 +01:00
|
|
|
val merge : t -> t -> Node.t -> Node.t -> t
|
|
|
|
|
val concat : t -> t -> t
|
2025-01-27 16:28:23 +01:00
|
|
|
val add_to_last_node : elt -> t -> t
|
2024-11-21 18:30:19 +01:00
|
|
|
|
|
|
|
|
val pp : out_channel -> t -> unit
|
|
|
|
|
end
|
|
|
|
|
|
2024-12-12 16:37:36 +01:00
|
|
|
module Make (M: PrintableType) = struct
|
2024-11-21 18:30:19 +01:00
|
|
|
type elt = M.t
|
2024-12-12 16:37:36 +01:00
|
|
|
type t = elt cfginternal
|
2024-11-21 18:30:19 +01:00
|
|
|
|
2024-11-27 20:18:30 +01:00
|
|
|
let empty : t =
|
2024-11-21 18:30:19 +01:00
|
|
|
{ empty = true;
|
|
|
|
|
nodes = NodeSet.empty;
|
|
|
|
|
edges = NodeMap.empty;
|
2025-01-27 16:28:23 +01:00
|
|
|
reverse_edges = NodeMap.empty;
|
|
|
|
|
input_val = None;
|
|
|
|
|
input_output_var = None;
|
2024-11-21 18:30:19 +01:00
|
|
|
initial = None;
|
|
|
|
|
terminal = None;
|
|
|
|
|
content = NodeMap.empty }
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let merge (cfg1: t) (cfg2: t) (entry_node: Node.t) (exit_node: Node.t) : t =
|
2024-11-21 18:30:19 +01:00
|
|
|
match (cfg1.empty, cfg2.empty) with
|
|
|
|
|
true, _ -> cfg2
|
|
|
|
|
| _, true -> cfg1
|
|
|
|
|
| false, false ->
|
2025-01-27 16:28:23 +01:00
|
|
|
let cfg1_initial = Option.get cfg1.initial in
|
|
|
|
|
let cfg2_initial = Option.get cfg2.initial in
|
|
|
|
|
let cfg1_terminal = Option.get cfg1.terminal in
|
|
|
|
|
let cfg2_terminal = Option.get cfg2.terminal in
|
2024-11-21 18:30:19 +01:00
|
|
|
{ empty = false;
|
|
|
|
|
nodes = NodeSet.union cfg1.nodes cfg2.nodes |>
|
2025-01-27 16:28:23 +01:00
|
|
|
NodeSet.add entry_node |>
|
|
|
|
|
NodeSet.add exit_node;
|
2025-01-11 20:32:11 +01:00
|
|
|
edges = NodeMap.union
|
|
|
|
|
(fun _ -> failwith "Failed merging edges of cfg.")
|
2024-11-21 18:30:19 +01:00
|
|
|
cfg1.edges cfg2.edges |>
|
2025-01-27 16:28:23 +01:00
|
|
|
NodeMap.add entry_node (cfg1_initial, Some cfg2_initial) |>
|
|
|
|
|
NodeMap.add cfg1_terminal (exit_node, None) |>
|
|
|
|
|
NodeMap.add cfg2_terminal (exit_node, None);
|
|
|
|
|
reverse_edges = NodeMap.union
|
2025-01-11 20:32:11 +01:00
|
|
|
(fun _ -> failwith "Failed merging edges of cfg.")
|
2025-01-27 16:28:23 +01:00
|
|
|
cfg1.reverse_edges cfg2.reverse_edges |>
|
|
|
|
|
NodeMap.add_to_list cfg1_initial entry_node |>
|
|
|
|
|
NodeMap.add_to_list cfg2_initial entry_node |>
|
|
|
|
|
NodeMap.add_to_list exit_node cfg1_terminal |>
|
|
|
|
|
NodeMap.add_to_list exit_node cfg2_terminal;
|
|
|
|
|
input_val = cfg1.input_val;
|
|
|
|
|
input_output_var = cfg1.input_output_var;
|
|
|
|
|
initial = Some entry_node;
|
|
|
|
|
terminal = Some exit_node;
|
2025-01-11 20:32:11 +01:00
|
|
|
content = NodeMap.union
|
|
|
|
|
(fun _ -> failwith "Failed merging code of cfg.")
|
2024-11-21 18:30:19 +01:00
|
|
|
cfg1.content cfg2.content
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let concat (cfg1: t) (cfg2: t) : t =
|
|
|
|
|
match (cfg1.empty, cfg2.empty) with
|
|
|
|
|
true, _ -> cfg2
|
|
|
|
|
| _, true -> cfg1
|
|
|
|
|
| false, false ->
|
2025-01-27 16:28:23 +01:00
|
|
|
let cfg1_initial = Option.get cfg1.initial in
|
|
|
|
|
let cfg2_initial = Option.get cfg2.initial in
|
|
|
|
|
let cfg1_terminal = Option.get cfg1.terminal in
|
|
|
|
|
let cfg2_terminal = Option.get cfg2.terminal in
|
2024-11-21 18:30:19 +01:00
|
|
|
{ empty = false;
|
|
|
|
|
nodes = NodeSet.union cfg1.nodes cfg2.nodes;
|
2025-01-11 20:32:11 +01:00
|
|
|
edges = NodeMap.union
|
|
|
|
|
(fun _ -> failwith "Failed merging edges of cfg.")
|
|
|
|
|
cfg1.edges cfg2.edges |>
|
2025-01-27 16:28:23 +01:00
|
|
|
NodeMap.add cfg1_terminal (cfg2_initial, None);
|
|
|
|
|
reverse_edges = NodeMap.union
|
2025-01-11 20:32:11 +01:00
|
|
|
(fun _ -> failwith "Failed merging edges of cfg.")
|
2025-01-27 16:28:23 +01:00
|
|
|
cfg1.reverse_edges cfg2.reverse_edges |>
|
|
|
|
|
NodeMap.add_to_list cfg2_initial cfg1_terminal;
|
|
|
|
|
input_val = cfg1.input_val;
|
|
|
|
|
input_output_var = cfg1.input_output_var;
|
|
|
|
|
initial = Some cfg1_initial;
|
|
|
|
|
terminal = Some cfg2_terminal;
|
2025-01-11 20:32:11 +01:00
|
|
|
content = NodeMap.union
|
|
|
|
|
(fun _ -> failwith "Failed merging code of cfg.")
|
2024-11-21 18:30:19 +01:00
|
|
|
cfg1.content cfg2.content
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-27 16:28:23 +01:00
|
|
|
let add_to_last_node (new_content: elt) (cfg: t) : t =
|
2025-01-26 23:03:20 +01:00
|
|
|
if cfg.empty then
|
2025-01-27 16:28:23 +01:00
|
|
|
let new_node = Node.create () in
|
2024-11-21 18:30:19 +01:00
|
|
|
{ empty = false;
|
2025-01-27 16:28:23 +01:00
|
|
|
nodes = NodeSet.singleton new_node;
|
2024-11-21 18:30:19 +01:00
|
|
|
edges = NodeMap.empty;
|
2025-01-27 16:28:23 +01:00
|
|
|
reverse_edges = NodeMap.empty;
|
|
|
|
|
input_val = None;
|
|
|
|
|
input_output_var = None;
|
|
|
|
|
initial = Some new_node;
|
|
|
|
|
terminal = Some new_node;
|
|
|
|
|
content = NodeMap.singleton new_node [new_content]
|
2024-11-21 18:30:19 +01:00
|
|
|
}
|
2025-01-26 23:03:20 +01:00
|
|
|
else
|
2025-01-27 16:28:23 +01:00
|
|
|
let prevcfg_terminal = Option.get cfg.terminal in
|
2024-11-21 18:30:19 +01:00
|
|
|
{ cfg with
|
2024-12-02 00:45:24 +01:00
|
|
|
content = (NodeMap.add_to_list_last
|
2025-01-27 16:28:23 +01:00
|
|
|
prevcfg_terminal
|
|
|
|
|
new_content
|
2024-11-21 18:30:19 +01:00
|
|
|
cfg.content) }
|
|
|
|
|
|
|
|
|
|
let pp (ppf) (c: t) : unit =
|
|
|
|
|
Printf.fprintf ppf "Nodes' ids: ";
|
2025-01-11 20:32:11 +01:00
|
|
|
List.iter
|
|
|
|
|
(fun (x : Node.t) -> Printf.fprintf ppf "%d " x.id)
|
|
|
|
|
(NodeSet.to_list c.nodes);
|
2024-11-21 18:30:19 +01:00
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Nodes' edges:\n";
|
2025-01-11 20:32:11 +01:00
|
|
|
List.iter
|
|
|
|
|
(fun ((n, (a, b)) : (Node.t * (Node.t * Node.t option))) : unit ->
|
|
|
|
|
match b with
|
|
|
|
|
None -> Printf.fprintf ppf "\t%d -> %d\n" n.id a.id
|
|
|
|
|
| Some b -> Printf.fprintf ppf "\t%d -> %d, %d\n" n.id a.id b.id )
|
|
|
|
|
(NodeMap.to_list c.edges);
|
2024-11-21 18:30:19 +01:00
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Nodes' back edges:\n";
|
|
|
|
|
List.iter (fun ((n, xs) : (Node.t * (Node.t list))) : unit ->
|
|
|
|
|
Printf.fprintf ppf "\t%d -> " n.id;
|
|
|
|
|
List.iter (fun (x: Node.t) -> Printf.fprintf ppf "%d, " x.id) xs;
|
|
|
|
|
Printf.fprintf ppf "\n"
|
2025-01-27 16:28:23 +01:00
|
|
|
) (NodeMap.to_list c.reverse_edges);
|
2024-11-21 18:30:19 +01:00
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Input Value: ";
|
2025-01-27 16:28:23 +01:00
|
|
|
(match c.input_val with
|
2024-11-27 20:18:30 +01:00
|
|
|
Some i -> Printf.fprintf ppf "%d" i;
|
2024-11-21 18:30:19 +01:00
|
|
|
| None -> Printf.fprintf ppf "None";);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
2024-11-27 20:18:30 +01:00
|
|
|
Printf.fprintf ppf "Input and Output Vars: ";
|
2025-01-27 16:28:23 +01:00
|
|
|
(match c.input_output_var with
|
2024-11-27 20:18:30 +01:00
|
|
|
Some (i, o) -> Printf.fprintf ppf "(in: %s, out: %s)" i o;
|
2024-11-21 18:30:19 +01:00
|
|
|
| None -> Printf.fprintf ppf "None";);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Initial node's id: ";
|
|
|
|
|
(match c.initial with
|
|
|
|
|
Some i -> Printf.fprintf ppf "%d" (i.id);
|
|
|
|
|
| None -> Printf.fprintf ppf "None";);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Terminal node's id: ";
|
|
|
|
|
(match c.terminal with
|
|
|
|
|
Some i -> Printf.fprintf ppf "%d" (i.id);
|
|
|
|
|
| None -> Printf.fprintf ppf "None";);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
|
|
|
|
|
Printf.fprintf ppf "Code:\n";
|
|
|
|
|
List.iter (fun ((n, stms) : Node.t * elt list) : unit ->
|
2025-01-27 16:28:23 +01:00
|
|
|
Printf.fprintf ppf "\tid %d --> %a\n%!" n.id M.pp_list stms
|
2024-11-21 18:30:19 +01:00
|
|
|
) (NodeMap.to_list c.content);
|
|
|
|
|
Printf.fprintf ppf "\n";
|
|
|
|
|
end
|
|
|
|
|
;;
|