From 7fcc03cc7282fba480a3cfc998e85f62182da4ad Mon Sep 17 00:00:00 2001 From: Valentin Perrelle <valentin.perrelle@cea.fr> Date: Fri, 31 Jul 2020 19:59:49 +0200 Subject: [PATCH] [Aorai] move metavariable assignements from conditions to transitions - Use the same field "actions" for parsed and typed transitions - Rename confusing types in Promelaast - Reorganized Promelaoutput to mirror the naming convention --- src/plugins/aorai/aorai_dataflow.ml | 6 +- src/plugins/aorai/aorai_graph.ml | 4 +- src/plugins/aorai/aorai_graph.mli | 3 +- src/plugins/aorai/aorai_metavariables.ml | 14 +- src/plugins/aorai/aorai_register.ml | 4 +- src/plugins/aorai/aorai_utils.ml | 45 +- src/plugins/aorai/aorai_utils.mli | 4 +- src/plugins/aorai/aorai_visitors.ml | 4 +- src/plugins/aorai/data_for_aorai.ml | 238 +++++----- src/plugins/aorai/data_for_aorai.mli | 13 +- src/plugins/aorai/logic_simplification.ml | 15 +- src/plugins/aorai/logic_simplification.mli | 4 +- src/plugins/aorai/promelaast.mli | 44 +- src/plugins/aorai/promelaoutput.ml | 414 +++++++++--------- src/plugins/aorai/promelaoutput.mli | 56 +-- src/plugins/aorai/promelaparser.mly | 8 +- src/plugins/aorai/promelaparser_withexps.mly | 8 +- .../aorai/tests/ya/metavariables-right.ya | 4 +- .../aorai/tests/ya/metavariables-wrong.ya | 2 +- src/plugins/aorai/tests/ya/stack.ya | 8 +- src/plugins/aorai/yaparser.mly | 31 +- 21 files changed, 473 insertions(+), 456 deletions(-) diff --git a/src/plugins/aorai/aorai_dataflow.ml b/src/plugins/aorai/aorai_dataflow.ml index f6315b5ce50..0662bf5764d 100644 --- a/src/plugins/aorai/aorai_dataflow.ml +++ b/src/plugins/aorai/aorai_dataflow.ml @@ -276,8 +276,7 @@ let make_start_transition ?(is_main=false) kf init_states = let my_trans = Path_analysis.get_transitions_of_state state auto in let treat_one_trans acc trans = if is_crossable trans kf then begin - let (_,action) = trans.cross in - let bindings = actions_to_range action in + let bindings = actions_to_range trans.actions in let fst_set = Data_for_aorai.Aorai_state.Set.singleton trans.stop in @@ -309,8 +308,7 @@ let make_return_transition kf state = let last = Data_for_aorai.Aorai_state.Set.singleton state in let treat_one_trans acc trans = if Aorai_utils.isCrossable trans kf Promelaast.Return then begin - let (_,action) = trans.cross in - let my_bindings = actions_to_range action in + let my_bindings = actions_to_range trans.actions in let new_bindings = compose_actions bindings (last, last, my_bindings) in add_or_merge trans.stop new_bindings acc end else acc diff --git a/src/plugins/aorai/aorai_graph.ml b/src/plugins/aorai/aorai_graph.ml index a72aca27e95..77f78d8950a 100644 --- a/src/plugins/aorai/aorai_graph.ml +++ b/src/plugins/aorai/aorai_graph.ml @@ -26,7 +26,7 @@ open Promelaast type state = Promelaast.state -type transition = (typed_condition * action) trans +type transition = Promelaast.typed_trans module Vertex = struct @@ -46,7 +46,7 @@ struct let compare x y = Pervasives.compare x.numt y.numt let default = { numt = -1; start = Vertex.default; stop = Vertex.default; - cross = TTrue,[] + cross = TTrue; actions = [] } end diff --git a/src/plugins/aorai/aorai_graph.mli b/src/plugins/aorai/aorai_graph.mli index 4823c41789d..8735c3cc1e7 100644 --- a/src/plugins/aorai/aorai_graph.mli +++ b/src/plugins/aorai/aorai_graph.mli @@ -24,8 +24,7 @@ (**************************************************************************) type state = Promelaast.state -type transition = - (Promelaast.typed_condition * Promelaast.action) Promelaast.trans +type transition = Promelaast.typed_trans type edge = state * transition * state include Graph.Sig.I diff --git a/src/plugins/aorai/aorai_metavariables.ml b/src/plugins/aorai/aorai_metavariables.ml index 9ce8aac82a0..6c77e04c43a 100644 --- a/src/plugins/aorai/aorai_metavariables.ml +++ b/src/plugins/aorai/aorai_metavariables.ml @@ -90,10 +90,9 @@ struct Format.pp_print_string fmt st.Promelaast.name let pretty_trans fmt tr = - let cond,act = tr.cross in - Promelaoutput.print_condition fmt cond; - if act <> [] then - Format.fprintf fmt "{@[%a@]}" Promelaoutput.print_action act + Promelaoutput.Typed.print_condition fmt tr.cross; + if tr.actions <> [] then + Format.fprintf fmt "{@[%a@]}" Promelaoutput.Typed.print_actionl tr.actions let pretty_set fmt set = let l = Set.elements set in @@ -115,18 +114,17 @@ struct let analyze ((src,tr,dst) as edge) = function | Bottom -> Bottom | InitializedSet initialized -> - let cond,act = tr.cross in (* Check that the condition uses only initialized variables *) - let used = used_metavariables cond in + let used = used_metavariables tr.cross in let diff = Set.diff used initialized in if not (Set.is_empty diff) then alarm edge diff; (* Add variables initialized by the condition *) - let add_initialized set = function + let add set = function | Copy_value ((TVar({lv_origin = Some vi}),_),_) -> Set.add vi set | _ -> set in - let initialized' = List.fold_left add_initialized initialized act in + let initialized' = List.fold_left add initialized tr.actions in Aorai_option.debug ~dkey "%a {%a} -> %a {%a}" pretty_state src pretty_set initialized pretty_state dst pretty_set initialized'; diff --git a/src/plugins/aorai/aorai_register.ml b/src/plugins/aorai/aorai_register.ml index 1ad1b145e78..14c35b7f0e6 100644 --- a/src/plugins/aorai/aorai_register.ml +++ b/src/plugins/aorai/aorai_register.ml @@ -48,7 +48,7 @@ let convert_ltl_exprs t = POr(c1,c2) -> POr (convert_cond c1, convert_cond c2) | PAnd(c1,c2) -> PAnd(convert_cond c1, convert_cond c2) | PNot c -> PNot (convert_cond c) - | PCall _ | PReturn _ | PTrue | PFalse | PAssign _ -> cond + | PCall _ | PReturn _ | PTrue | PFalse -> cond | PRel(Neq,PVar x,PCst _) -> (try let (rel,t1,t2) = Hashtbl.find ltl_to_promela x in PRel(rel,t1,t2) @@ -259,7 +259,7 @@ let output () = (* Dot file *) if (Aorai_option.Dot.get()) then begin - Promelaoutput.output_dot_automata (Data_for_aorai.getAutomata ()) + Promelaoutput.Typed.output_dot_automata (Data_for_aorai.getAutomata ()) (!dot_file:>string); printverb "Generating dot file : done\n" end; diff --git a/src/plugins/aorai/aorai_utils.ml b/src/plugins/aorai/aorai_utils.ml index 5daa862d825..c192b4c348e 100644 --- a/src/plugins/aorai/aorai_utils.ml +++ b/src/plugins/aorai/aorai_utils.ml @@ -66,8 +66,7 @@ let isCrossable tr func st = | TFalse -> False | TRel _ -> Undefined in - let cond,_ = tr.cross in - let res = isCross cond <> False in + let res = isCross tr.cross <> False in Aorai_option.debug ~level:2 "Function %a %s-state, \ transition %s -> %s is%s possible" Kernel_function.pretty func (if st=Call then "pre" else "post") @@ -307,8 +306,7 @@ let isCrossableAtInit tr func = | TRel(rel,t1,t2) -> eval_rel_at_init rel t1 t2 in - let (cond,_) = tr.cross in - match isCross cond with + match isCross tr.cross with | Bool3.True | Bool3.Undefined -> true | Bool3.False -> false @@ -557,7 +555,7 @@ let mk_behavior_call generated_kf kf bhv = (* Translate the cross condition of an automaton edge to an expression. Used in mk_stmt. This might generate calls to auxiliary functions, to take into account a guard that uses a function behavior. *) -let crosscond_to_exp generated_kf curr_f curr_status loc (cond,_) res = +let crosscond_to_exp generated_kf curr_f curr_status loc cond res = let check_current_event f status = Kernel_function.equal curr_f f && curr_status = status in @@ -1059,10 +1057,10 @@ let mk_deterministic_lemma () = let subst = Cil_datatype.Logic_var.Hashtbl.create 5 in let subst_res = Kernel_function.Hashtbl.create 5 in let guard1 = - pred_of_condition subst subst_res label (fst trans1.cross) + pred_of_condition subst subst_res label trans1.cross in let guard2 = - pred_of_condition subst subst_res label (fst trans2.cross) + pred_of_condition subst subst_res label trans2.cross in let pred = Logic_const.pnot (Logic_const.pand (guard1, guard2)) in let quants = @@ -1288,7 +1286,7 @@ let action_assigns trans = add_if_needed caux (Logic_const.tvar aux) empty | _ -> empty in - let _,res = List.fold_left treat_one_action empty_pebble (snd trans.cross) in + let _,res = List.fold_left treat_one_action empty_pebble trans.actions in Writes res let get_reachable_trans state st auto current_state = @@ -1354,7 +1352,7 @@ let force_transition loc f st current_state = *) let add_one_trans (has_crossable_trans, crossable_non_reject) trans = let has_crossable_trans = - Logic_simplification.tor has_crossable_trans (fst trans.cross) + Logic_simplification.tor has_crossable_trans trans.cross in let crossable_non_reject = crossable_non_reject || @@ -1428,7 +1426,7 @@ let partition_action trans = *) in let treat_one_trans acc tr = - List.fold_left (treat_one_action tr.start) acc (snd tr.cross) + List.fold_left (treat_one_action tr.start) acc tr.actions in List.fold_left treat_one_trans Cil_datatype.Term_lval.Map.empty trans @@ -1530,7 +1528,8 @@ let add_behavior_pebble_actions ~loc f st behaviors state trans = let set = Data_for_aorai.pebble_set_at set Logic_const.here_label in let treat_action guard res action = match action with - | Copy_value _ | Counter_incr _ | Counter_init _ -> res + | Copy_value _ | Counter_incr _ | Counter_init _ -> + res | Pebble_init (_,_,v) -> let a = Cil_const.make_logic_var_quant aux.lv_name aux.lv_type in let guard = rename_pred aux a guard in @@ -1558,9 +1557,9 @@ let add_behavior_pebble_actions ~loc f st behaviors state trans = :: res in let treat_one_trans acc tr = - let guard = crosscond_to_pred (fst tr.cross) f st in + let guard = crosscond_to_pred tr.cross f st in let guard = Logic_const.pold guard in - List.fold_left (treat_action guard) acc (snd tr.cross) + List.fold_left (treat_action guard) acc tr.actions in let res = List.fold_left treat_one_trans [] trans in let res = Logic_const.term (Tunion res) set.term_type in @@ -1639,8 +1638,7 @@ let mk_unchanged_aux_vars trans = | Pebble_init _ | Pebble_move _ -> acc in let add_one_trans acc tr = - let (_,actions) = tr.cross in - List.fold_left add_one_action acc actions + List.fold_left add_one_action acc tr.actions in let my_aux_vars = List.fold_left add_one_trans my_aux_vars trans in let treat_lval lv acc = @@ -1672,15 +1670,14 @@ let mk_behavior ~loc auto kf e status state = List.fold_left (fun (in_guard, out_guard, all_assigns, action_bhvs) trans -> Aorai_option.debug "examining transition %d" trans.numt; - let (cond,actions) = trans.cross in Aorai_option.debug "transition %d is active" trans.numt; - let guard = crosscond_to_pred cond kf e in + let guard = crosscond_to_pred trans.cross kf e in let my_in_guard,my_out_guard = match state.multi_state with | None -> guard, Logic_const.pnot ~loc guard | Some (_,aux) -> let set = - find_pebble_origin Logic_const.here_label actions + find_pebble_origin Logic_const.here_label trans.actions in pebble_guard ~loc set aux guard, pebble_guard_neg ~loc set aux guard @@ -1689,7 +1686,7 @@ let mk_behavior ~loc auto kf e status state = Logic_const.pand ~loc (out_guard, my_out_guard) in let in_guard, all_assigns, action_bhvs = - match actions with + match trans.actions with | [] -> (Logic_const.por ~loc (in_guard,my_in_guard), all_assigns, @@ -1721,7 +1718,7 @@ let mk_behavior ~loc auto kf e status state = | Some (_,aux) -> let set = find_pebble_origin - Logic_const.pre_label actions + Logic_const.pre_label trans.actions in acc @ List.map @@ -1732,7 +1729,7 @@ let mk_behavior ~loc auto kf e status state = posts in let post_cond = - List.fold_left treat_one_action [post_cond] actions + List.fold_left treat_one_action [post_cond] trans.actions in let assigns = action_assigns trans in let all_assigns = concat_assigns assigns all_assigns in @@ -1879,7 +1876,7 @@ let auto_func_behaviors loc f st state = global_behavior :: (List.rev behaviors) -let act_convert loc (_,act) res = +let act_convert loc act res = let treat_one_act = function | Counter_init t_lval -> @@ -1929,7 +1926,7 @@ let mk_stmt generated_kf loc (states, tr) f fst status ((st,_) as state) res = Cil_datatype.Varinfo.Set.union tr_funcs new_funcs, Cil.mkBinOp loc LAnd (is_state_exp trans.start loc) exp ::exp_from_trans, - act_convert loc trans.cross res :: stmt_from_action)) + act_convert loc trans.actions res :: stmt_from_action)) useful_trans ([],[],Cil_datatype.Varinfo.Set.empty, [], []) in @@ -2079,7 +2076,7 @@ let auto_func_block generated_kf loc f st status res = let get_preds_wrt_params_reachable_states state f status = let auto = Data_for_aorai.getGraph () in - let treat_one_trans acc tr = Logic_simplification.tor acc (fst tr.cross) in + let treat_one_trans acc tr = Logic_simplification.tor acc tr.cross in let find_trans state prev tr = Path_analysis.get_edges prev state auto @ tr in diff --git a/src/plugins/aorai/aorai_utils.mli b/src/plugins/aorai/aorai_utils.mli index 47d4bb47275..0bc659364f4 100644 --- a/src/plugins/aorai/aorai_utils.mli +++ b/src/plugins/aorai/aorai_utils.mli @@ -32,12 +32,12 @@ open Promelaast *) val isCrossable: - (typed_condition * action) trans -> kernel_function -> funcStatus -> bool + typed_trans -> kernel_function -> funcStatus -> bool (** Given a transition and the main entry point it returns if the cross condition can be satisfied at the beginning of the program. *) val isCrossableAtInit: - (typed_condition * action) trans -> kernel_function -> bool + typed_trans -> kernel_function -> bool (** This function rewrites a cross condition into an ACSL expression. Moreover, by giving current operation name and its status (call or diff --git a/src/plugins/aorai/aorai_visitors.ml b/src/plugins/aorai/aorai_visitors.ml index ad68e06ec7a..486c67733ed 100644 --- a/src/plugins/aorai/aorai_visitors.ml +++ b/src/plugins/aorai/aorai_visitors.ml @@ -382,7 +382,7 @@ let possible_start kf (start,int) = let trans = Path_analysis.get_edges start int auto in let treat_one_trans cond tr = Logic_const.por - (cond, Aorai_utils.crosscond_to_pred (fst tr.cross) kf Promelaast.Call) + (cond, Aorai_utils.crosscond_to_pred tr.cross kf Promelaast.Call) in let cond = List.fold_left treat_one_trans Logic_const.pfalse trans in Logic_const.pand (Aorai_utils.is_state_pred start, cond) @@ -409,7 +409,7 @@ let neg_trans kf trans = List.fold_left (fun cond tr -> Logic_simplification.tand - cond (Logic_simplification.tnot (fst tr.cross))) + cond (Logic_simplification.tnot tr.cross)) cond trans) TTrue same_start in diff --git a/src/plugins/aorai/data_for_aorai.ml b/src/plugins/aorai/data_for_aorai.ml index 56f2d69b042..54f5d8c0e25 100644 --- a/src/plugins/aorai/data_for_aorai.ml +++ b/src/plugins/aorai/data_for_aorai.ml @@ -57,19 +57,18 @@ module Aorai_typed_trans = Datatype.Make_with_collections( struct let name = "Aorai_typed_trans" - type t = - (Promelaast.typed_condition * Promelaast.action) Promelaast.trans + type t = Promelaast.typed_trans let structural_descr = Structural_descr.t_abstract let reprs = [ { numt = -1; start = List.hd (Aorai_state.reprs); stop = List.hd (Aorai_state.reprs); - cross = (TTrue,[]); } ] + cross = TTrue; actions=[]; } ] let equal x y = Datatype.Int.equal x.numt y.numt let hash x = x.numt let rehash = Datatype.identity let compare x y = Datatype.Int.compare x.numt y.numt let copy = Datatype.identity let internal_pretty_code = Datatype.undefined - let pretty = Promelaoutput.print_transition + let pretty = Promelaoutput.Typed.print_transition let varname _ = assert false let mem_project = Datatype.never_any_project end) @@ -354,8 +353,8 @@ let new_state name = let new_intermediate_state () = new_state "aorai_intermediate_state" -let new_trans start stop cond = - { start = start; stop = stop; cross = cond; numt = TransIndex.next () } +let new_trans start stop cross actions = + { start; stop; cross; actions; numt = TransIndex.next () } let check_states s = let {states;trans} = getAutomata() in @@ -410,25 +409,23 @@ let is_single elt = the entire automaton is processed by adding direct transitions from the starting state to the children of the end state. *) -type eps_trans = - Normal of typed_condition * action - | Epsilon of typed_condition * action - -let print_epsilon_trans fmt = function - | Normal (c,a) -> - Format.fprintf fmt "%a%a" - Promelaoutput.print_condition c - Promelaoutput.print_action a - | Epsilon (c,a) -> - Format.fprintf fmt "epsilon-trans:@\n%a%a" - Promelaoutput.print_condition c - Promelaoutput.print_action a +type 'a eps = Normal of 'a | Epsilon of 'a + +let print_eps f fmt = function + | Normal x -> f fmt x + | Epsilon x -> Format.fprintf fmt "epsilon-trans:@\n%a" f x + +let print_eps_trans fmt tr = + Format.fprintf fmt "%s -> %s:@[%a%a@]" + tr.start.name tr.stop.name + (print_eps Promelaoutput.Typed.print_condition) tr.cross + Promelaoutput.Typed.print_actionl tr.actions type current_event = | ECall of kernel_function * Cil_types.logic_var Cil_datatype.Varinfo.Hashtbl.t - * eps_trans Promelaast.trans + * (typed_condition eps,typed_action) Promelaast.trans | EReturn of kernel_function | ECOR of kernel_function | ENone (* None found yet *) @@ -553,11 +550,11 @@ let memo_aux_variable tr counter used_prms vi = let my_lvar = Cil.cvar_to_lvar my_var in Cil_datatype.Varinfo.Hashtbl.add used_prms vi my_lvar; (match tr.cross with - | Normal (cond,action) -> + | Normal _ -> let st = Extlib.opt_map (fun _ -> tr.stop) counter in let loc = get_bindings st my_lvar in let copy = Copy_value (loc,Logic_const.tvar (Cil.cvar_to_lvar vi)) in - tr.cross <- Normal(cond,copy::action) + tr.actions <- copy :: tr.actions | Epsilon _ -> Aorai_option.fatal "Epsilon transition used as Call event" ); @@ -896,36 +893,27 @@ let type_cond needs_pebble metaenv env tr cond = let current = if needs_pebble then Some tr.stop else None in let rec aux pos env = function - | PAssign (s, e) -> - if not pos then - Aorai_option.abort - "Metavariable assignment cannot be done under a negation"; - let vi = find_metavar s metaenv in - let env, e, c = type_expr metaenv env ~tr ?current e in - let assign = Copy_value ((TVar (Cil.cvar_to_lvar vi), TNoOffset), e) in - (* TODO: check type assignability *) - env, c, [assign] | PRel(rel,e1,e2) -> let env, e1, c1 = type_expr metaenv env ~tr ?current e1 in let env, e2, c2 = type_expr metaenv env ~tr ?current e2 in let call_cond = if pos then tand c1 c2 else tor (tnot c1) (tnot c2) in let rel = TRel(Logic_typing.type_rel rel,e1,e2) in let cond = if pos then tand call_cond rel else tor call_cond rel in - env, cond, [] - | PTrue -> env, TTrue, [] - | PFalse -> env, TFalse, [] + env, cond + | PTrue -> env, TTrue + | PFalse -> env, TFalse | POr(c1,c2) -> - let env1, c1, a1 = aux pos env c1 in - let env2, c2, a2 = aux pos env c2 in + let env1, c1 = aux pos env c1 in + let env2, c2 = aux pos env c2 in let env, c = merge_current_event env1 env2 c1 c2 in - env, c, a1 @ a2 + env, c | PAnd(c1,c2) -> - let env, c1, a1 = aux pos env c1 in - let env, c2, a2 = aux pos env c2 in - env, TAnd (c1,c2), a1 @ a2 + let env, c1 = aux pos env c1 in + let env, c2 = aux pos env c2 in + env, TAnd (c1,c2) | PNot c -> - let env, c, a = aux (not pos) env c in - env, TNot c, a + let env, c = aux (not pos) env c in + env, TNot c | PCall (s,b) -> let kf = try Globals.Functions.find_by_name s @@ -946,9 +934,9 @@ let type_cond needs_pebble metaenv env tr cond = (ECall (kf, Cil_datatype.Varinfo.Hashtbl.create 3, tr)) env (TCall (kf,b)) in - env, c, [] + env, c else - env, TCall (kf,b), [] + env, TCall (kf,b) | PReturn s -> let kf = try @@ -957,9 +945,9 @@ let type_cond needs_pebble metaenv env tr cond = in if pos then let env,c = add_current_event (EReturn kf) env (TReturn kf) in - env, c, [] + env, c else - env, TReturn kf, [] + env, TReturn kf in aux true (ENone::env) cond @@ -1029,7 +1017,7 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s | _ -> new_intermediate_state () in Aorai_option.debug "Examining single elt:@\n%s -> %s:@[%a@]" - curr_start.name my_end.name Promelaoutput.print_seq_elt elt; + curr_start.name my_end.name Promelaoutput.Parsed.print_seq_elt elt; let guard_exit_loop env current counter = if is_opt then TTrue else @@ -1070,9 +1058,9 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s [] -> my_end | _ -> new_intermediate_state () in - let trans_start = new_trans curr_start seq_start (Normal (TTrue,[])) + let trans_start = new_trans curr_start seq_start (Normal TTrue) [] in - let inner_env, cond, act = + let inner_env, cond = type_cond needs_pebble metaenv env trans_start cond in let (env,states, seq_transitions, seq_end) = @@ -1089,8 +1077,8 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s let states = add_if_needed states curr_start in let transitions = trans_start :: seq_transitions in (match trans_start.cross with - | Normal (conds,action) -> - trans_start.cross <- Normal (tand cond conds,action @ act) + | Normal conds -> + trans_start.cross <- Normal (tand cond conds) | Epsilon _ -> Aorai_option.fatal "Transition guard translated as epsilon transition"); @@ -1121,7 +1109,7 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s let auto = (inner_states,inner_trans) in if at_most_one then begin (* Just adds an epsilon transition from start to end *) - let opt = new_trans curr_start oth_start (Epsilon (TTrue,[])) in + let opt = new_trans curr_start oth_start (Epsilon TTrue) [] in env, states, opt::trans, curr_start, curr_end end else if has_loop then begin @@ -1159,19 +1147,12 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s List.fold_left (fun acc tr -> let init_action = Counter_init (make_counter tr.stop) in - let init_cross = - match tr.cross with - | Normal (cond, actions) -> - Normal(cond, init_action :: actions) - | Epsilon(cond, actions) -> - Epsilon(cond, init_action :: actions) - in - Aorai_option.debug "New init trans %s -> %s: %a" - st.name tr.stop.name - print_epsilon_trans init_cross; + let init_actions = init_action :: tr.actions in let init_trans = - new_trans st tr.stop init_cross + new_trans st tr.stop tr.cross init_actions in + Aorai_option.debug "New init trans %a" + print_eps_trans init_trans; if at_most_one then init_trans :: acc else begin let st = @@ -1183,24 +1164,22 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s (make_counter_term curr_start) else TTrue in - let loop_action = - if needs_counter then begin + let loop_actions = + if needs_counter then let counter = make_counter curr_start in - [ Counter_incr counter ] - end else [] + Counter_incr counter :: tr.actions + else tr.actions in let loop_cross = match tr.cross with - | Normal(cond, actions) -> - Normal(tand loop_cond cond, loop_action @ actions) - | Epsilon(cond, actions) -> - Epsilon(tand loop_cond cond, loop_action @ actions) + | Normal cond -> Normal (tand loop_cond cond) + | Epsilon cond -> Epsilon (tand loop_cond cond) in - Aorai_option.debug "New loop trans %s -> %s: %a" - inner_end.name tr.stop.name - print_epsilon_trans loop_cross; let loop_trans = - new_trans inner_end tr.stop loop_cross in + new_trans inner_end tr.stop loop_cross loop_actions + in + Aorai_option.debug "New loop trans %a" + print_eps_trans loop_trans; init_trans :: loop_trans :: acc end) oth_trans trans @@ -1220,7 +1199,7 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s in TRel (Cil_types.Req, t, Logic_const.tinteger ~loc 0) in - let no_seq = new_trans st oth_start (Epsilon (zero_cond,[])) in + let no_seq = new_trans st oth_start (Epsilon zero_cond) [] in no_seq :: loop_trans end else loop_trans in @@ -1236,11 +1215,10 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s guard_exit_loop env st (make_counter_term curr_end) else TTrue in - let min_cond = Epsilon (min_cond,[]) in - Aorai_option.debug "New exit trans %s -> %s: %a" - inner_end.name oth_start.name - print_epsilon_trans min_cond; - let exit_trans = new_trans inner_end oth_start min_cond in + let min_cond = Epsilon min_cond in + let exit_trans = new_trans inner_end oth_start min_cond [] in + Aorai_option.debug "New exit trans %a" + print_eps_trans exit_trans; let trans = exit_trans :: trans @ oth_trans in states, trans end else begin @@ -1256,7 +1234,7 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s List.fold_left (fun acc tr -> match tr.cross with - | Normal (cond,_) | Epsilon (cond,_) -> + | Normal cond | Epsilon cond -> let cond = change_bound_var tr.stop st cond in tor acc cond) TFalse trans @@ -1268,7 +1246,7 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s | _ -> let reject = get_reject_state () in let states = add_if_needed states reject in - let trans = new_trans st reject (Normal(cond,[])) :: trans + let trans = new_trans st reject (Normal cond) [] :: trans in states, trans @ oth_trans ) end @@ -1284,6 +1262,13 @@ let rec type_seq default_state tr metaenv env needs_pebble curr_start curr_end s end else env, states, trans, curr_start, curr_end +let type_action metaenv env = function +| Metavar_assign (s, e) -> + let vi = find_metavar s metaenv in + let _, e, _ = type_expr metaenv env e in + (* TODO: check type assignability *) + Copy_value ((TVar (Cil.cvar_to_lvar vi), TNoOffset), e) + let single_path (states,transitions as auto) tr = Aorai_option.Deterministic.get () || (let init = Path_analysis.get_init_states auto in @@ -1311,15 +1296,26 @@ let type_trans auto metaenv env tr = in Aorai_option.debug "Analyzing transition %s -> %s: %a (needs pebble: %B)" - tr.start.name tr.stop.name Promelaoutput.print_parsed tr.cross needs_pebble; + tr.start.name tr.stop.name + Promelaoutput.Parsed.print_guard + tr.cross needs_pebble; match tr.cross with | Seq seq -> let default_state = find_otherwise_trans auto tr.start in let has_default_state = Extlib.has_some default_state in - let _,states, transitions,_,_ = + let env,states, transitions,_,_ = type_seq has_default_state tr metaenv env needs_pebble tr.start tr.stop seq in - let (states, transitions) = + (* Insert metavariable assignments for transitions to tr.stop *) + let meta_actions = List.map (type_action metaenv env) tr.actions in + let add_meta_actions t = + if Aorai_state.equal t.stop tr.stop then + { t with actions = t.actions @ meta_actions } + else + t + in + let transitions = List.map add_meta_actions transitions in + let transitions = if List.exists (fun st -> st.multi_state <> None) states then begin (* We have introduced some multi-state somewhere, we have to introduce pebbles and propagate them from state to state. *) @@ -1334,26 +1330,25 @@ let type_trans auto metaenv env tr = (fun trans -> match trans.cross with | Epsilon _ -> trans - | Normal(cond,actions) -> + | Normal _ -> let (dest,d_aux) = memo_multi_state tr.stop in let actions = if tr.start.nums <> start.nums then begin let src,s_aux = memo_multi_state tr.start in - Pebble_move(dest,d_aux,src,s_aux) :: actions + Pebble_move(dest,d_aux,src,s_aux) :: trans.actions end else begin let v = Cil.cvar_to_lvar count in let incr = Counter_incr (TVar v, TNoOffset) in let init = Pebble_init (dest, d_aux, v) in - init::incr::actions + init::incr::trans.actions end in - { trans with - cross = Normal(cond, actions) }) + { trans with actions }) transitions in - states, transitions + transitions end else - states, transitions + transitions in (* For each intermediate state, add a transition to either the default state or a rejection state (in which we will @@ -1368,8 +1363,8 @@ let type_trans auto metaenv env tr = in Aorai_option.debug "Resulting transitions:@\n%a" (Pretty_utils.pp_list ~sep:"@\n" - (fun fmt tr -> Format.fprintf fmt "%s -> %s:@[%a@]" - tr.start.name tr.stop.name print_epsilon_trans tr.cross)) + (fun fmt tr -> Format.fprintf fmt "%a" + print_eps_trans tr)) transitions; states, transitions, needs_default | Otherwise -> [],[], false (* treated directly by type_seq *) @@ -1382,8 +1377,7 @@ let add_reject_trans auto intermediate_states = let cond = List.fold_left (fun acc tr -> - let cond,_ = tr.cross in - let cond = change_bound_var tr.stop st cond in + let cond = change_bound_var tr.stop st tr.cross in tor cond acc) TFalse my_trans in @@ -1393,35 +1387,38 @@ let add_reject_trans auto intermediate_states = | _ -> Aorai_option.debug "Adding default transition %s -> %s: %a" - st.name reject_state.name Promelaoutput.print_condition cond; - states, new_trans st reject_state (cond,[]) :: trans + st.name reject_state.name Promelaoutput.Typed.print_condition cond; + states, new_trans st reject_state cond [] :: trans in List.fold_left treat_one_state auto intermediate_states let propagate_epsilon_transitions (states, _ as auto) = - let rec transitive_closure start (conds,actions) known_states curr = + let rec transitive_closure start conds actions known_states curr = let known_states = curr :: known_states in let trans = Path_analysis.get_transitions_of_state curr auto in List.fold_left (fun acc tr -> match tr.cross with - | Epsilon (cond,my_actions) -> + | Epsilon cond -> Aorai_option.debug "Treating epsilon trans %s -> %s" curr.name tr.stop.name; if List.exists (fun st -> st.nums = tr.stop.nums) known_states then acc else transitive_closure - start (tand cond conds, my_actions @ actions) + start (tand cond conds) (tr.actions @ actions) known_states tr.stop @ acc - | Normal (cond, action) -> + | Normal cond -> Aorai_option.debug "Adding transition %s -> %s from epsilon trans" start.name tr.stop.name; - new_trans start tr.stop (tand cond conds,action @ actions) ::acc) + let tr = + new_trans start tr.stop (tand cond conds) (tr.actions @ actions) + in + tr :: acc) [] trans in let treat_one_state acc st = - acc @ transitive_closure st (TTrue,[]) [] st + acc @ transitive_closure st TTrue [] [] st in let trans = List.fold_left treat_one_state [] states in (states, trans) @@ -1435,26 +1432,26 @@ let add_default_trans (states, transitions as auto) otherwise = let cond = List.fold_left (fun acc c -> - let (cond,_) = c.cross in + let cond = c.cross in Aorai_option.debug "considering trans %s -> %s: %a" - c.start.name c.stop.name Promelaoutput.print_condition cond; + c.start.name c.stop.name Promelaoutput.Typed.print_condition cond; let neg = tnot cond in Aorai_option.debug "negation: %a" - Promelaoutput.print_condition neg; + Promelaoutput.Typed.print_condition neg; Aorai_option.debug "acc: %a" - Promelaoutput.print_condition acc; + Promelaoutput.Typed.print_condition acc; let res = tand acc (tnot cond) in Aorai_option.debug "partial result: %a" - Promelaoutput.print_condition res; + Promelaoutput.Typed.print_condition res; res ) TTrue my_trans in Aorai_option.debug "resulting transition: %a" - Promelaoutput.print_condition cond; + Promelaoutput.Typed.print_condition cond; let cond,_ = Logic_simplification.simplifyCond cond in - let new_trans = new_trans st tr.stop (cond,[]) in + let new_trans = new_trans st tr.stop cond [] in new_trans::acc in let transitions = List.fold_left add_one_trans transitions otherwise in @@ -1474,11 +1471,7 @@ let type_cond_auto auto = "Considering parsed transition %s -> %s" tr.start.name tr.stop.name; Aorai_option.debug "Resulting transitions:@\n%a@\nEnd of transitions" - (Pretty_utils.pp_list ~sep:"@\n" - (fun fmt tr -> - Format.fprintf fmt "%s -> %s: %a" - tr.start.name tr.stop.name print_epsilon_trans tr.cross)) - trans; + (Pretty_utils.pp_list ~sep:"@\n" print_eps_trans) trans; let add_reject = if needs_reject then (List.filter @@ -1504,20 +1497,19 @@ let type_cond_auto auto = let states, trans = match Reject_state.get_option () with | Some state -> - (states, (new_trans state state (TTrue,[])):: transitions) + (states, new_trans state state TTrue [] :: transitions) | None -> auto in let auto = { original_auto with states ; trans } in if Aorai_option.debug_atleast 1 then - Promelaoutput.output_dot_automata auto "aorai_debug_typed.dot"; + Promelaoutput.Typed.output_dot_automata auto "aorai_debug_typed.dot"; let (_,trans) = List.fold_left (fun (i,l as acc) t -> - let cond, action = t.cross in - let cond = fst (Logic_simplification.simplifyCond cond) + let cond = fst (Logic_simplification.simplifyCond t.cross) in match cond with TFalse -> acc - | _ -> (i+1,{ t with cross = (cond,action); numt = i } :: l)) + | _ -> (i+1,{ t with cross = cond; numt = i } :: l)) (0,[]) trans in let _, states = @@ -1562,7 +1554,7 @@ let setAutomata auto = automata:=Some auto; check_states "typed automata"; if Aorai_option.debug_atleast 1 then - Promelaoutput.output_dot_automata auto "aorai_debug_reduced.dot"; + Promelaoutput.Typed.output_dot_automata auto "aorai_debug_reduced.dot"; if (Array.length !cond_of_parametrizedTransitions) < (getNumberOfTransitions ()) then diff --git a/src/plugins/aorai/data_for_aorai.mli b/src/plugins/aorai/data_for_aorai.mli index 2d440c0e0e8..8c7ed586075 100644 --- a/src/plugins/aorai/data_for_aorai.mli +++ b/src/plugins/aorai/data_for_aorai.mli @@ -42,10 +42,8 @@ exception Empty_automaton module Aorai_state: Datatype.S_with_collections with type t = Promelaast.state -module Aorai_typed_trans: - Datatype.S_with_collections - with - type t = (Promelaast.typed_condition * Promelaast.action) Promelaast.trans +module Aorai_typed_trans: + Datatype.S_with_collections with type t = Promelaast.typed_trans (** Initializes some tables according to data from Cil AST. *) val setCData : unit -> unit @@ -201,13 +199,13 @@ val buch_sync : string val new_state: string -> state -val new_trans: state -> state -> 'a -> 'a trans +val new_trans: state -> state -> 'c -> 'a list -> ('c,'a) trans (** Return the buchi automata as stored after parsing *) val getAutomata : unit -> Promelaast.typed_automaton (** Return only the graph part of the automata *) -val getGraph : unit -> state list * (typed_condition * action) trans list +val getGraph : unit -> state list * typed_trans list (** Type-checks the parsed automaton and stores the result. This might introduce new global variables in case of sequences. @@ -249,8 +247,7 @@ val is_reject_state: state -> bool (** returns the transition having the corresponding id. @raise Not_found if this is not the case. *) -val getTransition: - int -> (Promelaast.typed_condition * Promelaast.action) Promelaast.trans +val getTransition: int -> Promelaast.typed_trans (* ************************************************************************* *) (**{b Variables information} Usually it seems very useful to access to varinfo diff --git a/src/plugins/aorai/logic_simplification.ml b/src/plugins/aorai/logic_simplification.ml index 88de692c01c..9bf174dd1ae 100644 --- a/src/plugins/aorai/logic_simplification.ml +++ b/src/plugins/aorai/logic_simplification.ml @@ -28,7 +28,7 @@ open Promelaast let pretty_clause fmt l = Format.fprintf fmt "@[<2>[%a@]]@\n" - (Pretty_utils.pp_list ~sep:",@ " Promelaoutput.print_condition) l + (Pretty_utils.pp_list ~sep:",@ " Promelaoutput.Typed.print_condition) l let pretty_dnf fmt l = Format.fprintf fmt "@[<2>[%a@]]@\n" @@ -360,7 +360,7 @@ let simplClause clause dnf = *) let simplifyCond condition = Aorai_option.debug - "initial condition: %a" Promelaoutput.print_condition condition; + "initial condition: %a" Promelaoutput.Typed.print_condition condition; (* Step 1 : Condition is translate into Disjunctive Normal Form *) let res1 = condToDNF condition in Aorai_option.debug "initial dnf: %a" pretty_dnf res1; @@ -394,14 +394,9 @@ let simplifyTrans transl = let (crossCond , pcond ) = simplifyCond (tr.cross) in (* pcond stands for parametrized condition : disjunction of conjunctions of parametrized call/return *) - let tr'={ start = tr.start ; - stop = tr.stop ; - cross = crossCond ; - numt = tr.numt - } - in + let tr'= { tr with cross = crossCond } in Aorai_option.debug "condition is %a, dnf is %a" - Promelaoutput.print_condition crossCond pretty_dnf pcond; + Promelaoutput.Typed.print_condition crossCond pretty_dnf pcond; if tr'.cross <> TFalse then (tr'::ltr,pcond::lpcond) else (ltr,lpcond) ) ([],[]) @@ -437,7 +432,7 @@ let simplifyDNFwrtCtx dnf kf1 status = in let res = tors (List.map simplCNFwrtCtx dnf) in Aorai_option.debug - "After simplification: %a" Promelaoutput.print_condition res; res + "After simplification: %a" Promelaoutput.Typed.print_condition res; res (* Tests : diff --git a/src/plugins/aorai/logic_simplification.mli b/src/plugins/aorai/logic_simplification.mli index 80956533bb6..6c58727222e 100644 --- a/src/plugins/aorai/logic_simplification.mli +++ b/src/plugins/aorai/logic_simplification.mli @@ -45,8 +45,8 @@ val simplifyCond: simplifyCond done on each cross condition. Uncrossable transition are removed. *) val simplifyTrans: - Promelaast.typed_condition Promelaast.trans list -> - (Promelaast.typed_condition Promelaast.trans list)* + Promelaast.typed_trans list -> + (Promelaast.typed_trans list)* (Promelaast.typed_condition list list list) val dnfToCond : diff --git a/src/plugins/aorai/promelaast.mli b/src/plugins/aorai/promelaast.mli index 3f7ac668c9f..518a203b36d 100644 --- a/src/plugins/aorai/promelaast.mli +++ b/src/plugins/aorai/promelaast.mli @@ -47,7 +47,6 @@ type condition = | PCall of string * string option (** Call might be done in a given behavior *) | PReturn of string - | PAssign of string * expression and seq_elt = { condition: condition option; @@ -62,7 +61,10 @@ and sequence = seq_elt list otherwise keyword. A single condition is expressed with a singleton having an empty nested sequence and min_rep and max_rep being equal to one. *) -type parsed_condition = Seq of sequence | Otherwise +type guard = Seq of sequence | Otherwise + +type action = + | Metavar_assign of string * expression type typed_condition = | TOr of typed_condition * typed_condition (** Logical OR *) @@ -80,7 +82,11 @@ type typed_condition = tied to the corresponding value. *) -type single_action = +(** Additional actions to perform when crossing a transition. + There is at most one Pebble_* action for each transition, and + each transition leading to a state with multi-state has such an action. + *) +type typed_action = | Counter_init of Cil_types.term_lval | Counter_incr of Cil_types.term_lval | Pebble_init of @@ -96,14 +102,9 @@ type single_action = moves pebbles from [old_set] to [new_set], governed by the corresponding aux variables. *) | Copy_value of Cil_types.term_lval * Cil_types.term - (** copy the current value of the given term into the given location - so that it can be accessed by a later state. *) + (** copy the current value of the given term into the given location + so that it can be accessed by a later state. *) -(** Additional actions to perform when crossing a transition. - There is at most one Pebble_* action for each transition, and - each transition leading to a state with multi-state has such an action. - *) -type action = single_action list (** Internal representation of a State from the Buchi automata. *) type state = @@ -125,23 +126,28 @@ type state = } (** Internal representation of a transition from the Buchi automata. *) -type 'condition trans = - { start : state ; (** Starting state of the transition *) - stop : state ; (** Ending state of the transition *) - mutable cross : 'condition ; (** Cross condition of the transition *) - mutable numt : int (** Numerical ID of the transition *) +type ('c,'a) trans = + { start : state ; (** Starting state of the transition *) + stop : state ; (** Ending state of the transition *) + mutable cross : 'c; (** Cross condition of the transition *) + mutable actions : 'a list; (** Actions to execute while crossing *) + mutable numt : int (** Numerical ID of the transition *) } +type parsed_trans = (guard, action) trans + +type typed_trans = (typed_condition, typed_action) trans + (** Internal representation of a Buchi automata : a list of states and a list of transitions.*) -type 'condition automaton = { +type ('c,'a) automaton = { states: state list; - trans: ('condition trans) list; + trans: (('c,'a) trans) list; metavariables: Cil_types.varinfo Datatype.String.Map.t; } -type parsed_automaton = parsed_condition automaton +type parsed_automaton = (guard, action) automaton -type typed_automaton = (typed_condition * action) automaton +type typed_automaton = (typed_condition, typed_action) automaton (** An operation can have two status: currently calling or returning. *) type funcStatus = diff --git a/src/plugins/aorai/promelaoutput.ml b/src/plugins/aorai/promelaoutput.ml index 85afe95f6ed..0eaf37ee308 100644 --- a/src/plugins/aorai/promelaoutput.ml +++ b/src/plugins/aorai/promelaoutput.ml @@ -30,139 +30,8 @@ open Promelaast open Bool3 open Format -let string_of_unop = function - | Uminus -> "-" - | Ustar -> "*" - | Uamp -> "&" - | Ubw_not -> "~" - -let rec print_parsed_expression fmt = function - | PVar s -> Format.fprintf fmt "%s" s - | PPrm (f,s) -> Format.fprintf fmt "%s().%s" f s - | PMetavar s -> Format.fprintf fmt "$%s" s - | PCst (IntConstant s) -> Format.fprintf fmt "%s" s - | PCst (FloatConstant s) -> Format.fprintf fmt "%s" s - | PCst (StringConstant s) -> Format.fprintf fmt "%S" s - | PCst (WStringConstant s) -> Format.fprintf fmt "%S" s - | PBinop(bop,e1,e2) -> - Format.fprintf fmt "(@[%a@])@ %a@ (@[%a@])" - print_parsed_expression e1 Printer.pp_binop (Logic_typing.type_binop bop) - print_parsed_expression e2 - | PUnop(uop,e) -> Format.fprintf fmt "%s@;(@[%a@])" - (string_of_unop uop) - print_parsed_expression e - | PArrget(e1,e2) -> Format.fprintf fmt "%a@;[@(%a@]]" - print_parsed_expression e1 print_parsed_expression e2 - | PField(e,s) -> Format.fprintf fmt "%a.%s" print_parsed_expression e s - | PArrow(e,s) -> Format.fprintf fmt "%a->%s" print_parsed_expression e s - -let rec print_parsed_condition fmt = function - | PRel(rel,e1,e2) -> - Format.fprintf fmt "%a %a@ %a" - print_parsed_expression e1 - Printer.pp_relation (Logic_typing.type_rel rel) - print_parsed_expression e2 - | PTrue -> Format.pp_print_string fmt "true" - | PFalse -> Format.pp_print_string fmt "false" - | POr(e1,e2) -> Format.fprintf fmt "(@[%a@])@ or@ (@[%a@])" - print_parsed_condition e1 print_parsed_condition e2 - | PAnd(e1,e2) -> Format.fprintf fmt "(@[%a@])@ and@ (@[%a@])" - print_parsed_condition e1 print_parsed_condition e2 - | PNot c -> Format.fprintf fmt "not(@[%a@])" - print_parsed_condition c - | PCall (s,None) -> Format.fprintf fmt "CALL(%s)" s - | PCall (s, Some b) -> Format.fprintf fmt "CALL(%s::%s)" s b - | PReturn s -> Format.fprintf fmt "RETURN(%s)" s - | PAssign (s, e) -> Format.fprintf fmt " %s := %a " s print_parsed_expression e - -let rec print_seq_elt fmt elt = - Format.fprintf fmt "(%a%a){@[%a,%a@]}" - (Pretty_utils.pp_opt print_parsed_condition) elt.condition - print_sequence elt.nested - (Pretty_utils.pp_opt print_parsed_expression) elt.min_rep - (Pretty_utils.pp_opt print_parsed_expression) elt.max_rep - -and print_sequence fmt l = - Pretty_utils.pp_list ~pre:"[@[" ~sep:";@ " ~suf:"@]]" print_seq_elt fmt l - -let print_parsed fmt = function - | Seq l -> print_sequence fmt l - | Otherwise -> Format.pp_print_string fmt "Otherwise" - -let rec print_condition fmt = function - | TCall (kf,None) -> - Format.fprintf fmt "Call(%a)" Kernel_function.pretty kf - | TCall (kf, Some b) -> - Format.fprintf fmt "Call(%a::%s)" - Kernel_function.pretty kf b.Cil_types.b_name - | TReturn kf -> - Format.fprintf fmt "Return(%a)" Kernel_function.pretty kf - | TOr (c1,c2) -> - Format.fprintf fmt "@[<hov>(@[<2>%a@])@]@ or@ @[<hov>(@[<2>%a@])@]" - print_condition c1 print_condition c2 - | TAnd (c1,c2) -> - Format.fprintf fmt "@[<hov>(@[<2>%a@])@]@ and@ @[<hov>(@[<2>%a@])@]" - print_condition c1 print_condition c2 - | TNot c -> - Format.fprintf fmt "@[<hov 4>@[<hov 5>not(%a@])@]" print_condition c - | TTrue -> Format.pp_print_string fmt "True" - | TFalse -> Format.pp_print_string fmt "False" - | TRel(rel,exp1,exp2) -> - (* \result will be printed as such, not as f().return *) - Format.fprintf fmt "@[(%a)@]@ %a@ @[(%a)@]" - Printer.pp_term exp1 - Printer.pp_relation rel - Printer.pp_term exp2 - -let print_one_action fmt = function - | Counter_init lv -> - Format.fprintf fmt "@[%a <- 1@]" Printer.pp_term_lval lv - | Counter_incr lv -> - Format.fprintf fmt "@[%a <- @[%a@ +@ 1@]@]" - Printer.pp_term_lval lv Printer.pp_term_lval lv - | Pebble_init (set,_,v) -> - Format.fprintf fmt "@[%a <- {@[ %a @]}@]" - Printer.pp_logic_var set.l_var_info Printer.pp_logic_var v - | Pebble_move(s1,_,s2,_) -> - Format.fprintf fmt "@[%a <- %a@]" - Printer.pp_logic_var s1.l_var_info - Printer.pp_logic_var s2.l_var_info - | Copy_value(lv,v) -> - Format.fprintf fmt "@[%a <- %a@]" Printer.pp_term_lval lv Printer.pp_term v - -let print_action fmt l = - Pretty_utils.pp_list ~sep:"@\n" print_one_action fmt l - -(* Use well-parenthesized combination of escape_newline/normal_newline*) -let escape_newline fmt = - let funcs = Format.pp_get_formatter_out_functions fmt () in - let has_printed = ref false in - let out_newline () = - if !has_printed then funcs.Format.out_string " \\\n" 0 3 - else funcs.Format.out_newline () - in - let out_string s b l = - if String.contains (String.sub s b l) '"' then - has_printed:=not !has_printed; - funcs.Format.out_string s b l - in - Format.pp_set_formatter_out_functions fmt - { funcs with Format.out_newline; out_string }; - funcs - -let print_full_transition fmt (cond,action) = - Format.fprintf fmt "%a@\n%a" print_condition cond print_action action - -let trans_label num = "tr"^string_of_int(num) - -let print_trans fmt trans = - Format.fprintf fmt - "@[<2>%s:@ %a@]" - (trans_label trans.numt) print_full_transition trans.cross +type 'a printer = Format.formatter -> 'a -> unit -let state_label num = "st"^string_of_int(num) -let print_state_label fmt st = - Format.fprintf fmt "@[<2>%s:@ %s@]" (state_label st.nums) st.name let print_bool3 fmt b = Format.pp_print_string fmt @@ -171,14 +40,6 @@ let print_bool3 fmt b = | False -> "False" | Undefined -> "Undef") -let print_transition fmt tr = - Format.fprintf fmt "@[<2>{@ %d:@ %s@ {%a}@ %s@]}" - tr.numt tr.start.name print_full_transition tr.cross tr.stop.name - -let print_transitionl fmt trl = - Format.fprintf fmt "@[<2>Transitions:@\n%a@]" - (Pretty_utils.pp_list ~sep:"@\n" ~suf:"@\n" print_transition) trl - let print_state fmt st = Format.fprintf fmt "@[<2>%s@ (acc=%a;@ init=%a;@ num=%d)@]" st.name print_bool3 st.acceptation print_bool3 st.init st.nums @@ -187,64 +48,223 @@ let print_statel fmt stl = Format.fprintf fmt "@[<2>States:@\n%a@]" (Pretty_utils.pp_list ~sep:"@\n" ~suf:"@\n" print_state) stl -let print_raw_automata fmt auto = - Format.fprintf fmt "@[<2>Automaton:@\n%a%a@]" - print_statel auto.states print_transitionl auto.trans - -let dot_state out st = - let shape = - if st.init = Bool3.True && st.acceptation=Bool3.True then "doubleoctagon" - else if st.acceptation=Bool3.True then "octagon" - else if st.init=Bool3.True then "doublecircle" - else "circle" - in - Format.fprintf out "\"%a\" [shape = %s];@\n" print_state_label st shape - -let dot_trans out tr = - let print_label fmt tr = - if DotSeparatedLabels.get () then - Format.pp_print_int fmt tr.numt - else print_trans fmt tr - in - Format.fprintf - out - "\"%a\"@ ->@ \"%a\"@ [label = @[\"%a\"@]];@\n" - print_state_label tr.start - print_state_label tr.stop - print_label tr - -let output_dot_automata {states ; trans} fichier = - let cout = open_out fichier in - let fmt = formatter_of_out_channel cout in - let output_functions = escape_newline fmt in - let one_line_comment s = - let l = String.length s in - let fill = if l >= 75 then 0 else 75 - l in - let spaces = String.make fill ' ' in - Format.fprintf fmt "@[/* %s%s*/@\n@]" s spaces - in - one_line_comment "File generated by Aorai LTL2ACSL Plug-in"; - one_line_comment ""; - one_line_comment "Usage of dot files '.dot' :"; - one_line_comment " dot <MyFile.dot> -T<DesiredType> > <OutputFile>"; - one_line_comment ""; - one_line_comment " Allowed types : canon,dot,xdot,fig,gd,gd2,"; - one_line_comment " gif,hpgl,imap,cmap,ismap,jpg,jpeg,mif,mp,pcl,pic,plain,"; - one_line_comment " plain-ext,png,ps,ps2,svg,svgz,vrml,vtx,wbmp"; - one_line_comment ""; - one_line_comment " Example with postscript file :"; - one_line_comment " dot property.dot -Tps > property.ps"; - Format.fprintf fmt "@[<2>@\ndigraph %s {@\n@\n%a@\n%a@\n%t}@\n@]" - (Filename.chop_extension (Filename.basename fichier)) - (Pretty_utils.pp_list dot_state) states - (Pretty_utils.pp_list dot_trans) trans - (fun fmt -> +let state_label num = "st"^string_of_int(num) +let print_state_label fmt st = + Format.fprintf fmt "@[<2>%s:@ %s@]" (state_label st.nums) st.name + + +module Parsed = +struct + let string_of_unop = function + | Uminus -> "-" + | Ustar -> "*" + | Uamp -> "&" + | Ubw_not -> "~" + + let rec print_expression fmt = function + | PVar s -> Format.fprintf fmt "%s" s + | PPrm (f,s) -> Format.fprintf fmt "%s().%s" f s + | PMetavar s -> Format.fprintf fmt "$%s" s + | PCst (IntConstant s) -> Format.fprintf fmt "%s" s + | PCst (FloatConstant s) -> Format.fprintf fmt "%s" s + | PCst (StringConstant s) -> Format.fprintf fmt "%S" s + | PCst (WStringConstant s) -> Format.fprintf fmt "%S" s + | PBinop(bop,e1,e2) -> + Format.fprintf fmt "(@[%a@])@ %a@ (@[%a@])" + print_expression e1 Printer.pp_binop (Logic_typing.type_binop bop) + print_expression e2 + | PUnop(uop,e) -> Format.fprintf fmt "%s@;(@[%a@])" + (string_of_unop uop) + print_expression e + | PArrget(e1,e2) -> Format.fprintf fmt "%a@;[@(%a@]]" + print_expression e1 print_expression e2 + | PField(e,s) -> Format.fprintf fmt "%a.%s" print_expression e s + | PArrow(e,s) -> Format.fprintf fmt "%a->%s" print_expression e s + + let rec print_condition fmt = function + | PRel(rel,e1,e2) -> + Format.fprintf fmt "%a %a@ %a" + print_expression e1 + Printer.pp_relation (Logic_typing.type_rel rel) + print_expression e2 + | PTrue -> Format.pp_print_string fmt "true" + | PFalse -> Format.pp_print_string fmt "false" + | POr(e1,e2) -> Format.fprintf fmt "(@[%a@])@ or@ (@[%a@])" + print_condition e1 print_condition e2 + | PAnd(e1,e2) -> Format.fprintf fmt "(@[%a@])@ and@ (@[%a@])" + print_condition e1 print_condition e2 + | PNot c -> Format.fprintf fmt "not(@[%a@])" + print_condition c + | PCall (s,None) -> Format.fprintf fmt "CALL(%s)" s + | PCall (s, Some b) -> Format.fprintf fmt "CALL(%s::%s)" s b + | PReturn s -> Format.fprintf fmt "RETURN(%s)" s + + let rec print_seq_elt fmt elt = + Format.fprintf fmt "(%a%a){@[%a,%a@]}" + (Pretty_utils.pp_opt print_condition) elt.condition + print_sequence elt.nested + (Pretty_utils.pp_opt print_expression) elt.min_rep + (Pretty_utils.pp_opt print_expression) elt.max_rep + + and print_sequence fmt l = + Pretty_utils.pp_list ~pre:"[@[" ~sep:";@ " ~suf:"@]]" print_seq_elt fmt l + + let print_guard fmt = function + | Seq l -> print_sequence fmt l + | Otherwise -> Format.pp_print_string fmt "Otherwise" + + let print_action fmt = function + | Metavar_assign (s, e) -> + Format.fprintf fmt "@[$%s := %a@]" s print_expression e + + let print_actionl fmt l = + Pretty_utils.pp_list ~sep:"@\n" print_action fmt l +end + + +module Typed = +struct + let rec print_condition fmt = function + | TCall (kf,None) -> + Format.fprintf fmt "Call(%a)" Kernel_function.pretty kf + | TCall (kf, Some b) -> + Format.fprintf fmt "Call(%a::%s)" + Kernel_function.pretty kf b.Cil_types.b_name + | TReturn kf -> + Format.fprintf fmt "Return(%a)" Kernel_function.pretty kf + | TOr (c1,c2) -> + Format.fprintf fmt "@[<hov>(@[<2>%a@])@]@ or@ @[<hov>(@[<2>%a@])@]" + print_condition c1 print_condition c2 + | TAnd (c1,c2) -> + Format.fprintf fmt "@[<hov>(@[<2>%a@])@]@ and@ @[<hov>(@[<2>%a@])@]" + print_condition c1 print_condition c2 + | TNot c -> + Format.fprintf fmt "@[<hov 4>@[<hov 5>not(%a@])@]" print_condition c + | TTrue -> Format.pp_print_string fmt "True" + | TFalse -> Format.pp_print_string fmt "False" + | TRel(rel,exp1,exp2) -> + (* \result will be printed as such, not as f().return *) + Format.fprintf fmt "@[(%a)@]@ %a@ @[(%a)@]" + Printer.pp_term exp1 + Printer.pp_relation rel + Printer.pp_term exp2 + + let print_action fmt = function + | Counter_init lv -> + Format.fprintf fmt "@[%a <- 1@]" Printer.pp_term_lval lv + | Counter_incr lv -> + Format.fprintf fmt "@[%a <- @[%a@ +@ 1@]@]" + Printer.pp_term_lval lv Printer.pp_term_lval lv + | Pebble_init (set,_,v) -> + Format.fprintf fmt "@[%a <- {@[ %a @]}@]" + Printer.pp_logic_var set.l_var_info Printer.pp_logic_var v + | Pebble_move(s1,_,s2,_) -> + Format.fprintf fmt "@[%a <- %a@]" + Printer.pp_logic_var s1.l_var_info + Printer.pp_logic_var s2.l_var_info + | Copy_value(lv,v) -> + Format.fprintf fmt "@[%a <- %a@]" Printer.pp_term_lval lv Printer.pp_term v + + let print_actionl fmt l = + Pretty_utils.pp_list ~sep:"@\n" print_action fmt l + + (* Use well-parenthesized combination of escape_newline/normal_newline*) + let escape_newline fmt = + let funcs = Format.pp_get_formatter_out_functions fmt () in + let has_printed = ref false in + let out_newline () = + if !has_printed then funcs.Format.out_string " \\\n" 0 3 + else funcs.Format.out_newline () + in + let out_string s b l = + if String.contains (String.sub s b l) '"' then + has_printed:=not !has_printed; + funcs.Format.out_string s b l + in + Format.pp_set_formatter_out_functions fmt + { funcs with Format.out_newline; out_string }; + funcs + + let trans_label num = "tr"^string_of_int(num) + + let print_trans fmt trans = + Format.fprintf fmt + "@[<2>%s:@ %a@\n%a@]" + (trans_label trans.numt) + print_condition trans.cross + print_actionl trans.actions + + let print_transition fmt tr = + Format.fprintf fmt "@[<2>{@ %d:@ %s@ {%a@\n%a}@ %s@]}" + tr.numt + tr.start.name + print_condition tr.cross + print_actionl tr.actions + tr.stop.name + + let print_transitionl fmt trl = + Format.fprintf fmt "@[<2>Transitions:@\n%a@]" + (Pretty_utils.pp_list ~sep:"@\n" ~suf:"@\n" print_transition) trl + + let print_automata fmt auto = + Format.fprintf fmt "@[<2>Automaton:@\n%a%a@]" + print_statel auto.states print_transitionl auto.trans + + let dot_state out st = + let shape = + if st.init = Bool3.True && st.acceptation=Bool3.True then "doubleoctagon" + else if st.acceptation=Bool3.True then "octagon" + else if st.init=Bool3.True then "doublecircle" + else "circle" + in + Format.fprintf out "\"%a\" [shape = %s];@\n" print_state_label st shape + + let dot_trans out tr = + let print_label fmt tr = if DotSeparatedLabels.get () then - (Format.fprintf fmt - "/* guards of transitions */@\ncomment=\"%a\";@\n" - (Pretty_utils.pp_list ~sep:"@\n" print_trans) trans)); - Format.pp_set_formatter_out_functions fmt output_functions; - close_out cout + Format.pp_print_int fmt tr.numt + else print_trans fmt tr + in + Format.fprintf + out + "\"%a\"@ ->@ \"%a\"@ [label = @[\"%a\"@]];@\n" + print_state_label tr.start + print_state_label tr.stop + print_label tr + + let output_dot_automata {states ; trans} fichier = + let cout = open_out fichier in + let fmt = formatter_of_out_channel cout in + let output_functions = escape_newline fmt in + let one_line_comment s = + let l = String.length s in + let fill = if l >= 75 then 0 else 75 - l in + let spaces = String.make fill ' ' in + Format.fprintf fmt "@[/* %s%s*/@\n@]" s spaces + in + one_line_comment "File generated by Aorai LTL2ACSL Plug-in"; + one_line_comment ""; + one_line_comment "Usage of dot files '.dot' :"; + one_line_comment " dot <MyFile.dot> -T<DesiredType> > <OutputFile>"; + one_line_comment ""; + one_line_comment " Allowed types : canon,dot,xdot,fig,gd,gd2,"; + one_line_comment " gif,hpgl,imap,cmap,ismap,jpg,jpeg,mif,mp,pcl,pic,plain,"; + one_line_comment " plain-ext,png,ps,ps2,svg,svgz,vrml,vtx,wbmp"; + one_line_comment ""; + one_line_comment " Example with postscript file :"; + one_line_comment " dot property.dot -Tps > property.ps"; + Format.fprintf fmt "@[<2>@\ndigraph %s {@\n@\n%a@\n%a@\n%t}@\n@]" + (Filename.chop_extension (Filename.basename fichier)) + (Pretty_utils.pp_list dot_state) states + (Pretty_utils.pp_list dot_trans) trans + (fun fmt -> + if DotSeparatedLabels.get () then + (Format.fprintf fmt + "/* guards of transitions */@\ncomment=\"%a\";@\n" + (Pretty_utils.pp_list ~sep:"@\n" print_trans) trans)); + Format.pp_set_formatter_out_functions fmt output_functions; + close_out cout +end (* Local Variables: diff --git a/src/plugins/aorai/promelaoutput.mli b/src/plugins/aorai/promelaoutput.mli index 75dcc4bba26..3edf6aabb28 100644 --- a/src/plugins/aorai/promelaoutput.mli +++ b/src/plugins/aorai/promelaoutput.mli @@ -23,35 +23,35 @@ (* *) (**************************************************************************) -val print_raw_automata : - Format.formatter -> Promelaast.typed_automaton -> unit +open Promelaast + +type 'a printer = Format.formatter -> 'a -> unit + +val print_state : state printer +val print_statel : state list printer + +module Parsed: +sig + val print_expression: expression printer + val print_condition: condition printer + val print_seq_elt: seq_elt printer + val print_sequence: sequence printer + val print_guard: guard printer + val print_action: action printer + val print_actionl: action list printer +end + +module Typed: +sig + val print_condition : typed_condition printer + val print_action: typed_action printer + val print_actionl: typed_action list printer + val print_transition: typed_trans printer + val print_transitionl: typed_trans list printer + val print_automata : typed_automaton printer + val output_dot_automata : typed_automaton -> string -> unit +end -val print_parsed_expression: Format.formatter -> Promelaast.expression -> unit - -val print_parsed_condition: Format.formatter -> Promelaast.condition -> unit - -val print_seq_elt: Format.formatter -> Promelaast.seq_elt -> unit - -val print_sequence: Format.formatter -> Promelaast.sequence -> unit - -val print_parsed: Format.formatter -> Promelaast.parsed_condition -> unit - -val print_condition: Format.formatter -> Promelaast.typed_condition -> unit - -val print_action: Format.formatter -> Promelaast.action -> unit - -val print_transition: - Format.formatter -> - (Promelaast.typed_condition * Promelaast.action) Promelaast.trans -> unit - -val print_transitionl: - Format.formatter -> - (Promelaast.typed_condition * Promelaast.action) Promelaast.trans list -> unit - -val print_state : Format.formatter -> Promelaast.state -> unit -val print_statel : Format.formatter -> Promelaast.state list -> unit - -val output_dot_automata : Promelaast.typed_automaton -> string -> unit (* Local Variables: diff --git a/src/plugins/aorai/promelaparser.mly b/src/plugins/aorai/promelaparser.mly index 2946304bdbe..4bcac643722 100644 --- a/src/plugins/aorai/promelaparser.mly +++ b/src/plugins/aorai/promelaparser.mly @@ -119,9 +119,9 @@ state trans else let tr_list= - List.fold_left (fun l1 (cr,stop_st) -> - List.fold_left (fun l2 st -> - {start=st;stop=stop_st;cross=Seq (to_seq cr);numt=(-1)}::l2 + List.fold_left (fun l1 (cr,stop) -> + List.fold_left (fun l2 start -> + {start;stop;cross=Seq (to_seq cr);actions=[];numt=(-1)}::l2 ) l1 stl ) [] trl in @@ -166,7 +166,7 @@ label (String.compare (String.sub $1 0 10) "accept_all")=0 then trans:= - {start=old;stop=old;cross=Seq (to_seq PTrue);numt=(-1)} :: + {start=old;stop=old;cross=Seq (to_seq PTrue);actions=[];numt=(-1)} :: !trans; (* If the name includes accept then this state is an acceptation one. *) diff --git a/src/plugins/aorai/promelaparser_withexps.mly b/src/plugins/aorai/promelaparser_withexps.mly index 1fd125c99c7..bf852a65f37 100644 --- a/src/plugins/aorai/promelaparser_withexps.mly +++ b/src/plugins/aorai/promelaparser_withexps.mly @@ -128,9 +128,9 @@ state trans else let tr_list= - List.fold_left (fun l1 (cr,stop_st) -> - List.fold_left (fun l2 st -> - {start=st;stop=stop_st;cross=Seq (to_seq cr);numt=(-1)}::l2 + List.fold_left (fun l1 (cr,stop) -> + List.fold_left (fun l2 start -> + {start;stop;cross=Seq (to_seq cr);actions=[];numt=(-1)}::l2 ) l1 stl ) [] trl in @@ -178,7 +178,7 @@ label (String.compare (String.sub $1 0 10) "accept_all")=0 then trans:= - {start=old;stop=old;cross=Seq (to_seq PTrue);numt=(-1)}::!trans; + {start=old;stop=old;cross=Seq (to_seq PTrue);actions=[];numt=(-1)}::!trans; (* If the name includes accept then this state is an acceptation one. *) diff --git a/src/plugins/aorai/tests/ya/metavariables-right.ya b/src/plugins/aorai/tests/ya/metavariables-right.ya index 2e5be920ec1..bacd7713870 100644 --- a/src/plugins/aorai/tests/ya/metavariables-right.ya +++ b/src/plugins/aorai/tests/ya/metavariables-right.ya @@ -7,7 +7,7 @@ $x : int; a : { CALL(main) } -> b; b : - { CALL(f) && $x := f().x } -> c + { CALL(f) } $x := f().x -> c | { CALL(g) } -> d ; @@ -24,6 +24,6 @@ f : { RETURN(h) } -> g; g : { CALL(i) } -> h; -h : { RETURN(i) && $x := 1 } -> e; +h : { RETURN(i) } $x := 1 -> e; i : -> i; diff --git a/src/plugins/aorai/tests/ya/metavariables-wrong.ya b/src/plugins/aorai/tests/ya/metavariables-wrong.ya index 6ab66a2fa64..8a29440dfdd 100644 --- a/src/plugins/aorai/tests/ya/metavariables-wrong.ya +++ b/src/plugins/aorai/tests/ya/metavariables-wrong.ya @@ -7,7 +7,7 @@ $x : int; a : { CALL(main) } -> b; b : - { CALL(f) && $x := f().x } -> c + { CALL(f) } $x := f().x -> c | { CALL(g) } -> d | { RETURN(main) } -> g ; diff --git a/src/plugins/aorai/tests/ya/stack.ya b/src/plugins/aorai/tests/ya/stack.ya index 4bbf8c1355f..29c24e7847e 100644 --- a/src/plugins/aorai/tests/ya/stack.ya +++ b/src/plugins/aorai/tests/ya/stack.ya @@ -5,7 +5,7 @@ $n : int; init: - { CALL(main) && $n := 0 } -> empty_stack + { CALL(main) } $n := 0 -> empty_stack ; empty_stack: @@ -14,7 +14,7 @@ empty_stack: ; filling_stack: - { RETURN(push) && $n := $n + 1 } -> filled_stack + { RETURN(push) } $n := $n + 1 -> filled_stack ; filled_stack: @@ -23,8 +23,8 @@ filled_stack: ; emptying_stack: - { RETURN(pop) && $n > 1 && $n := $n - 1 } -> filled_stack -| { RETURN(pop) && $n == 1 && $n := $n - 1 } -> empty_stack + { RETURN(pop) && $n > 1 } $n := $n - 1 -> filled_stack +| { RETURN(pop) && $n == 1 } $n := $n - 1 -> empty_stack ; accept: -> accept; diff --git a/src/plugins/aorai/yaparser.mly b/src/plugins/aorai/yaparser.mly index ab9603e45c5..655a5d32db9 100644 --- a/src/plugins/aorai/yaparser.mly +++ b/src/plugins/aorai/yaparser.mly @@ -158,7 +158,7 @@ type pre_cond = Behavior of string | Pre of Promelaast.condition %left DOT %nonassoc NOT TRUE FALSE %nonassoc QUESTION -%right SEMICOLON +%right SEMI_COLON %nonassoc lowest %type <Promelaast.parsed_automaton> main @@ -214,7 +214,7 @@ state let start_state = fetch_and_create_state $1 in let (_, transitions) = List.fold_left - (fun (otherwise, transitions) (cross,stop_state) -> + (fun (otherwise, transitions) (cross,actions,stop_state) -> if otherwise then Aorai_option.abort "'other' directive in definition of %s \ @@ -222,7 +222,7 @@ state else begin let trans = { start=start_state; stop=stop_state; - cross=cross; numt=(-1) }::transitions + cross; actions; numt=(-1) }::transitions in let otherwise = match cross with @@ -242,10 +242,12 @@ transitions /*=> [transition; ...] */ transition: /*=> (guard, state) */ - | LCURLY seq_elt RCURLY RARROW IDENTIFIER - { (Seq $2, prefetch_and_create_state $5) } - | OTHERWISE RARROW IDENTIFIER {(Otherwise, prefetch_and_create_state $3) } - | RARROW IDENTIFIER { (Seq (to_seq PTrue), prefetch_and_create_state $2) } + | LCURLY seq_elt RCURLY actions RARROW IDENTIFIER + { (Seq $2, $4, prefetch_and_create_state $6) } + | OTHERWISE actions RARROW IDENTIFIER + { (Otherwise, $2, prefetch_and_create_state $4) } + | actions RARROW IDENTIFIER + { (Seq (to_seq PTrue), $1, prefetch_and_create_state $3) } ; non_empty_seq: @@ -338,7 +340,6 @@ single_cond: | single_cond OR single_cond { POr ($1,$3) } | LPAREN single_cond RPAREN { $2 } | logic_relation { $1 } - | METAVAR AFF arith_relation { PAssign ($1, $3) } ; logic_relation @@ -392,3 +393,17 @@ access_leaf | LPAREN access RPAREN { $2 } | METAVAR { PMetavar $1 } ; + +actions + : /* epsilon */ { [] } + | non_empty_actions { $1 } + ; + +non_empty_actions + : non_empty_actions action { $1 @ [$2] } + | action { [$1] } + ; + +action + : METAVAR AFF arith_relation { Metavar_assign ($1, $3) } + ; -- GitLab