diff --git a/src/kernel_services/ast_building/cil_builder.ml b/src/kernel_services/ast_building/cil_builder.ml index 62e90943b9eb30621cf58f479633bc13f5c0ea0d..c59609f5aa9536d2b996066c580f36e2f9f93b2d 100644 --- a/src/kernel_services/ast_building/cil_builder.ml +++ b/src/kernel_services/ast_building/cil_builder.ml @@ -537,11 +537,84 @@ struct let loc = Location.loc + + (* Conversion to Cil *) + + let build_instr_list l = + let rev_build_one acc = function + | Label _ | CilStmt _ | CilStmtkind _ -> + raise (WrongContext "not convertible to instr") + | CilInstr instr -> instr :: acc + in + List.fold_left rev_build_one [] l + + let build_stmt_list ~ghost l = + let rev_build_one acc = function + | Label l -> + begin match acc with + | [] -> (* No generated statement to attach the label to *) + let stmt = Cil.mkEmptyStmt ~ghost ~loc () in + stmt.Cil_types.labels <- [l]; + stmt :: acc + | stmt :: _ -> (* There is a statement to attach the label to *) + stmt.Cil_types.labels <- l :: stmt.Cil_types.labels; + acc + end + | CilStmt stmt -> + stmt :: acc + | CilStmtkind sk -> + Cil.mkStmt ~ghost sk :: acc + | CilInstr instr -> + Cil.mkStmt ~ghost (Cil_types.Instr instr) :: acc + in + List.fold_left rev_build_one [] l + + let build_block b = + let block = Cil.mkBlock (build_stmt_list ~ghost:b.ghost b.stmts) in + block.Cil_types.blocals <- List.rev b.vars; + block + + let build_stmtkind b = + let block = build_block b in + match b.scope_type with + | Block -> + Cil_types.Block block + | IfThen { ifthen_exp } -> + Cil_types.If (ifthen_exp, block, Cil.mkBlock [], loc) + | IfThenElse { ifthenelse_exp; then_block } -> + Cil_types.If (ifthenelse_exp, then_block, block, loc) + | Switch { switch_exp } -> + let open Cil_types in + (* Case are only allowed in the current block by the case function *) + let contains_case stmt = + List.exists (function Case _ -> true | _ -> false) stmt.labels + in + let case_stmts = List.filter contains_case block.bstmts in + Cil_types.Switch (switch_exp, block, case_stmts , loc) + | Function _ -> + raise (WrongContext "not convertible to stmtkind") + + (* State management *) - let stack : scope list ref = ref [] let owner: Cil_types.fundec option ref = ref None + let reset_owner () = + owner := None + + let set_owner o = + if Extlib.has_some !owner then + raise (WrongContext "already in a function"); + owner := Some o + + let get_owner () = + match !owner with + | None -> raise (WrongContext "function context not set") + | Some fundec -> fundec + + + let stack : scope list ref = ref [] + let pretty_stack fmt = let pretty_stack_type fmt b = match b.scope_type with @@ -584,72 +657,20 @@ struct hd let finish () = + reset_owner (); match !stack with | [] -> raise (WrongContext "not in an opened context") | [b] -> b | _ :: _ :: _ -> raise (WrongContext "all contextes have not been closed") - let reset_owner () = - owner := None - - let set_owner o = - owner := Some o - - let get_owner () = - match !owner with - | None -> raise (WrongContext "not in an opened function") - | Some fundec -> fundec - let append_stmt b s = b.stmts <- s :: b.stmts - (* Conversion to Cil *) - - let build_stmt_list ~ghost l = - let rev_build_one acc = function - | Label l -> - begin match acc with - | [] -> (* No generated statement to attach the label to *) - let stmt = Cil.mkEmptyStmt ~ghost ~loc () in - stmt.Cil_types.labels <- [l]; - stmt :: acc - | stmt :: _ -> (* There is a statement to attach the label to *) - stmt.Cil_types.labels <- l :: stmt.Cil_types.labels; - acc - end - | CilStmt stmt -> - stmt :: acc - | CilStmtkind sk -> - Cil.mkStmt ~ghost sk :: acc - | CilInstr instr -> - Cil.mkStmt ~ghost (Cil_types.Instr instr) :: acc - in - List.fold_left rev_build_one [] l - - let build_block b = - let block = Cil.mkBlock (build_stmt_list ~ghost:b.ghost b.stmts) in - block.Cil_types.blocals <- List.rev b.vars; - block + let append_local v = + let fundec = get_owner () and b = top () in + fundec.Cil_types.slocals <- fundec.Cil_types.slocals @ [v]; + b.vars <- v :: b.vars - let build_stmtkind b = - let block = build_block b in - match b.scope_type with - | Block -> - Cil_types.Block block - | IfThen { ifthen_exp } -> - Cil_types.If (ifthen_exp, block, Cil.mkBlock [], loc) - | IfThenElse { ifthenelse_exp; then_block } -> - Cil_types.If (ifthenelse_exp, then_block, block, loc) - | Switch { switch_exp } -> - let open Cil_types in - (* Case are only allowed in the current block by the case function *) - let contains_case stmt = - List.exists (function Case _ -> true | _ -> false) stmt.labels - in - let case_stmts = List.filter contains_case block.bstmts in - Cil_types.Switch (switch_exp, block, case_stmts , loc) - | Function _ -> - raise (WrongContext "not convertible to stmtkind") (* Statements *) @@ -678,17 +699,20 @@ struct push (new_block ?ghost (Function {fundec})); `var fundec.Cil_types.svar - let open_block () = - push (new_block Block) + let open_block ?into ?ghost () = + Extlib.may set_owner into; + push (new_block ?ghost Block) - let open_ghost () = - push (new_block ~ghost:true Block) + let open_ghost ?into () = + open_block ?into ~ghost:true () - let open_switch exp = + let open_switch ?into exp = + Extlib.may set_owner into; let switch_exp = cil_exp ~loc exp in push (new_block (Switch {switch_exp})) - let open_if exp = + let open_if ?into exp = + Extlib.may set_owner into; let ifthen_exp = cil_exp ~loc exp in push (new_block (IfThen {ifthen_exp})) @@ -712,6 +736,17 @@ struct | Cil_types.Block b -> b | _ -> raise (WrongContext "not in an opened simple block context") + let finish_instr_list ?scope () = + let b = finish () in + begin match scope, b.vars with + | None, [] -> () (* Nothing to do *) + | Some block, vars -> + block.Cil_types.blocals <- List.rev vars @ block.Cil_types.blocals + | None, _ :: _ -> + raise (WrongContext "a scope must be provide to insert local variables") + end; + build_instr_list b.stmts + let finish_stmt () = let b = finish () in Cil.mkStmt ~ghost:b.ghost (build_stmtkind b) @@ -731,7 +766,6 @@ struct Cfg.prepareCFG ~keepSwitch fundec; Cfg.cfgFun fundec; end; - reset_owner (); GFun (fundec,loc) | _ -> raise (WrongContext "not in a opened function context") @@ -778,7 +812,7 @@ struct let local' ?(ghost=false) ?init typ name = let fundec = get_owner () and b = top () in let ghost = ghost || b.ghost in - let v = Cil.makeLocalVar fundec ~insert:false ~ghost ~loc name typ in + let v = Cil.makeLocalVar ~insert:false ~ghost ~loc fundec name typ in begin match init with | None -> () | Some init -> @@ -786,6 +820,7 @@ struct instr (Cil_types.Local_init (v, local_init, loc)); v.vdefined <- true end; + append_local v; `var v let local ?ghost ?init typ name = @@ -798,8 +833,7 @@ struct let v = Cil.copyVarinfo vi (vi.Cil_types.vname ^ suffix) in v.vghost <- v.vghost || ghost; Cil.refresh_local_name fundec v; - fundec.Cil_types.slocals <- fundec.Cil_types.slocals @ [v]; - b.vars <- v :: b.vars; + append_local v; `var v let parameter ?(ghost=false) ?(attributes=[]) typ name = diff --git a/src/kernel_services/ast_building/cil_builder.mli b/src/kernel_services/ast_building/cil_builder.mli index f6d22d45bc0fb504c4af8fcc0de6aeed0d8cd8eb..11c744096fa2deac101e03321673c94c8102fb49 100644 --- a/src/kernel_services/ast_building/cil_builder.mli +++ b/src/kernel_services/ast_building/cil_builder.mli @@ -229,13 +229,14 @@ sig val stmt : Cil_types.stmt -> unit val stmts : Cil_types.stmt list -> unit val open_function : ?ghost:bool -> string -> [> var] - val open_block : unit -> unit - val open_ghost : unit -> unit - val open_switch : [< exp] -> unit - val open_if : [< exp] -> unit + val open_block : ?into:Cil_types.fundec -> ?ghost:bool -> unit -> unit + val open_ghost : ?into:Cil_types.fundec -> unit -> unit + val open_switch : ?into:Cil_types.fundec -> [< exp] -> unit + val open_if : ?into:Cil_types.fundec -> [< exp] -> unit val open_else : unit -> unit val close : unit -> unit val finish_block : unit -> Cil_types.block + val finish_instr_list : ?scope:Cil_types.block -> unit -> Cil_types.instr list val finish_stmt : unit -> Cil_types.stmt val finish_function : ?register:bool -> unit -> Cil_types.global val case : [< exp] -> unit