diff --git a/src/plugins/e-acsl/Makefile.in b/src/plugins/e-acsl/Makefile.in
index aed90a086c6ad3694d8b651b1b7c6dcb094c1d74..f7b3af2154a7d982397e655030d199bf8b7251a9 100644
--- a/src/plugins/e-acsl/Makefile.in
+++ b/src/plugins/e-acsl/Makefile.in
@@ -68,6 +68,10 @@ SRC_ANALYSES:= \
 SRC_ANALYSES:=$(addprefix src/analyses/, $(SRC_ANALYSES))
 
 # code generator
+CODE_GENERATOR_CMI:= \
+	contract_types
+CODE_GENERATOR_CMI:=$(addprefix src/code_generator/, $(CODE_GENERATOR_CMI))
+
 SRC_CODE_GENERATOR:= \
 	smart_exp \
 	smart_stmt \
@@ -82,6 +86,7 @@ SRC_CODE_GENERATOR:= \
 	logic_functions \
 	logic_array \
 	translate \
+	contract \
 	temporal \
 	memory_observer \
 	literal_observer \
@@ -112,7 +117,8 @@ PLUGIN_CMO:= src/local_config \
 	$(SRC_ANALYSES) \
 	$(SRC_CODE_GENERATOR) \
 	src/main
-
+PLUGIN_CMI:= \
+	$(CODE_GENERATOR_CMI)
 PLUGIN_HAS_MLI:=yes
 PLUGIN_DISTRIBUTED:=yes
 PLUGIN_DEPENDENCIES:= RteGen
