open Lexing
open Cmdline
open Ast
open Num_domain
open Nonrelational
open Apron_domain
open Abs_domain
open Enum_domain_edd
open Abs_interp_dynpart
module Interpret = Interpret.I
module ItvND = Apron_domain.ND_Box (* Nonrelational.ND(Intervals_domain.VD) *)
module PolyND = Apron_domain.ND_Poly
module OctND = Apron_domain.ND_Oct
module ItvOND = NumDomainOnly(ItvND)
module PolyOND = NumDomainOnly(PolyND)
module OctOND = NumDomainOnly(OctND)
module ItvEND = NumEnumDomain(Enum_domain.MultiValuation)(ItvND)
module PolyEND = NumEnumDomain(Enum_domain.MultiValuation)(PolyND)
module ItvENDEdd = NumEnumDomain(Enum_domain_edd.EDD)(ItvND)
module PolyENDEdd = NumEnumDomain(Enum_domain_edd.EDD)(PolyND)
module AI_Itv = Abs_interp.I(Enum_domain.MultiValuation)(ItvND)
module AI_Poly = Abs_interp.I(Enum_domain.MultiValuation)(PolyND)
module AI_Oct = Abs_interp.I(Enum_domain.MultiValuation)(OctND)
module AI_Itv_EDD = Abs_interp_edd.I(ItvOND)
module AI_Poly_EDD = Abs_interp_edd.I(PolyOND)
module AI_Oct_EDD = Abs_interp_edd.I(OctOND)
module AI_S_Itv_DP = Abs_interp_dynpart.I(ItvEND)
module AI_S_Rel_DP = Abs_interp_dynpart.I(PolyEND)
module AI_EDD_Itv_DP = Abs_interp_dynpart.I(ItvENDEdd)
module AI_EDD_Rel_DP = Abs_interp_dynpart.I(PolyENDEdd)
(* command line options *)
let times = ref false
let dump = ref false
let dumprn = ref false
let test = ref false
let vtest = ref false
let ai_itv = ref false
let ai_poly = ref false
let ai_oct = ref false
let ai_itv_edd = ref false
let ai_poly_edd = ref false
let ai_oct_edd = ref false
let ai_s_itv_dp = ref false
let ai_s_rel_dp = ref false
let ai_edd_itv_dp = ref false
let ai_edd_rel_dp = ref false
let ai_root = ref "test"
let ai_widen_delay = ref 5
let ai_no_time_scopes = ref "all"
let ai_init_scopes = ref "all"
let ai_disj_v = ref "all"
let ai_max_dp_depth = ref 10
let ai_max_dp_width = ref 100
let ai_vci = ref false
let ai_vvci = ref false
let ifile = ref ""
let usage = "usage: analyzer [options] file.scade"
let options = [
"--exec-times", Arg.Set times,
"Show time spent in each function of the analyzer, for some functions";
"--dump", Arg.Set dump, "Dump program source.";
"--dump-rn", Arg.Set dumprn, "Dump program source, after renaming.";
"--vtest", Arg.Set vtest, "Verbose testing (direct interpret).";
"--test", Arg.Set test, "Simple testing (direct interpret).";
"--ai-itv", Arg.Set ai_itv, "Do abstract analysis using intervals.";
"--ai-poly", Arg.Set ai_poly, "Do abstract analysis using Apron polyhedra domain.";
"--ai-oct", Arg.Set ai_oct, "Do abstract analysis using Apron octagon domain.";
"--ai-itv-edd", Arg.Set ai_itv_edd,
"Do abstract analysis using intervals and EDD disjunction domain.";
"--ai-poly-edd", Arg.Set ai_poly_edd,
"Do abstract analysis using Apron polyhedra domain and EDD disjunction domain.";
"--ai-oct-edd", Arg.Set ai_oct_edd,
"Do abstract analysis using Apron octagon domain and EDD disjunction domain.";
"--ai-s-itv-dp", Arg.Set ai_s_itv_dp,
"Do abstract analysis using dynamic partitionning method, "^
"with intervals and valuation domain for enums.";
"--ai-s-rel-dp", Arg.Set ai_s_rel_dp,
"Do abstract analysis using dynamic partitionning method, "^
"with Apron and valuation domain for enums.";
"--ai-edd-itv-dp", Arg.Set ai_edd_itv_dp,
"Do abstract analysis using dynamic partitionning method, "^
"with intervals and EDD domain for enums.";
"--ai-edd-rel-dp", Arg.Set ai_edd_rel_dp,
"Do abstract analysis using dynamic partitionning method, "^
"with Apron and EDD domain for enums.";
"--ai-vci", Arg.Set ai_vci,
"Verbose chaotic iterations (show state at each iteration)";
"--ai-vvci", Arg.Set ai_vvci,
"Very verbose chaotic iterations (show everything all the time)";
"--ai-wd", Arg.Set_int ai_widen_delay,
"Widening delay in abstract analysis of loops (default: 3).";
"--ai-max-dp-depth", Arg.Set_int ai_max_dp_depth,
"Maximum depth in the dynamic partitionning tree.";
"--ai-max-dp-width", Arg.Set_int ai_max_dp_width,
"Maximum number of dynamically partitionned locations.";
"--root", Arg.Set_string ai_root,
"Root node for abstract analysis (default: test).";
"--no-time", Arg.Set_string ai_no_time_scopes,
"Scopes for which not to introduce a 'time' variable in analysis.";
"--disj", Arg.Set_string ai_disj_v,
"Variables for which to introduce a disjunction.";
"--init", Arg.Set_string ai_init_scopes,
"Scopes for which to introduce a 'init' variable in analysis.";
]
let parse_file (filename : string) : prog =
let f = open_in filename in
let lex = from_channel f in
try
lex.lex_curr_p <- { lex.lex_curr_p with pos_fname = filename; };
Parser.file Lexer.token lex
with
| Parser.Error ->
Util.error (Printf.sprintf "Parse error (invalid syntax) near %s"
(Util.string_of_position lex.lex_start_p))
| Failure "lexing: empty token" ->
Util.error (Printf.sprintf "Parse error (invalid token) near %s"
(Util.string_of_position lex.lex_start_p))
let do_test_interpret prog verbose =
let f0 _ = false in
let s0 = Interpret.init_state (Typing.root_prog prog "test" f0 f0) in
if verbose then begin
Format.printf "Init state:@.";
Interpret.print_state Format.std_formatter s0;
end;
let rec it i st =
let next_st, out =
Interpret.step st
["i", Interpret.int_value i]
in
if verbose then begin
Format.printf "@.> Step %d:@." i;
Interpret.print_state Format.std_formatter st;
Format.printf "Outputs:@.";
List.iter
(fun (k, v) -> Format.printf "%s = %s@."
k (Interpret.str_repr_of_val v))
out;
end else begin
Format.printf "%d. %s %s %s@." i
(Interpret.str_repr_of_val (List.assoc "a" out))
(Interpret.str_repr_of_val (List.assoc "b" out))
(Interpret.str_repr_of_val (List.assoc "c" out));
end;
if not (Interpret.as_bool (List.assoc "exit" out)) then
it (i+1) next_st
in
it 0 s0
let () =
(* AI_Itv_EDD.test (); *)
Arg.parse options (fun f -> ifile := f) usage;
if !ifile = "" then begin
Format.eprintf "No input file...@.";
exit 1
end;
try
let prog = parse_file !ifile in
if !dump then Ast_printer.print_prog Format.std_formatter prog;
let prog = Rename.rename_prog prog in
if !dumprn then Ast_printer.print_prog Format.std_formatter prog;
if !ai_itv || !ai_poly || !ai_oct
|| !ai_itv_edd || !ai_poly_edd || !ai_oct_edd
|| !ai_s_itv_dp || !ai_s_rel_dp
|| !ai_edd_itv_dp || !ai_edd_rel_dp then
begin
let comma_split = Str.split (Str.regexp ",") in
let match_s s pat =
let n, m = String.length s, String.length pat in
let memo = Array.make_matrix (n+1) (m+1) None in
let rec aux i j =
match memo.(i).(j) with
| Some x -> x
| None ->
let x =
if i = n && j = m
then true
else if j = m && i < n
then false
else if i = n && j < m
then pat.[j] = '*' && aux i (j+1)
else
if pat.[j] = '*'
then aux (i+1) j || aux i (j+1)
else s.[i] = pat.[j] && aux (i+1) (j+1)
in memo.(i).(j) <- Some x; x
in aux 0 0
in
let select_f x =
if x = "all" then
(fun _ -> true)
else if x = "last" then
(fun i -> i.[0] = 'L')
else if String.length x > 5 && String.sub x 0 5 = "last+" then
let psl = comma_split
(String.sub x 5 (String.length x - 5)) in
(fun i -> i.[0] = 'L' || List.exists (match_s i) psl)
else
(fun i -> List.mem i (comma_split x))
in
let rp = Typing.root_prog prog !ai_root
(select_f !ai_no_time_scopes)
(select_f !ai_init_scopes) in
let disj = select_f !ai_disj_v in
let opt = {
widen_delay = !ai_widen_delay;
disjunct = disj;
verbose_ci = !ai_vci;
vverbose_ci = !ai_vvci;
max_dp_width = !ai_max_dp_width;
max_dp_depth = !ai_max_dp_depth;
} in
if !ai_itv then AI_Itv.do_prog opt rp;
if !ai_poly then AI_Poly.do_prog opt rp;
if !ai_oct then AI_Oct.do_prog opt rp;
if !ai_itv_edd then AI_Itv_EDD.do_prog opt rp;
if !ai_poly_edd then AI_Poly_EDD.do_prog opt rp;
if !ai_oct_edd then AI_Oct_EDD.do_prog opt rp;
if !ai_s_itv_dp then AI_S_Itv_DP.do_prog opt rp;
if !ai_s_rel_dp then AI_S_Rel_DP.do_prog opt rp;
if !ai_edd_itv_dp then AI_EDD_Itv_DP.do_prog opt rp;
if !ai_edd_rel_dp then AI_EDD_Rel_DP.do_prog opt rp;
end;
if !vtest then do_test_interpret prog true
else if !test then do_test_interpret prog false;
if !times then Util.show_times();
with
| Util.NoLocError e -> Format.eprintf "Error: %s@." e
| Util.LocError(l, e) ->
Format.eprintf "Error: %s@." e;
List.iter
(fun loc -> Format.eprintf "At: %s@." (Util.string_of_extent loc))
l