diff --git a/Makefile b/Makefile
index 7f7d6c9d99545f4713c0c6040965cdfd3daed406..5b1cb6057283e4c4e9203c1df0dcab604e48bc4f 100644
--- a/Makefile
+++ b/Makefile
@@ -302,6 +302,7 @@ DISTRIB_FILES:=\
       $(wildcard src/kernel_internals/typing/*.ml*)                     \
       $(wildcard src/kernel_services/ast_data/*.ml*)                    \
       $(wildcard src/kernel_services/ast_queries/*.ml*)                 \
+			$(wildcard src/kernel_services/ast_building/*.ml*)                \
       $(wildcard src/kernel_services/ast_printing/*.ml*)                \
       $(wildcard src/kernel_services/cmdline_parameters/*.ml*)          \
       $(wildcard src/kernel_services/analysis/*.ml*)                    \
@@ -627,7 +628,8 @@ KERNEL_CMO=\
 	src/kernel_services/ast_transformations/filter.cmo                          \
 	src/kernel_services/ast_transformations/inline.cmo              \
 	src/kernel_internals/runtime/special_hooks.cmo                  \
-	src/kernel_internals/runtime/messages.cmo
+	src/kernel_internals/runtime/messages.cmo                       \
+	src/kernel_services/ast_building/cil_builder.cmo                       \
 
 CMO	+= $(KERNEL_CMO)
 
diff --git a/headers/header_spec.txt b/headers/header_spec.txt
index a201e0f32e7a5d6c5491bb2f1e97396c84fe0add..afdc2161a96bc21aafe417e4a274eb10f7069b4a 100644
--- a/headers/header_spec.txt
+++ b/headers/header_spec.txt
@@ -493,6 +493,8 @@ src/kernel_services/analysis/undefined_sequence.ml: CEA_LGPL
 src/kernel_services/analysis/undefined_sequence.mli: CEA_LGPL
 src/kernel_services/analysis/wto_statement.ml: CEA_LGPL
 src/kernel_services/analysis/wto_statement.mli: CEA_LGPL
+src/kernel_services/ast_building/cil_builder.ml: CEA_LGPL
+src/kernel_services/ast_building/cil_builder.mli: CEA_LGPL
 src/kernel_services/ast_data/README.md: .ignore
 src/kernel_services/ast_data/alarms.ml: CEA_LGPL
 src/kernel_services/ast_data/alarms.mli: CEA_LGPL
diff --git a/share/Makefile.common b/share/Makefile.common
index affc77563611993266375cc54d2dfdfb7d31ba4e..a8db78b9f90ed31b98f2aaa537f1948fb6768a0e 100644
--- a/share/Makefile.common
+++ b/share/Makefile.common
@@ -43,6 +43,7 @@ FRAMAC_SRC_DIRS= plugins/pdg_types plugins/value_types \
 	       kernel_services/ast_data \
 	       kernel_services/ast_queries \
 	       kernel_services/ast_printing \
+	       kernel_services/ast_building \
 	       kernel_services/cmdline_parameters \
 	       kernel_services/plugin_entry_points \
 	       kernel_services/abstract_interp \
diff --git a/src/kernel_services/ast_building/cil_builder.ml b/src/kernel_services/ast_building/cil_builder.ml
new file mode 100644
index 0000000000000000000000000000000000000000..83db7e89fda810eba0c93f569741232ce0a85416
--- /dev/null
+++ b/src/kernel_services/ast_building/cil_builder.ml
@@ -0,0 +1,631 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2020                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It is distributed in the hope that it will be useful,                 *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
+(*  GNU Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(* --- C & Logic expressions builder --- *)
+
+module Exp =
+struct
+  (*
+    This modules exportes polymorphic variant to simulate subtyping.
+    It uses regular variant internally though, instead of using only the
+    polymorphic variant, as
+    1. it simplifies greatly the .mli since most of the types don't have
+       to be exposed ; it also greatly simplifies mistyping errors for the user
+    2. recursive polymorphic variant do not allow inclusion of one into another
+    3. it is much easier to type the program with regular variants
+  *)
+
+  type const' =
+    | Int of Integer.t
+    | CilConstant of Cil_types.constant
+  and var' =
+    Cil_types.varinfo
+  and lval' =
+    | CilLval of Cil_types.lval
+    | Var of var'
+    | Result
+    | Mem of exp'
+    | Field of lval' * Cil_types.fieldinfo
+    | FieldNamed of lval' * string
+  and exp' =
+    | CilExp of Cil_types.exp
+    | CilExpCopy of Cil_types.exp
+    | CilTerm of Cil_types.term
+    | Lval of lval'
+    | Const of const'
+    | Range of exp' option * exp' option
+    | Unop of Cil_types.unop * exp'
+    | Binop of Cil_types.binop * exp' * exp'
+
+  type const = [ `const of const' ]
+  type var = [ `var of var' ]
+  type lval = [  var | `lval of lval' ]
+  type exp = [ const | lval | `exp of exp' ]
+
+  (* Depolymorphize *)
+
+  let harden_const c =
+    match (c :> const) with
+    | `const const -> const
+
+  let harden_var v =
+    match (v :> var) with
+    | `var var -> var
+
+  let harden_lval lv =
+    match (lv :> lval) with
+    | #var as var -> Var (harden_var var)
+    | `lval lval -> lval
+
+  let harden_lval_opt = function
+    | `none -> None
+    | #lval as lval -> Some (harden_lval lval)
+
+  let harden_exp e =
+    match (e :> exp) with
+    | #const as const -> Const (harden_const const)
+    | #lval as lval -> Lval (harden_lval lval)
+    | `exp exp -> exp
+
+  let harden_exp_opt = function
+    | `none -> None
+    | #exp as exp -> Some (harden_exp exp)
+
+  let harden_exp_list l =
+    List.map harden_exp l
+
+  (* Build *)
+
+  let constant c = `const (CilConstant c)
+  let integer i = `const (Int i)
+  let int i = `const (Int (Integer.of_int i))
+  let zero = int 0
+  let one = int 1
+  let var v = `var v
+  let lval lv = `lval (CilLval lv)
+  let exp e = `exp (CilExp e)
+  let exp_copy e = `exp (CilExpCopy e)
+  let unop op e = `exp (Unop (op, harden_exp e))
+  let neg e = unop Cil_types.Neg e
+  let lognot e = unop Cil_types.LNot e
+  let bwnot e = unop Cil_types.BNot e
+  let binop op e1 e2 = `exp (Binop (op, harden_exp e1, harden_exp e2))
+  let add e1 e2 = binop Cil_types.PlusA e1 e2
+  let sub e1 e2 = binop Cil_types.MinusA e1 e2
+  let mul e1 e2 = binop Cil_types.Mult e1 e2
+  let div e1 e2 = binop Cil_types.Div e1 e2
+  let modulo e1 e2 = binop Cil_types.Mod e1 e2
+  let shiftl e1 e2 = binop Cil_types.Shiftlt e1 e2
+  let shiftr e1 e2 = binop Cil_types.Shiftrt e1 e2
+  let lt e1 e2 = binop Cil_types.Lt e1 e2
+  let gt e1 e2 = binop Cil_types.Gt e1 e2
+  let le e1 e2 = binop Cil_types.Le e1 e2
+  let ge e1 e2 = binop Cil_types.Ge e1 e2
+  let eq e1 e2 = binop Cil_types.Eq e1 e2
+  let ne e1 e2 = binop Cil_types.Ne e1 e2
+  let bwand e1 e2 = binop Cil_types.BAnd e1 e2
+  let bwor e1 e2 = binop Cil_types.BOr e1 e2
+  let bwxor e1 e2 = binop Cil_types.BXor e1 e2
+  let logand e1 e2 = binop Cil_types.LAnd e1 e2
+  let logor e1 e2 = binop Cil_types.LOr e1 e2
+  let mem e = `lval (Mem (harden_exp e))
+  let field lv fi = `lval (Field (harden_lval lv, fi))
+  let fieldnamed lv s = `lval (FieldNamed (harden_lval lv, s))
+  let result = `lval Result
+  let term t = `exp (CilTerm t)
+  let none = `none
+  let range e1 e2 = `exp (Range (harden_exp_opt e1, harden_exp_opt e2))
+
+  exception EmptyList
+
+  let reduce f l =
+    match (l :> exp list) with
+    | [] -> raise EmptyList
+    | h :: t -> List.fold_left f h t
+
+  let logand_list l = reduce logand l
+  let logor_list l = reduce logor l
+
+  let (+), (-), ( * ), (/), (%) = add, sub, mul, div, modulo
+  let (<<), (>>) = shiftl, shiftr
+  let (<), (>), (<=), (>=), (==), (!=) = lt, gt, le, ge, eq, ne
+
+  (* Convert *)
+
+  exception LogicInC
+  exception CInLogic
+  exception Typing_error of string
+
+  let get_fieldinfo typ fieldname =
+    match Cil.unrollType typ with
+    | Cil_types.TComp (compinfo,_,_) ->
+      begin try
+          Cil.getCompField compinfo fieldname
+        with Not_found ->
+          let cname = compinfo.Cil_types.cname in
+          raise (Typing_error ("no field " ^ fieldname ^ " in " ^ cname))
+      end
+    | _ ->
+      raise (Typing_error ("trying to get a field of a non-composite type"))
+
+  let get_fieldinfo_from_ltype ltyp fieldname =
+    match Logic_utils.unroll_type ltyp with
+    | Cil_types.Ctype typ ->
+      get_fieldinfo typ fieldname
+    | _ ->
+      raise (Typing_error ("trying to get a field of a logic type"))
+
+  let rec build_constant = function
+    | CilConstant const -> const
+    | Int i -> Cil_types.(CInt64 (i, IInt, None))
+
+  and build_lval ~loc = function
+    | CilLval lval -> lval
+    | Var v -> Cil_types.(Var v, NoOffset)
+    | Result -> raise LogicInC
+    | Mem e ->
+      Cil.mkMem ~addr:(build_exp ~loc e) ~off:Cil_types.NoOffset
+    | Field (lv,f) ->
+      let host, offset = build_lval ~loc lv in
+      let offset' = Cil.addOffset Cil_types.(Field (f, NoOffset)) in
+      host, offset' offset
+    | FieldNamed (lv,s) ->
+      let (host, offset) as lval = build_lval ~loc lv in
+      let ty = Cil.typeOfLval lval in
+      let f = get_fieldinfo ty s in
+      let offset' = Cil_types.(Field (f, NoOffset)) in
+      host, Cil.addOffset offset' offset
+
+  and build_exp ~loc = function
+    | CilTerm _ | Range _ -> raise LogicInC
+    | CilExp exp -> exp
+    | CilExpCopy exp -> Cil.copy_exp exp
+    | Const c->
+      Cil.new_exp ~loc (Cil_types.Const (build_constant c))
+    | Lval lval ->
+      Cil.new_exp ~loc (Cil_types.Lval (build_lval ~loc lval))
+    | Unop (op,e) ->
+      let e' = build_exp ~loc e in
+      let t = Cil.typeOf e' in
+      let t' = Cil.integralPromotion t in
+      Cil.(new_exp ~loc (Cil_types.UnOp (op, mkCastT e' t t', t')))
+    | Binop (op,e1,e2) ->
+      let e1' = build_exp ~loc e1
+      and e2' = build_exp ~loc e2 in
+      Cil.mkBinOp ~loc op e1' e2'
+
+  let rec build_term_lval ~loc ~restyp = function
+    | CilLval _ -> raise CInLogic
+    | Var v -> Cil_types.(TVar (Cil.cvar_to_lvar v), TNoOffset)
+    | Mem e -> Cil_types.(TMem (build_term ~loc ~restyp e), TNoOffset)
+    | Result -> Cil_types.(TResult restyp, TNoOffset)
+    | Field (lv,f) ->
+      let host, offset = build_term_lval ~loc ~restyp lv in
+      let offset' = Cil_types.(TField (f, TNoOffset)) in
+      host, Logic_const.addTermOffset offset' offset
+    | FieldNamed (lv,s) ->
+      let (host, offset) as tlval = build_term_lval ~loc ~restyp lv in
+      let ty = Cil.typeOfTermLval tlval in
+      let f = get_fieldinfo_from_ltype ty s in
+      let offset' = Cil_types.(TField (f, TNoOffset)) in
+      host, Logic_const.addTermOffset offset' offset
+
+  and build_term ~loc ~restyp = function
+    | Const (CilConstant _) | CilExp _ | CilExpCopy _ -> raise CInLogic
+    | CilTerm term -> term
+    | Const (Int i) ->
+      Logic_const.tint ~loc i
+    | Lval lval ->
+      let tlval = build_term_lval ~loc ~restyp lval in
+      Logic_const.term ~loc Cil_types.(TLval tlval) (Cil.typeOfTermLval tlval)
+    | Unop (op,e) ->
+      let t = build_term e ~loc ~restyp in
+      let ty = t.Cil_types.term_type in
+      (* TODO: type conversion *)
+      Logic_const.term ~loc Cil_types.(TUnOp (op,t)) ty
+    | Binop (op,t1,t2) ->
+      let t1 = build_term ~loc ~restyp t1
+      and t2 = build_term ~loc ~restyp t2 in
+      let ty = t1.Cil_types.term_type in
+      (* TODO: type conversion *)
+      Logic_const.term ~loc Cil_types.(TBinOp (op,t1,t2)) ty
+    | Range (t1,t2) ->
+      let t1' = Extlib.opt_map (build_term ~loc ~restyp) t1
+      and t2' = Extlib.opt_map (build_term ~loc ~restyp) t2 in
+      Logic_const.trange ~loc (t1',t2')
+
+  (* Export *)
+
+  let cil_varinfo v = harden_var v
+  let cil_constant c = build_constant (harden_const c)
+  let cil_lval ~loc lv = build_lval ~loc (harden_lval lv)
+  let cil_lval_opt ~loc lv =
+    Extlib.opt_map (build_lval ~loc) (harden_lval_opt lv)
+  let cil_exp ~loc e = build_exp ~loc (harden_exp e)
+  let cil_exp_opt ~loc e = Extlib.opt_map (build_exp ~loc) (harden_exp_opt e)
+  let cil_exp_list ~loc l = List.map (cil_exp ~loc) l
+  let cil_term_lval ~loc ~restyp lv =
+    build_term_lval ~loc ~restyp (harden_lval lv)
+  let cil_term ~loc ~restyp e = build_term ~loc ~restyp (harden_exp e)
+end
+
+
+(* --- Pure builder --- *)
+
+module Pure =
+struct
+  include Exp
+
+  type instr' =
+    | CilInstr of Cil_types.instr
+    | Skip
+    | Assign of lval' * exp'
+    | Call of lval' option * exp' * exp' list
+
+  type stmt' =
+    | CilStmt of Cil_types.stmt
+    | CilStmtkind of Cil_types.stmtkind
+    | Instr of instr'
+    | Sequence of stmt' list
+
+  type instr = [ `instr of instr' ]
+  type stmt = [ instr | `stmt of stmt' ]
+
+  (* Sequences *)
+
+  let flatten_sequences l =
+    let rec add_one acc = function
+      | Sequence l -> add_list acc l
+      | stmt -> stmt :: acc
+    and add_list acc l =
+      List.fold_left add_one acc l
+    in
+    List.rev (add_list [] l)
+
+  (* Depolymorphize *)
+
+  let harden_instr i =
+    match (i :> instr) with
+    | `instr instr -> instr
+
+  let harden_stmt s =
+    match (s :> stmt) with
+    | #instr as instr -> Instr (harden_instr instr)
+    | `stmt stmt -> stmt
+
+  (* Build *)
+
+  let instr i = `instr (CilInstr i)
+  let skip = `instr Skip
+  let assign dest src = `instr (Assign (harden_lval dest, harden_exp src))
+  let incr dest = `instr (Assign (harden_lval dest, harden_exp (add dest one)))
+  let call res callee args =
+    `instr (Call (harden_lval_opt res, harden_exp callee, harden_exp_list args))
+  let stmtkind sk = `stmt (CilStmtkind sk)
+  let stmt s = `stmt (CilStmt s)
+  let stmts l = `stmt (Sequence (List.map (fun s -> CilStmt s) l))
+  let block l = `stmt (Sequence (List.map harden_stmt l))
+
+  (* Convert *)
+
+  let build_instr ~loc = function
+    | CilInstr i -> i
+    | Skip ->
+      Cil_types.Skip (loc)
+    | Assign (dest,src) ->
+      Cil_types.Set (build_lval ~loc dest, build_exp ~loc src, loc)
+    | Call (dest,callee,args) ->
+      let dest' = Extlib.opt_map (build_lval ~loc) dest
+      and callee' = build_exp ~loc callee
+      and args' = List.map (build_exp ~loc) args in
+      Cil_types.Call (dest', callee', args', loc)
+
+  let rec build_stmtkind ~loc = function
+    | CilStmt s -> s.Cil_types.skind
+    | CilStmtkind sk -> sk
+    | Instr i -> Cil_types.Instr (build_instr ~loc i)
+    | Sequence l -> Cil_types.Block (build_block ~loc l)
+
+  and build_stmt ~loc = function
+    | CilStmt s -> s
+    | stmt -> Cil.mkStmt (build_stmtkind ~loc stmt)
+
+  and build_block ~loc l =
+    let bstmts = List.map (build_stmt ~loc) (flatten_sequences l) in
+    Cil.mkBlock bstmts
+
+  (* Export *)
+
+  let cil_instr ~loc i = build_instr ~loc (harden_instr i)
+  let cil_stmtkind ~loc s = build_stmtkind ~loc (harden_stmt s)
+  let cil_stmt ~loc s = build_stmt ~loc (harden_stmt s)
+end
+
+
+(* --- Stateful builder --- *)
+
+let dkey = Kernel.register_category "cil-builder"
+
+exception WrongContext of string
+
+module type T =
+sig
+  val loc : Cil_types.location
+end
+
+module Stateful (Location : T) =
+struct
+  include Exp
+
+  type block =
+    {
+      block_type: block_type;
+      mutable stmts: Cil_types.stmt list; (* In reverse order *)
+      mutable locals: Cil_types.varinfo list; (* In reverse order *)
+      mutable pending_labels: Cil_types.label list;
+    }
+  and block_type =
+    | Block
+    | IfThen of {ifthen_exp: Cil_types.exp}
+    | IfThenElse of {ifthenelse_exp: Cil_types.exp; then_block: Cil_types.block}
+    | Switch of {switch_exp: Cil_types.exp}
+    | Function of {fundec: Cil_types.fundec}
+
+
+  let loc = Location.loc
+
+  (* State management *)
+
+  let stack : block list ref = ref []
+  let owner: Cil_types.fundec option ref = ref None
+
+  let pretty_stack fmt =
+    let pretty_block fmt b =
+      match b.block_type with
+      | Block -> Format.pp_print_string fmt "block"
+      | IfThen _ -> Format.pp_print_string fmt "if-then"
+      | IfThenElse _ -> Format.pp_print_string fmt "if-then-else"
+      | Switch _ -> Format.pp_print_string fmt "switch"
+      | Function _ -> Format.pp_print_string fmt "function"
+    in
+    Pretty_utils.pp_list ~pre:"[@[" ~sep:";@," ~last:"@]]"
+      pretty_block fmt !stack
+
+  let check_empty () =
+    if !stack <> [] then
+      raise (WrongContext "some contextes have not been closed")
+
+  let check_not_empty () =
+    if !stack = [] then
+      raise (WrongContext "only a finish_* function can close all contextes")
+
+  let top () =
+    match !stack with
+    | [] -> raise (WrongContext "not in an opened context")
+    | state :: _ -> state
+
+  let push state =
+    stack := state :: !stack;
+    Kernel.debug ~dkey "push onto %t" pretty_stack
+
+  let pop () =
+    Kernel.debug ~dkey "pop from %t" pretty_stack;
+    match !stack with
+    | [] -> raise (WrongContext "not in an opened context")
+    | hd :: tail ->
+      stack := tail;
+      hd
+
+  let finish () =
+    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
+
+  (* Block management *)
+
+  let append_stmt b s =
+    if b.pending_labels <> [] then begin
+      s.Cil_types.labels <- List.rev b.pending_labels @ s.Cil_types.labels;
+      b.pending_labels <- [];
+    end;
+    b.stmts <- s :: b.stmts
+
+  (* Conversion to Cil *)
+
+  let build_block b =
+    if b.pending_labels <> [] then begin
+      append_stmt b (Cil.mkEmptyStmt ~loc ())
+    end;
+    let block = Cil.mkBlock (List.rev b.stmts) in
+    block.Cil_types.blocals <- List.rev b.locals;
+    block
+
+  let build_stmtkind b =
+    let block = build_block b in
+    match b.block_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 *)
+
+  let stmt s =
+    let b = top () in
+    append_stmt b s
+
+  let stmts l =
+    let b = top () in
+    List.iter (append_stmt b) l
+
+  let stmtkind sk =
+    stmt (Cil.mkStmt sk)
+
+  let new_block block_type = {
+    block_type;
+    stmts = [];
+    locals = [];
+    pending_labels = [];
+  }
+
+  let open_function name =
+    check_empty ();
+    let fundec = Cil.emptyFunction name in
+    set_owner fundec;
+    push (new_block (Function {fundec}));
+    `var fundec.Cil_types.svar
+
+  let open_block () =
+    push (new_block Block)
+
+  let open_switch exp =
+    let switch_exp = cil_exp ~loc exp in
+    push (new_block (Switch {switch_exp}))
+
+  let open_if exp =
+    let ifthen_exp = cil_exp ~loc exp in
+    push (new_block (IfThen {ifthen_exp}))
+
+  let open_else () =
+    let b = pop () in
+    let ifthenelse_exp = match b.block_type with
+      | IfThen {ifthen_exp} -> ifthen_exp
+      | _ -> raise (WrongContext "not in an opened if-then-else context")
+    in
+    let then_block = build_block b in
+    push (new_block (IfThenElse {ifthenelse_exp; then_block}))
+
+  let close () =
+    let above = pop () in
+    check_not_empty ();
+    stmtkind (build_stmtkind above) (* add the block to the parent *)
+
+  let finish_block () =
+    let b = finish () in
+    match build_stmtkind b with
+    | Cil_types.Block b -> b
+    | _ -> raise (WrongContext "not in an opened simple block context")
+
+  let finish_stmt () =
+    let b = finish () in
+    Cil.mkStmt (build_stmtkind b)
+
+  let finish_function ?(register=true) () =
+    let b = finish () in
+    match b.block_type with
+    | Function {fundec} ->
+      let open Cil_types in
+      fundec.sbody <- build_block b;
+      fundec.svar.vdefined <- true;
+      if register then begin
+        let funspec = Cil.empty_funspec () in
+        Globals.Functions.replace_by_definition funspec fundec loc;
+        let keepSwitch = Kernel.KeepSwitch.get () in
+        Cfg.prepareCFG ~keepSwitch fundec;
+        Cfg.cfgFun fundec;
+      end;
+      reset_owner ();
+      GFun (fundec,loc)
+    | _ -> raise (WrongContext "not in a opened function context")
+
+  let case exp =
+    let b = top () in
+    match b.block_type with
+    | Switch _context ->
+      let label = Cil_types.Case (cil_exp ~loc exp, loc) in
+      b.pending_labels <- label :: b.pending_labels
+    | _ -> raise (WrongContext "no in a opened switch context")
+
+  let break () =
+    stmtkind (Cil_types.Break loc)
+
+  let return exp =
+    stmtkind (Cil_types.Return (cil_exp_opt ~loc exp, loc))
+
+  (* Instructions *)
+
+  let instr i =
+    stmtkind (Cil_types.Instr i)
+
+  let assign lval exp =
+    let lval' = cil_lval ~loc lval
+    and exp' = cil_exp ~loc exp in
+    instr (Cil_types.Set (lval', exp', loc))
+
+  let incr lval =
+    assign lval (add lval (int 1))
+
+  let call dest callee args =
+    let dest' = cil_lval_opt ~loc dest
+    and callee' = cil_exp ~loc callee
+    and args' = cil_exp_list ~loc args in
+    instr (Cil_types.Call (dest', callee', args', loc))
+
+  (* Variables *)
+
+  let return_type typ =
+    let fundec = get_owner () in
+    Cil.setReturnType fundec typ
+
+  let local typ name =
+    let fundec = get_owner () in
+    let v = Cil.makeLocalVar fundec ~insert:false name typ in
+    `var v
+
+  let local_copy ?(suffix="_tmp") (`var vi) =
+    let fundec = get_owner () and b = top () in
+    let v = Cil.copyVarinfo vi (vi.Cil_types.vname ^ suffix) in
+    Cil.refresh_local_name fundec v;
+    fundec.Cil_types.slocals <- fundec.Cil_types.slocals @ [v];
+    b.locals <- v :: b.locals;
+    `var v
+
+  let parameter ?(attributes=[]) typ name =
+    let fundec = get_owner () in
+    let v = Cil.makeFormalVar fundec name typ in
+    v.Cil_types.vattr <- attributes;
+    `var v
+end
diff --git a/src/kernel_services/ast_building/cil_builder.mli b/src/kernel_services/ast_building/cil_builder.mli
new file mode 100644
index 0000000000000000000000000000000000000000..17b07cf2e44a2827b9c3f3ba2c133801a2f27016
--- /dev/null
+++ b/src/kernel_services/ast_building/cil_builder.mli
@@ -0,0 +1,199 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of Frama-C.                                         *)
+(*                                                                        *)
+(*  Copyright (C) 2007-2020                                               *)
+(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
+(*         alternatives)                                                  *)
+(*                                                                        *)
+(*  you can redistribute it and/or modify it under the terms of the GNU   *)
+(*  Lesser General Public License as published by the Free Software       *)
+(*  Foundation, version 2.1.                                              *)
+(*                                                                        *)
+(*  It is distributed in the hope that it will be useful,                 *)
+(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
+(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
+(*  GNU Lesser General Public License for more details.                   *)
+(*                                                                        *)
+(*  See the GNU Lesser General Public License version 2.1                 *)
+(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(*
+- Permet l'utilisation des lval là où il faut des expression (sous typage)
+- Construit de la même manière le C et la logique
+- Pas nécessaire de renseigner la location partout
+- Interface unifiée vers les smart constructors
+*)
+
+
+(* --- C & Logic expressions builder --- *)
+
+module Exp :
+sig
+  type const'
+  type var'
+  type lval'
+  type exp'
+
+  type const = [ `const of const' ]
+  type var = [ `var of var' ]
+  type lval = [  var | `lval of lval' ]
+  type exp = [ const | lval | `exp of exp' ]
+
+  (* Build Constants *)
+
+  val constant : Cil_types.constant -> [> const]
+  val int : int -> [> const]
+  val integer : Integer.t -> [> const]
+  val zero : [> const]
+  val one : [> const]
+
+  (* Build LValues *)
+
+  val var : Cil_types.varinfo -> [> var]
+  val lval : Cil_types.lval -> [> lval]
+
+  (* Build Expressions *)
+
+  val exp : Cil_types.exp -> [> exp]
+  val exp_copy : Cil_types.exp -> [> exp]
+  val unop : Cil_types.unop -> [< exp] -> [> exp]
+  val neg : [< exp] -> [> exp]
+  val lognot : [< exp] -> [> exp]
+  val bwnot : [< exp] -> [> exp]
+  val binop : Cil_types.binop -> [< exp] -> [< exp] -> [> exp]
+  val add : [< exp] -> [< exp] -> [> exp]
+  val sub : [< exp] -> [< exp] -> [> exp]
+  val mul : [< exp] -> [< exp] -> [> exp]
+  val div : [< exp] -> [< exp] -> [> exp]
+  val modulo : [< exp] -> [< exp] -> [> exp]
+  val shiftl : [< exp] -> [< exp] -> [> exp]
+  val shiftr : [< exp] -> [< exp] -> [> exp]
+  val lt : [< exp] -> [< exp] -> [> exp]
+  val gt : [< exp] -> [< exp] -> [> exp]
+  val le : [< exp] -> [< exp] -> [> exp]
+  val ge : [< exp] -> [< exp] -> [> exp]
+  val eq : [< exp] -> [< exp] -> [> exp]
+  val ne : [< exp] -> [< exp] -> [> exp]
+  val logor : [< exp] -> [< exp] -> [> exp]
+  val logand : [< exp] -> [< exp] -> [> exp]
+  val bwand : [< exp] -> [< exp] -> [> exp]
+  val bwor : [< exp] -> [< exp] -> [> exp]
+  val bwxor : [< exp] -> [< exp] -> [> exp]
+  val mem : [< exp] -> [> lval]
+  val field : [< lval] -> Cil_types.fieldinfo -> [> lval]
+  val fieldnamed : [< lval] -> string -> [> lval]
+  val result : [> lval]
+  val term : Cil_types.term -> [> exp]
+  val none : [> `none]
+  val range :  [< exp | `none] -> [< exp | `none] -> [> exp]
+
+  exception EmptyList
+
+  val logor_list : [< exp] list -> exp
+  val logand_list : [< exp] list -> exp
+
+  (* Redefined operators *)
+
+  val (+) : [< exp] -> [< exp] -> [> exp]
+  val (-) : [< exp] -> [< exp] -> [> exp]
+  val ( * ) : [< exp] -> [< exp] -> [> exp]
+  val (/) : [< exp] -> [< exp] -> [> exp]
+  val (%) : [< exp] -> [< exp] -> [> exp]
+  val (<<) : [< exp] -> [< exp] -> [> exp]
+  val (>>) : [< exp] -> [< exp] -> [> exp]
+  val (<) : [< exp] -> [< exp] -> [> exp]
+  val (>) : [< exp] -> [< exp] -> [> exp]
+  val (<=) : [< exp] -> [< exp] -> [> exp]
+  val (>=) : [< exp] -> [< exp] -> [> exp]
+  val (==) : [< exp] -> [< exp] -> [> exp]
+  val (!=) : [< exp] -> [< exp] -> [> exp]
+
+  (* Export CIL objects from built expressions *)
+
+  exception LogicInC
+  exception CInLogic
+  exception Typing_error of string
+
+  val cil_constant : [< const] -> Cil_types.constant
+  val cil_varinfo : [< var] -> Cil_types.varinfo
+  val cil_lval : loc:Cil_types.location -> [< lval] -> Cil_types.lval
+  val cil_exp : loc:Cil_types.location -> [< exp] -> Cil_types.exp
+  val cil_term_lval : loc:Cil_types.location -> restyp:Cil_types.typ ->
+    [< lval] -> Cil_types.term_lval
+  val cil_term : loc:Cil_types.location -> restyp:Cil_types.typ ->
+    [< exp] -> Cil_types.term
+end
+
+
+(* --- Pure builder --- *)
+
+module Pure :
+sig
+  include module type of Exp
+
+  type instr'
+  type stmt'
+
+  type instr = [ `instr of instr' ]
+  type stmt = [ instr | `stmt of stmt' ]
+
+  val instr : Cil_types.instr -> [> instr]
+  val skip : [> instr]
+  val assign : [< lval] -> [< exp] -> [> instr]
+  val incr : [< lval] -> [> instr]
+  val call : [< lval | `none] -> [< exp] -> [< exp] list -> [> instr]
+  val stmtkind : Cil_types.stmtkind -> [> stmt]
+  val stmt : Cil_types.stmt -> [> stmt]
+  val stmts : Cil_types.stmt list -> [> stmt]
+  val block : [< stmt] list -> [> stmt]
+
+  val cil_instr : loc:Cil_types.location -> instr -> Cil_types.instr
+  val cil_stmtkind : loc:Cil_types.location -> stmt -> Cil_types.stmtkind
+  val cil_stmt : loc:Cil_types.location -> stmt -> Cil_types.stmt
+end
+
+
+(* --- Stateful builder --- *)
+
+exception WrongContext of string
+
+module type T =
+sig
+  val loc : Cil_types.location
+end
+
+module Stateful (Location : T) :
+sig
+  include module type of Exp
+
+  (* Statements *)
+  val instr : Cil_types.instr -> unit
+  val stmtkind : Cil_types.stmtkind -> unit
+  val stmt : Cil_types.stmt -> unit
+  val stmts : Cil_types.stmt list -> unit
+  val open_function : string -> [> var]
+  val open_block : unit -> unit
+  val open_switch : [< exp] -> unit
+  val open_if : [< exp] -> unit
+  val open_else : unit -> unit
+  val close : unit -> unit
+  val finish_block : unit -> Cil_types.block
+  val finish_stmt : unit -> Cil_types.stmt
+  val finish_function : ?register:bool -> unit -> Cil_types.global
+  val case : [< exp] -> unit
+  val break : unit -> unit
+  val return : [< exp | `none] -> unit
+  val assign : [< lval] -> [< exp] -> unit
+  val incr : [< lval] -> unit
+  val call : [< lval | `none] -> [< exp] -> [< exp] list -> unit
+
+  (* Variables *)
+  val return_type : Cil_types.typ -> unit
+  val local : Cil_types.typ -> string -> [> var]
+  val local_copy : ?suffix:string -> [< var] -> [> var]
+  val parameter : ?attributes:Cil_types.attributes ->
+    Cil_types.typ -> string -> [> var]
+end