diff --git a/src/plugins/e-acsl/headers/header_spec.txt b/src/plugins/e-acsl/headers/header_spec.txt
index de8c767ec7536bab5ed0794cd0055c093ec1a9b0..ac18901b5347f1d2d5263d35907e13d279a6cb00 100644
--- a/src/plugins/e-acsl/headers/header_spec.txt
+++ b/src/plugins/e-acsl/headers/header_spec.txt
@@ -82,6 +82,9 @@ src/analyses/typing.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/analyses/typing.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/code_generator/at_with_lscope.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/code_generator/at_with_lscope.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL
+src/code_generator/contract.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
+src/code_generator/contract.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL
+src/code_generator/contract_types.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/code_generator/env.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/code_generator/env.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/code_generator/global_observer.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
diff --git a/src/plugins/e-acsl/src/code_generator/contract.ml b/src/plugins/e-acsl/src/code_generator/contract.ml
new file mode 100644
index 0000000000000000000000000000000000000000..7a8291e0b66e658b7660e7feb38e681c89c084fb
--- /dev/null
+++ b/src/plugins/e-acsl/src/code_generator/contract.ml
@@ -0,0 +1,753 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of the Frama-C's E-ACSL plug-in.                    *)
+(*                                                                        *)
+(*  Copyright (C) 2012-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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+open Cil_types
+open Contract_types
+
+(**************************************************************************)
+(********************** Forward references ********************************)
+(**************************************************************************)
+
+let must_translate_ppt_ref : (Property.t -> bool) ref =
+  Extlib.mk_fun "must_translate_ppt_ref"
+
+let must_translate_ppt_opt_ref : (Property.t option -> bool) ref =
+  Extlib.mk_fun "must_translate_ppt_opt_ref"
+
+(**************************************************************************)
+(********************** Contract ********************************)
+(**************************************************************************)
+
+type t = contract
+
+(** Module to ease the access to the C API for contracts *)
+module Rtl_call: sig
+  val init:
+    loc:location -> result_name:string -> Env.t -> kernel_function -> int ->
+    varinfo * exp * Env.t
+  (** Call the C function [__e_acsl_contract_init] *)
+
+  val cleanup:
+    loc:location -> Env.t -> kernel_function -> exp -> Env.t
+  (** Call the C function [__e_acsl_contract_cleanup] *)
+
+  val set_assumes:
+    loc:location -> Env.t -> kernel_function -> exp -> int -> predicate ->
+    Env.t
+  (** Call the C function [__e_acsl_contract_set_behavior_assumes] *)
+
+  val get_assumes:
+    loc:location -> result:varinfo -> Env.t -> kernel_function -> exp -> int ->
+    Env.t
+  (** Call the C function [__e_acsl_contract_get_behavior_assumes] *)
+
+  val partial_count_behaviors:
+    loc:location -> result:varinfo -> Env.t -> kernel_function -> exp ->
+    int list -> Env.t
+  (** Call the C function [__e_acsl_contract_partial_count_behaviors] *)
+
+  val partial_count_all_behaviors:
+    loc:location -> result:varinfo -> Env.t -> kernel_function -> exp -> Env.t
+    (** Call the C function [__e_acsl_contract_partial_count_all_behaviors] *)
+
+end = struct
+  let init_function_name = "contract_init"
+
+  let init_kf_lazy =
+    lazy
+      (Globals.Functions.find_by_name
+         (Functions.RTL.mk_api_name init_function_name))
+
+  let ctyp_lazy =
+    lazy
+      (Globals.Types.find_type
+         Logic_typing.Typedef (Functions.RTL.mk_api_name "contract_t"))
+
+  let init ~loc ~result_name env kf count =
+    (* Tell Eva to use init as a builtin *)
+    let init_kf = Lazy.force init_kf_lazy in
+    Dep_eva.use_builtin init_kf "Frama_C_malloc";
+    (* Add a call to init in the environment *)
+    let ty = TPtr(Lazy.force ctyp_lazy, []) in
+    Env.new_var
+      ~loc
+      ~name:result_name
+      ~scope:Varname.Function
+      env
+      kf
+      None
+      ty
+      (fun vi _e ->
+         let result = Cil.var vi in
+         let count_e = Cil.integer ~loc count in
+         [ Smart_stmt.rtl_call
+             ~loc
+             ~result
+             init_function_name
+             [count_e] ])
+
+  let cleanup ~loc env kf contract =
+    Env.add_stmt
+      env
+      kf
+      (Smart_stmt.rtl_call
+         ~loc
+         "contract_clean"
+         [contract])
+
+  let set_assumes ~loc env kf contract idx assumes =
+    let idx_e = Cil.integer ~loc idx in
+    let assumes_e, env =
+      Translate.generalized_untyped_predicate_to_exp kf env assumes
+    in
+    Env.add_stmt
+      env
+      kf
+      (Smart_stmt.rtl_call
+         ~loc
+         "contract_set_behavior_assumes"
+         [contract; idx_e; assumes_e])
+
+  let get_assumes ~loc ~result env kf contract idx =
+    let idx_e = Cil.integer ~loc idx in
+    let result = Cil.var result in
+    Env.add_stmt
+      env
+      kf
+      (Smart_stmt.rtl_call
+         ~loc
+         ~result
+         "contract_get_behavior_assumes"
+         [contract; idx_e])
+
+  let partial_count_behaviors ~loc ~result env kf contract idxes =
+    let idxes, count =
+      List.fold_right
+        (fun idx (idxes, count) ->
+           Cil.integer ~loc idx :: idxes, count + 1)
+        idxes
+        ([], 0)
+    in
+    let result = Cil.var result in
+    Env.add_stmt
+      env
+      kf
+      (Smart_stmt.rtl_call
+         ~loc
+         ~result
+         "contract_partial_count_behaviors"
+         (contract :: Cil.integer ~loc count :: idxes))
+
+  let partial_count_all_behaviors ~loc ~result env kf contract =
+    let result = Cil.var result in
+    Env.add_stmt
+      env
+      kf
+      (Smart_stmt.rtl_call
+         ~loc
+         ~result
+         "contract_partial_count_all_behaviors"
+         [ contract ])
+end
+
+(** Convert the given assumes clauses list to a single [predicate] *)
+let assumes_predicate assumes =
+  List.fold_left
+    (fun acc p ->
+       let pred = p.ip_content.tp_statement in
+       let loc = pred.pred_loc in
+       Logic_const.pand ~loc
+         (acc,
+          Logic_const.unamed ~loc pred.pred_content))
+    Logic_const.ptrue
+    assumes
+
+(** Create a [predicate] from the requires [identified_predicate] *)
+let requires_predicate requires =
+  let pred = requires.ip_content.tp_statement in
+  let loc = pred.pred_loc in
+  let p = Logic_const.unamed ~loc pred.pred_content
+  in
+  p
+
+(** Create a [predicate] from the ensures [identified_predicate] *)
+let ensures_predicate ensures =
+  let pred = ensures.ip_content.tp_statement in
+  let loc = pred.pred_loc in
+  let p = Logic_const.unamed ~loc pred.pred_content
+  in
+  p
+
+let create ~loc spec =
+  (* Create a hashtable to associate a behavior name with an index *)
+  let name_to_idx_tbl = Hashtbl.create 7 in
+  let named_behaviors_count =
+    List.fold_left
+      (fun idx b ->
+         if Cil.is_default_behavior b then
+           idx
+         else begin
+           Hashtbl.add name_to_idx_tbl b.b_name idx;
+           idx + 1
+         end
+      )
+      0
+      spec.spec_behavior
+  in
+  let var = None in
+  (* Create the contract *)
+  { location = loc;
+    named_behaviors_count;
+    name_to_idx_tbl;
+    var;
+    all_assumes_translated = true;
+    spec }
+
+(** Initialize the C API for the given contract *)
+let init kf env contract =
+  if contract.named_behaviors_count > 0 then
+    let loc = contract.location in
+    let contract_vi, contract_e, env =
+      Rtl_call.init
+        ~loc
+        ~result_name:"contract"
+        env
+        kf
+        contract.named_behaviors_count
+    in
+    contract.var <- Some (contract_vi, contract_e);
+    env
+  else env
+
+(** Cleanup the C API for the given contract *)
+let cleanup kf env contract =
+  match contract.var with
+  | None -> env
+  | Some (_, e) ->
+    let loc = contract.location in
+    Rtl_call.cleanup ~loc env kf e
+
+(** Retrieve the behavior index from its name for the given contract *)
+let get_bhvr_idx contract bhvr_name =
+  (* by construction, the behavior name is in the hashtable *)
+  try Hashtbl.find contract.name_to_idx_tbl bhvr_name
+  with _ -> assert false
+
+(** Retrieve the C variable with the contract structure for the given contract.
+    Assumes that there is such a variable. *)
+let get_contract_var contract =
+  match contract.var with
+  | Some (contract_vi, contract_e) -> contract_vi, contract_e
+  | None ->
+    Options.fatal
+      "Unexpected call to get_contract_var with a contract without named \
+       behaviors"
+
+(** Setup the assumes values for the C API *)
+let setup_assumes kf env contract =
+  match contract.var with
+  | None -> env
+  | Some (_, contract_e) ->
+    let do_fold env b =
+      let do_it env =
+        try
+          if Cil.is_default_behavior b then
+            env
+          else
+            let assumes = assumes_predicate b.b_assumes in
+            let loc = assumes.pred_loc in
+            Cil.CurrentLoc.set loc;
+            let idx = get_bhvr_idx contract b.b_name in
+            Rtl_call.set_assumes ~loc env kf contract_e idx assumes
+        with exn ->
+          (* Unable to translate the assumes clause. Save that fact and re-raise
+             the exception *)
+          contract.all_assumes_translated <- false;
+          raise exn
+      in
+      Env.handle_error do_it env
+    in
+    List.fold_left do_fold env contract.spec.spec_behavior
+
+(** Returns a closure that will (1) creates a local C variable when first
+    called and (2) returns said variable on subsequent calls. *)
+let mk_get_or_create_var kf typ var_name =
+  let var_ref = ref None in
+  let f ~loc env =
+    match !var_ref with
+    | None ->
+      let vi, e, env =
+        Env.new_var
+          ~loc
+          ~scope:Varname.Block
+          ~name:var_name
+          env
+          kf
+          None
+          typ
+          (fun _ _ -> [])
+      in
+      var_ref := Some (vi, e);
+      vi, e, env
+    | Some (vi, e) -> vi, e, env
+  in
+  f
+
+(** Drop-in replacement for [List.fold_left] with the folding function wrapped
+    in a [handle_error] call *)
+let fold_left_handle_error f env l =
+  (* Reverse input args of f *)
+  let f2 x env = f env x in
+  (* Call fold_left on the list with handle_error at each element *)
+  List.fold_left
+    (fun env x ->
+       Env.handle_error (f2 x) env)
+    env
+    l
+
+(** Drop-in replacement for [List.fold_left] when the accumulator is more than
+    the [env], with the folding function wrapped in a [handle_error] call.
+
+    The accumulator for the fold should be set up with a pair where the first
+    element is the environment and the second element the rest of the
+    accumulator. *)
+let fold_left_handle_error_with_args f (env, acc) l =
+  let f2 x (env, args) = f (env, args) x in
+  List.fold_left
+    (fun (env, args) x ->
+       Env.handle_error_with_args (f2 x) (env, args))
+    (env, acc)
+    l
+
+(** Insert requires check for the given contract in the environment *)
+let check_requires kf kinstr env contract =
+  let get_or_create_assumes_var =
+    mk_get_or_create_var kf Cil.intType "assumes_value"
+  in
+  let do_behavior env b =
+    if Cil.is_default_behavior b then
+      fold_left_handle_error
+        (fun env requires ->
+           if !must_translate_ppt_ref
+               (Property.ip_of_requires kf kinstr b requires) then
+             (* If translating the default behavior, directly translate the
+                predicate *)
+             let requires = requires_predicate requires in
+             let loc = requires.pred_loc in
+             Cil.CurrentLoc.set loc;
+             Translate.translate_predicate kf env requires
+           else
+             env)
+        env
+        b.b_requires
+    else
+      (* Compute the assumes predicate for pretty-printing *)
+      let assumes = assumes_predicate b.b_assumes in
+      (* Push a new env and check the requires of the behavior *)
+      let env = Env.push env in
+      let env, stmts =
+        fold_left_handle_error_with_args
+          (fun (env, stmts) requires ->
+             if !must_translate_ppt_ref
+                 (Property.ip_of_requires kf kinstr b requires) then
+               let requires = requires_predicate requires in
+               let loc = requires.pred_loc in
+               Cil.CurrentLoc.set loc;
+               (* Prepend the name of the behavior *)
+               let requires =
+                 { requires with pred_name = b.b_name :: requires.pred_name }
+               in
+               (* Create runtime check *)
+               let requires_e, env =
+                 Translate.generalized_untyped_predicate_to_exp kf env requires
+               in
+               let stmt =
+                 Smart_stmt.runtime_check
+                   Smart_stmt.Precondition
+                   kf
+                   requires_e
+                   requires
+               in
+               env, stmt :: stmts
+             else
+               env, stmts)
+          (env, [])
+          b.b_requires
+      in
+      let requires = Smart_stmt.block_from_stmts stmts in
+      (* Pop the env to build the requires check *)
+      let requires_blk, env =
+        Env.pop_and_get
+          env
+          requires
+          ~global_clear:false
+          Env.Middle
+      in
+      match stmts with
+      | [] ->
+        (* If no requires check have been generated, then return immediately *)
+        env
+      | _ :: _ ->
+        (* Generate a predicate that will retrieve and test the
+           already computed assumes value for the behavior *)
+        let loc = assumes.pred_loc in
+        Cil.CurrentLoc.set loc;
+        let assumes_vi, assumes_e, env =
+          get_or_create_assumes_var ~loc env
+        in
+        let _, contract_e = get_contract_var contract in
+        let idx = get_bhvr_idx contract b.b_name in
+        let env =
+          Rtl_call.get_assumes
+            ~loc
+            ~result:assumes_vi
+            env
+            kf
+            contract_e
+            idx
+        in
+        let stmt = Smart_stmt.if_stmt ~loc ~cond:assumes_e requires_blk in
+        Env.add_stmt env kf stmt
+  in
+  List.fold_left
+    do_behavior
+    env
+    contract.spec.spec_behavior
+
+type translate_ppt =
+  | Complete
+  | Disjoint
+  | Both
+
+(** For each set of behavior names in [clauses], [check_active_behaviors] counts
+    the number of active behaviors and creates assertions for the
+    [ppt_to_translate]. *)
+let check_active_behaviors ~ppt_to_translate ~get_or_create_var kf kinstr env contract clauses =
+  let must_translate = !must_translate_ppt_ref in
+  let loc = contract.location in
+  Cil.CurrentLoc.set loc;
+  let do_clause env bhvrs =
+    let bhvrs_list = Datatype.String.Set.elements bhvrs in
+    let active = [] in (* TODO: 'for' behaviors, e-acsl#109 *)
+    let must_translate_complete =
+      match ppt_to_translate with
+      | Both | Complete ->
+        must_translate (Property.ip_of_complete kf kinstr ~active bhvrs_list)
+      | Disjoint -> false
+    in
+    let must_translate_disjoint =
+      match ppt_to_translate with
+      | Both | Disjoint ->
+        must_translate (Property.ip_of_disjoint kf kinstr ~active bhvrs_list)
+      | Complete -> false
+    in
+
+    if must_translate_complete || must_translate_disjoint then
+      (* Retrieve the number of active behaviors *)
+      let active_bhvrs_e, complete_msg, disjoint_msg, env =
+        let _, contract_e = get_contract_var contract in
+        let vi, e, env = get_or_create_var ~loc env in
+        let clause_card = Datatype.String.Set.cardinal bhvrs in
+        let env, complete_msg, disjoint_msg =
+          if Datatype.Int.equal clause_card contract.named_behaviors_count then
+            let env =
+              Rtl_call.partial_count_all_behaviors
+                ~loc
+                ~result:vi
+                env
+                kf
+                contract_e
+            in
+            let complete_msg = "all behaviors complete" in
+            let disjoint_msg = "all behaviors disjoint" in
+            env, complete_msg, disjoint_msg
+          else
+            let args, bhvrs_names =
+              Datatype.String.Set.fold
+                (fun bhvr_name (args, bhvrs_names) ->
+                   let args = get_bhvr_idx contract bhvr_name :: args in
+                   let bhvrs_names = bhvr_name :: bhvrs_names in
+                   args, bhvrs_names)
+                bhvrs
+                ([], [])
+            in
+            let env =
+              Rtl_call.partial_count_behaviors
+                ~loc
+                ~result:vi
+                env
+                kf
+                contract_e
+                args
+            in
+            let bhvrs_names = String.concat ", " bhvrs_names in
+            let complete_msg =
+              Format.sprintf "complete behaviors %s" bhvrs_names
+            in
+            let disjoint_msg =
+              Format.sprintf "disjoint behaviors %s" bhvrs_names
+            in
+            env, complete_msg, disjoint_msg
+        in
+        e, complete_msg, disjoint_msg, env
+      in
+
+      (* Create assertions for complete and disjoint behaviors checks *)
+      let create_assert_stmt bop msg =
+        Smart_stmt.runtime_check_with_msg
+          ~loc
+          msg
+          (Env.annotation_kind env)
+          kf
+          (Cil.mkBinOp ~loc bop active_bhvrs_e (Cil.one ~loc))
+      in
+      let assert_complete_stmt = create_assert_stmt Ge complete_msg in
+      let assert_disjoint_stmt = create_assert_stmt Le disjoint_msg in
+
+      if must_translate_complete && must_translate_disjoint then
+        (* Build an enclosing [if] if both complete and disjoint must be checked
+           for the given clause *)
+        Env.add_stmt
+          env
+          kf
+          (Smart_stmt.if_stmt
+             ~loc
+             ~cond:(Cil.mkBinOp ~loc Ne active_bhvrs_e (Cil.one ~loc))
+             (Cil.mkBlock [ assert_complete_stmt; assert_disjoint_stmt ]))
+          (* Otherwise just get the corresponding assertion *)
+      else if must_translate_complete then
+        Env.add_stmt env kf assert_complete_stmt
+      else if must_translate_disjoint then
+        Env.add_stmt env kf assert_disjoint_stmt
+      else
+        (* By construction, at least either [must_translate_complete] or
+           [must_translate_disjoint] is true *)
+        assert false
+    else
+      (* Nothing to translate *)
+      env
+  in
+  fold_left_handle_error do_clause env clauses
+
+(** Insert complete and disjoint behaviors check for the given contract in the
+    environement *)
+let check_complete_and_disjoint kf kinstr env contract =
+  (* Only translate the complete and disjoint clauses if all the assumes clauses
+     could be translated *)
+  if contract.all_assumes_translated then
+    (* Partition the complete and disjoint clauses of the contract into 3 lists:
+       - The complete and disjoint list
+       - The complete list
+       - The disjoint list
+
+       The behaviors of a clause are stored in a Set so that they are
+       automatically sorted, the duplicates are removed, and they can be compared
+       for equality.
+    *)
+    let completes =
+      List.map
+        Datatype.String.Set.of_list
+        contract.spec.spec_complete_behaviors
+    in
+    let completes_and_disjoints, completes, disjoints =
+      List.fold_left
+        (fun (completes_and_disjoints, completes, disjoints) clause ->
+           let clause = Datatype.String.Set.of_list clause in
+           if List.mem clause completes then
+             let completes_and_disjoints = clause :: completes_and_disjoints in
+             let completes =
+               List.filter
+                 (fun c -> not (Datatype.String.Set.equal clause c))
+                 completes
+             in
+             completes_and_disjoints, completes, disjoints
+           else
+             let disjoints = clause :: disjoints in
+             completes_and_disjoints, completes, disjoints
+        )
+        ([], completes, [])
+        contract.spec.spec_disjoint_behaviors
+    in
+    (* Create a common variable to hold the number of active behavior for the
+       current check *)
+    let get_or_create_var = mk_get_or_create_var kf Cil.intType "active_bhvrs" in
+    (* Check the complete and disjoint clauses *)
+    let check_bhvrs env ppt_to_translate bhvrs =
+      check_active_behaviors
+        ~ppt_to_translate
+        ~get_or_create_var
+        kf
+        kinstr
+        env
+        contract
+        bhvrs
+    in
+    let env = check_bhvrs env Both completes_and_disjoints in
+    let env = check_bhvrs env Complete completes in
+    let env = check_bhvrs env Disjoint disjoints in
+    env
+  else begin
+    Cil.CurrentLoc.set contract.location;
+    Options.warning
+      ~current:true
+      "@[Some assumes clauses couldn't be translated.@ Ignoring complete and \
+       disjoint behaviors annotations.@]";
+    env
+  end
+
+(** Insert ensures check for the given contract in the environement *)
+let check_post_conds kf kinstr env contract =
+  let get_or_create_assumes_var =
+    mk_get_or_create_var kf Cil.intType "assumes_value"
+  in
+  let do_behavior env b =
+    let env =
+      Env.handle_error
+        (fun env ->
+           let active = [] in (* TODO: 'for' behaviors, e-acsl#109 *)
+           let ppt = Property.ip_assigns_of_behavior kf kinstr ~active b in
+           if b.b_assigns <> WritesAny && !must_translate_ppt_opt_ref ppt
+           then Env.not_yet env "assigns clause in behavior";
+           (* ignore b.b_extended since we never translate them *)
+           env)
+        env
+    in
+    if Cil.is_default_behavior b then
+      fold_left_handle_error
+        (fun env ((termination, post_cond) as tp) ->
+           if !must_translate_ppt_ref
+               (Property.ip_of_ensures kf kinstr b tp) then
+             let post_cond = ensures_predicate post_cond in
+             let loc = post_cond.pred_loc in
+             Cil.CurrentLoc.set loc;
+             match termination with
+             | Normal ->
+               (* If translating the default behavior, directly translate the
+                  predicate *)
+               Translate.translate_predicate kf env post_cond
+             | Exits | Breaks | Continues | Returns ->
+               Error.process_error
+                 (Error.not_yet "abnormal termination case in behavior");
+               env
+           else
+             env)
+        env
+        b.b_post_cond
+    else
+      (* Compute the assumes predicate for pretty printing *)
+      let assumes = assumes_predicate b.b_assumes in
+      (* Push a new env and check the ensures of the behavior *)
+      let env = Env.push env in
+      let env, stmts =
+        fold_left_handle_error_with_args
+          (fun (env, stmts) ((termination, post_cond) as tp) ->
+             if !must_translate_ppt_ref
+                 (Property.ip_of_ensures kf kinstr b tp) then
+               let post_cond = ensures_predicate post_cond in
+               let loc = post_cond.pred_loc in
+               Cil.CurrentLoc.set loc;
+               match termination with
+               | Normal ->
+                 (* Prepend the name of the behavior *)
+                 let post_cond =
+                   { post_cond with pred_name = b.b_name :: post_cond.pred_name }
+                 in
+                 (* Create runtime check *)
+                 let post_cond_e, env =
+                   Translate.generalized_untyped_predicate_to_exp kf env post_cond
+                 in
+                 let stmt =
+                   Smart_stmt.runtime_check
+                     Smart_stmt.Postcondition
+                     kf
+                     post_cond_e
+                     post_cond
+                 in
+                 env, stmt :: stmts
+               | Exits | Breaks | Continues | Returns ->
+                 Error.process_error (Error.not_yet "abnormal termination case in behavior");
+                 env, stmts
+             else
+               env, stmts)
+          (env, [])
+          b.b_post_cond
+      in
+      let post_cond = Smart_stmt.block_from_stmts stmts in
+      (* Pop the env to build the post_cond check *)
+      let post_cond_blk, env =
+        Env.pop_and_get
+          env
+          post_cond
+          ~global_clear:false
+          Env.Middle
+      in
+      match stmts with
+      | [] ->
+        (* If no post_cond check have been generated, then return immediately *)
+        env
+      | _ :: _ ->
+        (* Generate a predicate that retrieves and tests the already
+           computed assumes value for the behavior *)
+        let loc = assumes.pred_loc in
+        let assumes_vi, assumes_e, env =
+          get_or_create_assumes_var ~loc env
+        in
+        let _, contract_e = get_contract_var contract in
+        let idx = get_bhvr_idx contract b.b_name in
+        let env =
+          Rtl_call.get_assumes
+            ~loc
+            ~result:assumes_vi
+            env
+            kf
+            contract_e
+            idx
+        in
+        let stmt = Smart_stmt.if_stmt ~loc ~cond:assumes_e post_cond_blk in
+        Env.add_stmt env kf stmt
+  in
+  List.fold_left
+    do_behavior
+    env
+    contract.spec.spec_behavior
+
+let translate_preconditions kf kinstr env contract =
+  let env = Env.set_annotation_kind env Smart_stmt.Precondition in
+  let env = Env.push_contract env contract in
+  let env = init kf env contract in
+  let env = setup_assumes kf env contract in
+  let do_it env =
+    let env = check_requires kf kinstr env contract in
+    let env = check_complete_and_disjoint kf kinstr env contract in
+    env
+  in
+  Env.handle_error do_it env
+
+let translate_postconditions kf kinstr env =
+  let env = Env.set_annotation_kind env Smart_stmt.Postcondition in
+  let contract, env = Env.pop_and_get_contract env in
+  let do_it env =
+    let env = check_post_conds kf kinstr env contract in
+    env
+  in
+  let env = Env.handle_error do_it env in
+  cleanup kf env contract
diff --git a/src/plugins/e-acsl/src/code_generator/contract.mli b/src/plugins/e-acsl/src/code_generator/contract.mli
new file mode 100644
index 0000000000000000000000000000000000000000..0b7732602334736cc9d258c4867bd6b57e028f66
--- /dev/null
+++ b/src/plugins/e-acsl/src/code_generator/contract.mli
@@ -0,0 +1,47 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of the Frama-C's E-ACSL plug-in.                    *)
+(*                                                                        *)
+(*  Copyright (C) 2012-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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+open Cil_types
+open Contract_types
+
+(** Translate a given ACSL contract (function or statement) into the
+    corresponding C statement for runtime assertion checking. *)
+
+type t = contract
+
+val create: loc:location -> spec -> t
+(** Create a contract from a [spec] object (either function spec or statement
+    spec) *)
+
+val translate_preconditions: kernel_function -> kinstr -> Env.t -> t -> Env.t
+(** Translate the preconditions of the given contract into the environement *)
+
+val translate_postconditions: kernel_function -> kinstr -> Env.t -> Env.t
+(** Translate the postconditions of the given contract into the environment *)
+
+(**************************************************************************)
+(********************** Forward references ********************************)
+(**************************************************************************)
+
+val must_translate_ppt_ref: (Property.t -> bool) ref
+
+val must_translate_ppt_opt_ref: (Property.t option -> bool) ref
diff --git a/src/plugins/e-acsl/src/code_generator/contract_types.mli b/src/plugins/e-acsl/src/code_generator/contract_types.mli
new file mode 100644
index 0000000000000000000000000000000000000000..adef414cc84636870d1c2d5167cf48384e6958e5
--- /dev/null
+++ b/src/plugins/e-acsl/src/code_generator/contract_types.mli
@@ -0,0 +1,51 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  This file is part of the Frama-C's E-ACSL plug-in.                    *)
+(*                                                                        *)
+(*  Copyright (C) 2012-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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+open Cil_types
+
+(** Represent a function or statement contract. *)
+type contract = {
+  location: location;
+  (** Location of the function or statement attached to the contract. *)
+
+  named_behaviors_count: int;
+  (** Number of named behaviors in the contract
+      (excluding the default behavior) *)
+
+  name_to_idx_tbl: (string, int) Hashtbl.t;
+  (** Hashtable associating the name of a behavior with its index in the C API
+      structure used to store behaviors information at runtime. *)
+
+  mutable var: (varinfo * exp) option;
+  (** Elements to access the C API structure used to store contracts
+      information at runtime. *)
+
+  mutable all_assumes_translated: bool;
+  (** True if all the assumes clauses of the contract could be translated, false
+      otherwise.
+
+      If even one assume clause can't be translated, then the complete and
+      disjoint clauses can't be computed. *)
+
+  spec: spec
+  (** Specification for the contract *)
+}
diff --git a/src/plugins/e-acsl/src/code_generator/env.ml b/src/plugins/e-acsl/src/code_generator/env.ml
index 5466f4cc98c85758ad4fc64e6091625ffc7e6097..595dc566e1e836413c056e3c2c462ff3fedcf11a 100644
--- a/src/plugins/e-acsl/src/code_generator/env.ml
+++ b/src/plugins/e-acsl/src/code_generator/env.ml
@@ -23,6 +23,7 @@
 module E_acsl_label = Label
 open Cil_types
 open Cil_datatype
+open Contract_types
 
 type localized_scope =
   | LGlobal
@@ -62,6 +63,8 @@ type t = {
      should be added. *)
   global_mp_tbl: mp_tbl;
   env_stack: local_env list;
+  contract_stack: contract list;
+  (* Stack of contracts for active functions and statements *)
   var_mapping: Varinfo.t Stack.t Logic_var.Map.t;
   (* records of C bindings for logic vars *)
   loop_invariants: predicate list list;
@@ -92,6 +95,7 @@ let empty =
     new_global_vars = [];
     global_mp_tbl = empty_mp_tbl;
     env_stack = [];
+    contract_stack = [];
     var_mapping = Logic_var.Map.empty;
     loop_invariants = [];
     cpt = 0 }
@@ -508,6 +512,23 @@ let untypable env s =
   Context.save env;
   Error.untypable s
 
+let push_contract env contract =
+  { env with contract_stack = contract :: env.contract_stack }
+
+let top_contract env =
+  match env.contract_stack with
+  | [] -> Options.fatal "Contract list is empty in env. That is unexpected"
+  | hd :: tl -> hd, tl
+
+let pop_and_get_contract env =
+  let hd, tl = top_contract env in
+  hd, { env with contract_stack = tl }
+
+let pop_contract env =
+  let _, env = pop_and_get_contract env in
+  env
+
+
 (* debugging purpose *)
 let pretty fmt env =
   let local_env, _ = top env in
diff --git a/src/plugins/e-acsl/src/code_generator/env.mli b/src/plugins/e-acsl/src/code_generator/env.mli
index 065d3babd2b2ec1c93d9d6661ba6eb7408b264ff..3a5aebf2f5d4f1a0ea67af77099032535365f8e7 100644
--- a/src/plugins/e-acsl/src/code_generator/env.mli
+++ b/src/plugins/e-acsl/src/code_generator/env.mli
@@ -21,6 +21,7 @@
 (**************************************************************************)
 
 open Cil_types
+open Contract_types
 
 (** Environments.
 
@@ -192,6 +193,19 @@ val not_yet: t -> string -> 'a
 val untypable: t -> string -> 'a
 (** Save the current context and raise [Error.Typing_error] exception. *)
 
+(* ************************************************************************** *)
+(** {2 Contracts} *)
+(* ************************************************************************** *)
+
+val push_contract: t -> contract -> t
+(** Push a contract to the environment's stack *)
+val top_contract: t -> contract * contract list
+(** Return the top contract of the environment's stack *)
+val pop_and_get_contract: t -> contract * t
+(** Pop and return the top contract of the environment's stack *)
+val pop_contract: t -> t
+(** Pop the top contract of the environment's stack *)
+
 val pretty: Format.formatter -> t -> unit
 
 (*