diff --git a/src/plugins/e-acsl/Makefile.in b/src/plugins/e-acsl/Makefile.in
index cdf795b172ca4a20b047f8b8e7ffaf7abed40ceb..83c4a7647cb171e1138b9eadb3212f9056058ab9 100644
--- a/src/plugins/e-acsl/Makefile.in
+++ b/src/plugins/e-acsl/Makefile.in
@@ -83,11 +83,12 @@ SRC_CODE_GENERATOR:= \
 	label \
 	env \
 	rational \
+	typed_number \
+	logic_functions \
 	loops \
 	quantif \
 	at_with_lscope \
 	memory_translate \
-	logic_functions \
 	logic_array \
 	translate \
 	contract \
diff --git a/src/plugins/e-acsl/headers/header_spec.txt b/src/plugins/e-acsl/headers/header_spec.txt
index b617a2a25a6db53ae67acc05e0627d8041b58505..82e0dc5a87c8525b82c160f0d198bed05dbead73 100644
--- a/src/plugins/e-acsl/headers/header_spec.txt
+++ b/src/plugins/e-acsl/headers/header_spec.txt
@@ -122,6 +122,8 @@ src/code_generator/translate.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/code_generator/translate.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/code_generator/translate_annots.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/code_generator/translate_annots.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL
+src/code_generator/typed_number.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
+src/code_generator/typed_number.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/dependencies/dep_eva.mli: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/dependencies/dep_eva.enabled.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 src/dependencies/dep_eva.disabled.ml: CEA_LGPL_OR_PROPRIETARY.E_ACSL
diff --git a/src/plugins/e-acsl/src/code_generator/gmp.ml b/src/plugins/e-acsl/src/code_generator/gmp.ml
index cfc504740298f8517998be505a7512b21b9e50a4..ce2757719cbb4693ca98c49c0160925e35b0fd99 100644
--- a/src/plugins/e-acsl/src/code_generator/gmp.ml
+++ b/src/plugins/e-acsl/src/code_generator/gmp.ml
@@ -35,6 +35,23 @@ let apply_on_var ~loc funname e =
   in
   Smart_stmt.rtl_call ~loc ~prefix funname [ e ]
 
+let name_of_mpz_arith_bop = function
+  | PlusA -> "__gmpz_add"
+  | MinusA -> "__gmpz_sub"
+  | Mult -> "__gmpz_mul"
+  | Div -> "__gmpz_tdiv_q"
+  | Mod -> "__gmpz_tdiv_r"
+  | BAnd -> "__gmpz_and"
+  | BOr -> "__gmpz_ior"
+  | BXor -> "__gmpz_xor"
+  | Shiftlt -> "__gmpz_mul_2exp"
+  | Shiftrt -> "__gmpz_tdiv_q_2exp"
+  | Lt | Gt | Le | Ge | Eq | Ne | LAnd | LOr | PlusPI | IndexPI | MinusPI
+  | MinusPP as bop ->
+    Options.fatal
+      "Operation '%a' either not arithmetic or not supported on GMP integers"
+      Printer.pp_binop bop
+
 let init ~loc e = apply_on_var "init" ~loc e
 let clear ~loc e = apply_on_var "clear" ~loc e
 
diff --git a/src/plugins/e-acsl/src/code_generator/gmp.mli b/src/plugins/e-acsl/src/code_generator/gmp.mli
index db4811dbeca2f1b6925cdc933215ea28c7a5cded..a4d86ff66e8969776b4061d4ba26e9990621bf08 100644
--- a/src/plugins/e-acsl/src/code_generator/gmp.mli
+++ b/src/plugins/e-acsl/src/code_generator/gmp.mli
@@ -24,6 +24,10 @@
 
 open Cil_types
 
+val name_of_mpz_arith_bop: binop -> string
+(** [name_of_mpz_arith_bop bop] returns the name of the GMP function on integer
+    corresponding to the [bop] arithmetic operation. *)
+
 val init: loc:location -> exp -> stmt
 (** build stmt [mpz_init(v)] or [mpq_init(v)] depending on typ of [v] *)
 
diff --git a/src/plugins/e-acsl/src/code_generator/logic_functions.ml b/src/plugins/e-acsl/src/code_generator/logic_functions.ml
index ebb75d0b2b7cda9a7955284269fcb74cab8f1041..860869d2fdc79820789af7e753044cdb8aad74ce 100644
--- a/src/plugins/e-acsl/src/code_generator/logic_functions.ml
+++ b/src/plugins/e-acsl/src/code_generator/logic_functions.ml
@@ -283,7 +283,9 @@ let add_generated_functions globals =
   in
   List.rev rev_globals
 
-let tapp_to_exp ~loc fname env kf t li params_ty args =
+(* Generate (and memoize) the function body and create the call to the
+   generated function. *)
+let function_to_exp ~loc fname env kf t li params_ty args =
   let ret_ty = Typing.get_typ t in
   let gen tbl =
     let vi, kf, gen_body = generate_kf fname ~loc env ret_ty params_ty li in
@@ -342,6 +344,101 @@ let tapp_to_exp ~loc fname env kf t li params_ty args =
     ret_ty
     (fun vi _ -> [ Cil.mkStmtOneInstr ~valid_sid:true (mkcall vi) ])
 
+let tapp_to_exp kf env ?eargs tapp =
+  match tapp.term_node with
+  | Tapp(li, [], targs) ->
+    let loc = tapp.term_loc in
+    let fname = li.l_var_info.lv_name in
+    (* build the varinfo (as an expression) which stores the result of the
+       function call. *)
+    let _, e, env =
+      if Builtins.mem li.l_var_info.lv_name then
+        (* E-ACSL built-in function call *)
+        let args, env =
+          match eargs with
+          | None ->
+            List.fold_right
+              (fun targ (l, env) ->
+                 let e, env = !term_to_exp_ref kf env targ in
+                 e :: l, env)
+              targs
+              ([], env)
+          | Some eargs ->
+            if List.compare_lengths targs eargs != 0 then
+              Options.fatal
+                "[Tapp] unexpected number of arguments when calling %s"
+                fname;
+            eargs, env
+        in
+        Env.new_var
+          ~loc
+          ~name:(fname ^ "_app")
+          env
+          kf
+          (Some tapp)
+          (Misc.cty (Option.get li.l_type))
+          (fun vi _ ->
+             [ Smart_stmt.rtl_call ~loc
+                 ~result:(Cil.var vi)
+                 ~prefix:""
+                 fname
+                 args ])
+      else
+        (* build the arguments and compute the integer_ty of the parameters *)
+        let params_ty, args, env =
+          let eargs, env =
+            match eargs with
+            | None ->
+              List.fold_right
+                (fun targ (eargs, env) ->
+                   let e, env = !term_to_exp_ref kf env targ in
+                   e :: eargs, env)
+                targs
+                ([], env)
+            | Some eargs ->
+              if List.compare_lengths targs eargs != 0 then
+                Options.fatal
+                  "[Tapp] unexpected number of arguments when calling %s"
+                  fname;
+              eargs, env
+          in
+          try
+            List.fold_right2
+              (fun targ earg (params_ty, args, env) ->
+                 let param_ty = Typing.get_number_ty targ in
+                 let e, env =
+                   try
+                     let ty = Typing.typ_of_number_ty param_ty in
+                     Typed_number.add_cast
+                       ~loc
+                       env
+                       kf
+                       (Some ty)
+                       Typed_number.C_number
+                       (Some targ)
+                       earg
+                   with Typing.Not_a_number ->
+                     earg, env
+                 in
+                 param_ty :: params_ty, e :: args, env)
+              targs eargs
+              ([], [], env)
+          with Invalid_argument _ ->
+            Options.fatal
+              "[Tapp] unexpected number of arguments when calling %s"
+              fname
+        in
+        let gen_fname =
+          Varname.get ~scope:Varname.Global (Functions.RTL.mk_gen_name fname)
+        in
+        function_to_exp ~loc gen_fname env kf tapp li params_ty args
+    in
+    e, env
+  | _ ->
+    Options.fatal
+      "tapp_to_exp called with '%a' instead of Tapp term"
+      Printer.pp_term tapp
+
 (*
 Local Variables:
 compile-command: "make -C ../.."
diff --git a/src/plugins/e-acsl/src/code_generator/logic_functions.mli b/src/plugins/e-acsl/src/code_generator/logic_functions.mli
index 0f8898ffb67155c4231e4f960f4d80b6c15c6ad8..6e3e662d05d912a3052c90d734515200a95bf118 100644
--- a/src/plugins/e-acsl/src/code_generator/logic_functions.mli
+++ b/src/plugins/e-acsl/src/code_generator/logic_functions.mli
@@ -37,10 +37,9 @@ open Cil_types
 val reset: unit -> unit
 
 val tapp_to_exp:
-  loc:location ->
-  string -> Env.t -> kernel_function ->
-  term -> logic_info -> Typing.number_ty list -> exp list ->
-  varinfo * exp * Env.t
+  kernel_function -> Env.t -> ?eargs:exp list -> term -> exp * Env.t
+(** Translate a Tapp term to an expression. If the optional argument [eargs] is
+    provided, then these expressions are used as arguments of the fonction. *)
 
 val add_generated_functions: global list -> global list
 (* @return the input list of globals in which the generated functions have been
diff --git a/src/plugins/e-acsl/src/code_generator/translate.ml b/src/plugins/e-acsl/src/code_generator/translate.ml
index b5b44048da759670b1884a7e9d2123655d6afd62..2c4ace3aea337c3113b74e6f977b64824b33b8b9 100644
--- a/src/plugins/e-acsl/src/code_generator/translate.ml
+++ b/src/plugins/e-acsl/src/code_generator/translate.ml
@@ -45,114 +45,10 @@ let relation_to_binop = function
   | Req -> Eq
   | Rneq -> Ne
 
-let name_of_mpz_arith_bop = function
-  | PlusA -> "__gmpz_add"
-  | MinusA -> "__gmpz_sub"
-  | Mult -> "__gmpz_mul"
-  | Div -> "__gmpz_tdiv_q"
-  | Mod -> "__gmpz_tdiv_r"
-  | BAnd -> "__gmpz_and"
-  | BOr -> "__gmpz_ior"
-  | BXor -> "__gmpz_xor"
-  | Shiftlt -> "__gmpz_mul_2exp"
-  | Shiftrt -> "__gmpz_tdiv_q_2exp"
-  | Lt | Gt | Le | Ge | Eq | Ne | LAnd | LOr | PlusPI | IndexPI | MinusPI
-  | MinusPP -> assert false
-
-(* Type of a string that represents a number.
-   Used when a string is required to encode a constant number because it is not
-   representable in any C type  *)
-type strnum =
-  | Str_Z         (* integers *)
-  | Str_R         (* reals *)
-  | C_number      (* integers and floats included *)
-
-(* convert [e] in a way that it is compatible with the given typing context. *)
-let add_cast ~loc ?name env kf ctx strnum t_opt e =
-  let mk_mpz e =
-    let _, e, env =
-      Env.new_var
-        ~loc
-        ?name
-        env
-        kf
-        t_opt
-        (Gmp_types.Z.t ())
-        (fun lv v -> [ Gmp.init_set ~loc (Cil.var lv) v e ])
-    in
-    e, env
-  in
-  let e, env = match strnum with
-    | Str_Z -> mk_mpz e
-    | Str_R -> Rational.create ~loc ?name e env kf t_opt
-    | C_number -> e, env
-  in
-  match ctx with
-  | None ->
-    e, env
-  | Some ctx ->
-    let ty = Cil.typeOf e in
-    match Gmp_types.Z.is_t ty, Gmp_types.Z.is_t ctx with
-    | true, true ->
-      (* Z --> Z *)
-      e, env
-    | false, true ->
-      if Gmp_types.Q.is_t ty then
-        (* R --> Z *)
-        Rational.cast_to_z ~loc ?name e env
-      else
-        (* C integer --> Z *)
-        let e =
-          if not (Cil.isIntegralType ty) && strnum = C_number then
-            (* special case for \null that must be casted to long: it is the
-               only non integral value that can be seen as an integer, while the
-               type system infers that it is C-representable (see
-               tests/runtime/null.i) *)
-            Cil.mkCast Cil.longType e (* \null *)
-          else
-            e
-        in
-        mk_mpz e
-    | _, false ->
-      if Gmp_types.Q.is_t ctx then
-        if Gmp_types.Q.is_t (Cil.typeOf e) then (* R --> R *)
-          e, env
-        else (* C integer or Z --> R *)
-          Rational.create ~loc ?name e env kf t_opt
-      else if Gmp_types.Z.is_t ty || strnum = Str_Z then
-        (* Z --> C type or the integer is represented by a string:
-           anyway, it fits into a C integer: convert it *)
-        let fname, new_ty =
-          if Cil.isSignedInteger ctx then "__gmpz_get_si", Cil.longType
-          else "__gmpz_get_ui", Cil.ulongType
-        in
-        let _, e, env =
-          Env.new_var
-            ~loc
-            ?name
-            env
-            kf
-            None
-            new_ty
-            (fun v _ ->
-               [ Smart_stmt.rtl_call ~loc
-                   ~result:(Cil.var v)
-                   ~prefix:""
-                   fname
-                   [ e ] ])
-        in
-        e, env
-      else if Gmp_types.Q.is_t ty || strnum = Str_R then
-        (* R --> C type or the real is represented by a string *)
-        Rational.add_cast ~loc ?name e env kf ctx
-      else
-        (* C type --> another C type *)
-        Cil.mkCastT ~force:false ~oldt:ty ~newt:ctx e, env
-
 let constant_to_exp ~loc t c =
   let mk_real s =
     let s = Rational.normalize_str s in
-    Cil.mkString ~loc s, Str_R
+    Cil.mkString ~loc s, Typed_number.Str_R
   in
   match c with
   | Integer(n, _repr) ->
@@ -163,7 +59,7 @@ let constant_to_exp ~loc t c =
      | Typing.Rational -> mk_real (Integer.to_string n)
      | Typing.Gmpz ->
        (* too large integer *)
-       Cil.mkString ~loc (Integer.to_string n), Str_Z
+       Cil.mkString ~loc (Integer.to_string n), Typed_number.Str_Z
      | Typing.C_float fkind ->
        Cil.kfloat ~loc fkind (Int64.to_float (Integer.to_int64 n)), C_number
      | Typing.C_integer kind ->
@@ -171,7 +67,7 @@ let constant_to_exp ~loc t c =
        match cast, kind with
        | Some ty, (ILongLong | IULongLong) when Gmp_types.Z.is_t ty ->
          (* too large integer *)
-         Cil.mkString ~loc (Integer.to_string n), Str_Z
+         Cil.mkString ~loc (Integer.to_string n), Typed_number.Str_Z
        | Some ty, _ when Gmp_types.Q.is_t ty ->
          mk_real (Integer.to_string n)
        | (None | Some _), _ ->
@@ -181,15 +77,15 @@ let constant_to_exp ~loc t c =
             long] addition and so [1LL]. If we keep the initial string
             representation, the kind would be ignored in the generated code and
             so [1] would be generated. *)
-         Cil.kinteger64 ~loc ~kind n, C_number)
-  | LStr s -> Cil.new_exp ~loc (Const (CStr s)), C_number
-  | LWStr s -> Cil.new_exp ~loc (Const (CWStr s)), C_number
-  | LChr c -> Cil.new_exp ~loc (Const (CChr c)), C_number
+         Cil.kinteger64 ~loc ~kind n, Typed_number.C_number)
+  | LStr s -> Cil.new_exp ~loc (Const (CStr s)), Typed_number.C_number
+  | LWStr s -> Cil.new_exp ~loc (Const (CWStr s)), Typed_number.C_number
+  | LChr c -> Cil.new_exp ~loc (Const (CChr c)), Typed_number.C_number
   | LReal lr ->
     if lr.r_lower = lr.r_upper
-    then Cil.kfloat ~loc FDouble lr.r_nearest, C_number
+    then Cil.kfloat ~loc FDouble lr.r_nearest, Typed_number.C_number
     else mk_real lr.r_literal
-  | LEnum e -> Cil.new_exp ~loc (Const (CEnum e)), C_number
+  | LEnum e -> Cil.new_exp ~loc (Const (CEnum e)), Typed_number.C_number
 
 let conditional_to_exp ?(name="if") loc kf t_opt e1 (e2, env2) (e3, env3) =
   let env = Env.pop (Env.pop env3) in
@@ -274,17 +170,18 @@ and context_insensitive_term_to_exp kf env t =
     c, env, strnum, ""
   | TLval lv ->
     let lv, env, name = tlval_to_lval kf env lv in
-    Smart_exp.lval ~loc lv, env, C_number, name
-  | TSizeOf ty -> Cil.sizeOf ~loc ty, env, C_number, "sizeof"
+    Smart_exp.lval ~loc lv, env, Typed_number.C_number, name
+  | TSizeOf ty -> Cil.sizeOf ~loc ty, env, Typed_number.C_number, "sizeof"
   | TSizeOfE t ->
     let e, env = term_to_exp kf env t in
-    Cil.sizeOf ~loc (Cil.typeOf e), env, C_number, "sizeof"
+    Cil.sizeOf ~loc (Cil.typeOf e), env, Typed_number.C_number, "sizeof"
   | TSizeOfStr s ->
-    Cil.new_exp ~loc (SizeOfStr s), env, C_number, "sizeofstr"
-  | TAlignOf ty -> Cil.new_exp ~loc (AlignOf ty), env, C_number, "alignof"
+    Cil.new_exp ~loc (SizeOfStr s), env, Typed_number.C_number, "sizeofstr"
+  | TAlignOf ty ->
+    Cil.new_exp ~loc (AlignOf ty), env, Typed_number.C_number, "alignof"
   | TAlignOfE t ->
     let e, env = term_to_exp kf env t in
-    Cil.new_exp ~loc (AlignOfE e), env, C_number, "alignof"
+    Cil.new_exp ~loc (AlignOfE e), env, Typed_number.C_number, "alignof"
   | TUnOp(Neg | BNot as op, t') ->
     let ty = Typing.get_typ t in
     let e, env = term_to_exp kf env t' in
@@ -303,11 +200,11 @@ and context_insensitive_term_to_exp kf env t =
           (Some t)
           (fun _ ev -> [ Smart_stmt.rtl_call ~loc ~prefix:"" name [ ev; e ] ])
       in
-      e, env, C_number, ""
+      e, env, Typed_number.C_number, ""
     else if Gmp_types.Q.is_t ty then
       Env.not_yet env "reals: Neg | BNot"
     else
-      Cil.new_exp ~loc (UnOp(op, e, ty)), env, C_number, ""
+      Cil.new_exp ~loc (UnOp(op, e, ty)), env, Typed_number.C_number, ""
   | TUnOp(LNot, t) ->
     let ty = Typing.get_op t in
     if Gmp_types.Z.is_t ty then
@@ -318,18 +215,19 @@ and context_insensitive_term_to_exp kf env t =
       let e, env =
         comparison_to_exp kf ~loc ~name:"not" env Typing.gmpz Eq t zero (Some t)
       in
-      e, env, C_number, ""
+      e, env, Typed_number.C_number, ""
     else begin
       assert (Cil.isIntegralType ty);
       let e, env = term_to_exp kf env t in
-      Cil.new_exp ~loc (UnOp(LNot, e, Cil.intType)), env, C_number, ""
+      let e = Cil.new_exp ~loc (UnOp(LNot, e, Cil.intType)) in
+      e, env, Typed_number.C_number, ""
     end
   | TBinOp(PlusA | MinusA | Mult as bop, t1, t2) ->
     let ty = Typing.get_typ t in
     let e1, env = term_to_exp kf env t1 in
     let e2, env = term_to_exp kf env t2 in
     if Gmp_types.Z.is_t ty then
-      let name = name_of_mpz_arith_bop bop in
+      let name = Gmp.name_of_mpz_arith_bop bop in
       let mk_stmts _ e = [ Smart_stmt.rtl_call ~loc
                              ~prefix:""
                              name
@@ -338,13 +236,13 @@ and context_insensitive_term_to_exp kf env t =
       let _, e, env =
         Env.new_var_and_mpz_init ~loc ~name env kf (Some t) mk_stmts
       in
-      e, env, C_number, ""
+      e, env, Typed_number.C_number, ""
     else if Gmp_types.Q.is_t ty then
       let e, env = Rational.binop ~loc bop e1 e2 env kf (Some t) in
-      e, env, C_number, ""
+      e, env, Typed_number.C_number, ""
     else begin
       assert (Logic_typing.is_integral_type t.term_type);
-      Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, C_number, ""
+      Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, Typed_number.C_number, ""
     end
   | TBinOp(Div | Mod as bop, t1, t2) ->
     let ty = Typing.get_typ t in
@@ -355,7 +253,7 @@ and context_insensitive_term_to_exp kf env t =
          RTE should do this automatically. *)
       let ctx = Typing.get_number_ty t in
       let t = Some t in
-      let name = name_of_mpz_arith_bop bop in
+      let name = Gmp.name_of_mpz_arith_bop bop in
       (* [TODO] can now do better since the type system got some info about
          possible values of [t2] *)
       (* guarding divisions and modulos *)
@@ -384,20 +282,20 @@ and context_insensitive_term_to_exp kf env t =
       in
       let name = Misc.name_of_binop bop in
       let _, e, env = Env.new_var_and_mpz_init ~loc ~name env kf t mk_stmts in
-      e, env, C_number, ""
+      e, env, Typed_number.C_number, ""
     else if Gmp_types.Q.is_t ty then
       let e, env = Rational.binop ~loc bop e1 e2 env kf (Some t) in
-      e, env, C_number, ""
+      e, env, Typed_number.C_number, ""
     else begin
       assert (Logic_typing.is_integral_type t.term_type);
       (* no guard required since RTEs are generated separately *)
-      Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, C_number, ""
+      Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, Typed_number.C_number, ""
     end
   | TBinOp(Lt | Gt | Le | Ge | Eq | Ne as bop, t1, t2) ->
     (* comparison operators *)
     let ity = Typing.get_integer_op t in
     let e, env = comparison_to_exp ~loc kf env ity bop t1 t2 (Some t) in
-    e, env, C_number, ""
+    e, env, Typed_number.C_number, ""
   | TBinOp((Shiftlt | Shiftrt) as bop, t1, t2) ->
     (* left/right shift *)
     let ty = Typing.get_typ t in
@@ -486,7 +384,7 @@ and context_insensitive_term_to_exp kf env t =
 
       (* Create the shift instruction *)
       let mk_shift_instr result_e =
-        let name = name_of_mpz_arith_bop bop in
+        let name = Gmp.name_of_mpz_arith_bop bop in
         Smart_stmt.rtl_call ~loc
           ~prefix:""
           name
@@ -543,10 +441,10 @@ and context_insensitive_term_to_exp kf env t =
       in
       let name = bop_name in
       let _, e, env = Env.new_var_and_mpz_init ~loc ~name env kf t mk_stmts in
-      e, env, C_number, ""
+      e, env, Typed_number.C_number, ""
     else begin
       assert (Logic_typing.is_integral_type t.term_type);
-      Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, C_number, ""
+      Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, Typed_number.C_number, ""
     end
   | TBinOp(LOr, t1, t2) ->
     (* t1 || t2 <==> if t1 then true else t2 *)
@@ -560,7 +458,7 @@ and context_insensitive_term_to_exp kf env t =
               ~name:"or" loc kf (Some t) e1 (Cil.one loc, env') res2
           )
     in
-    e, env, C_number, ""
+    e, env, Typed_number.C_number, ""
   | TBinOp(LAnd, t1, t2) ->
     (* t1 && t2 <==> if t1 then t2 else false *)
     let e, env =
@@ -573,7 +471,7 @@ and context_insensitive_term_to_exp kf env t =
               ~name:"and" loc kf (Some t) e1 res2 (Cil.zero loc, env3)
           )
     in
-    e, env, C_number, ""
+    e, env, Typed_number.C_number, ""
   | TBinOp((BOr | BXor | BAnd) as bop, t1, t2) ->
     (* other logic/arith operators  *)
     let ty = Typing.get_typ t in
@@ -581,17 +479,17 @@ and context_insensitive_term_to_exp kf env t =
     let e2, env = term_to_exp kf env t2 in
     if Gmp_types.Z.is_t ty then
       let mk_stmts _v e =
-        let name = name_of_mpz_arith_bop bop in
+        let name = Gmp.name_of_mpz_arith_bop bop in
         let instr = Smart_stmt.rtl_call ~loc ~prefix:"" name [ e; e1; e2 ] in
         [ instr ]
       in
       let name = Misc.name_of_binop bop in
       let t = Some t in
       let _, e, env = Env.new_var_and_mpz_init ~loc ~name env kf t mk_stmts in
-      e, env, C_number, ""
+      e, env, Typed_number.C_number, ""
     else begin
       assert (Logic_typing.is_integral_type t.term_type);
-      Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, C_number, ""
+      Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, Typed_number.C_number, ""
     end
   | TBinOp(PlusPI | IndexPI | MinusPI as bop, t1, t2) ->
     if Misc.is_set_of_ptr_or_array t1.term_type ||
@@ -607,14 +505,15 @@ and context_insensitive_term_to_exp kf env t =
     in
     let e1, env = term_to_exp kf env t1 in
     let e2, env = term_to_exp kf env t2 in
-    Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, C_number, ""
+    Cil.new_exp ~loc (BinOp(bop, e1, e2, ty)), env, Typed_number.C_number, ""
   | TBinOp(MinusPP, t1, t2) ->
     begin match Typing.get_number_ty t with
       | Typing.C_integer _ ->
         let e1, env = term_to_exp kf env t1 in
         let e2, env = term_to_exp kf env t2 in
         let ty = Typing.get_typ t in
-        Cil.new_exp ~loc (BinOp(MinusPP, e1, e2, ty)), env, C_number, ""
+        let e = Cil.new_exp ~loc (BinOp(MinusPP, e1, e2, ty)) in
+        e, env, Typed_number.C_number, ""
       | Typing.Gmpz ->
         Env.not_yet env "pointer subtraction resulting in gmp"
       | Typing.(C_float _ | Rational | Real | Nan) ->
@@ -623,73 +522,27 @@ and context_insensitive_term_to_exp kf env t =
   | TCastE(ty, t') ->
     let e, env = term_to_exp kf env t' in
     let e, env =
-      add_cast ~loc ~name:"cast" env kf (Some ty) C_number (Some t) e
+      Typed_number.add_cast
+        ~loc
+        ~name:"cast"
+        env
+        kf
+        (Some ty)
+        Typed_number.C_number
+        (Some t)
+        e
     in
-    e, env, C_number, ""
+    e, env, Typed_number.C_number, ""
   | TLogic_coerce _ -> assert false (* handle in [term_to_exp] *)
   | TAddrOf lv ->
     let lv, env, _ = tlval_to_lval kf env lv in
-    Cil.mkAddrOf ~loc lv, env, C_number, "addrof"
+    Cil.mkAddrOf ~loc lv, env, Typed_number.C_number, "addrof"
   | TStartOf lv ->
     let lv, env, _ = tlval_to_lval kf env lv in
-    Cil.mkAddrOrStartOf ~loc lv, env, C_number, "startof"
-  | Tapp(li, [], targs) ->
-    let fname = li.l_var_info.lv_name in
-    (* build the varinfo (as an expression) which stores the result of the
-       function call. *)
-    let _, e, env =
-      if Builtins.mem li.l_var_info.lv_name then
-        (* E-ACSL built-in function call *)
-        let args, env =
-          try
-            List.fold_right
-              (fun targ (l, env) ->
-                 let e, env = term_to_exp kf env targ in
-                 e :: l, env)
-              targs
-              ([], env)
-          with Invalid_argument _ ->
-            Options.fatal
-              "[Tapp] unexpected number of arguments when calling %s"
-              fname
-        in
-        Env.new_var
-          ~loc
-          ~name:(fname ^ "_app")
-          env
-          kf
-          (Some t)
-          (Misc.cty (Option.get li.l_type))
-          (fun vi _ ->
-             [ Smart_stmt.rtl_call ~loc
-                 ~result:(Cil.var vi)
-                 ~prefix:""
-                 fname
-                 args ])
-      else
-        (* build the arguments and compute the integer_ty of the parameters *)
-        let params_ty, args, env =
-          List.fold_right
-            (fun targ (params_ty, args, env) ->
-               let e, env = term_to_exp kf env targ in
-               let param_ty = Typing.get_number_ty targ in
-               let e, env =
-                 try
-                   let ty = Typing.typ_of_number_ty param_ty in
-                   add_cast loc env kf (Some ty) C_number (Some targ) e
-                 with Typing.Not_a_number ->
-                   e, env
-               in
-               param_ty :: params_ty, e :: args, env)
-            targs
-            ([], [], env)
-        in
-        let gen_fname =
-          Varname.get ~scope:Varname.Global (Functions.RTL.mk_gen_name fname)
-        in
-        Logic_functions.tapp_to_exp ~loc gen_fname env kf t li params_ty args
-    in
-    e, env, C_number, "app"
+    Cil.mkAddrOrStartOf ~loc lv, env, Typed_number.C_number, "startof"
+  | Tapp(_, [], _) ->
+    let e, env = Logic_functions.tapp_to_exp kf env t in
+    e, env, Typed_number.C_number, "app"
   | Tapp(_, _ :: _, _) ->
     Env.not_yet env "logic functions with labels"
   | Tlambda _ -> Env.not_yet env "functional"
@@ -704,16 +557,16 @@ and context_insensitive_term_to_exp kf env t =
             conditional_to_exp loc kf (Some t) e1 res2 res3
           )
     in
-    e, env, C_number, ""
+    e, env, Typed_number.C_number, ""
   | Tat(t, BuiltinLabel Here) ->
     let e, env = term_to_exp kf env t in
-    e, env, C_number, ""
+    e, env, Typed_number.C_number, ""
   | Tat(t', label) ->
     let lscope = Env.Logic_scope.get env in
     let pot = Lscope.PoT_term t' in
     if Lscope.is_used lscope pot then
       let e, env = At_with_lscope.to_exp ~loc kf env pot label in
-      e, env, C_number, ""
+      e, env, Typed_number.C_number, ""
     else
       let e, env = term_to_exp kf (Env.push env) t' in
       let e, env, sty = at_to_exp_no_lscope env kf (Some t) label e in
@@ -721,22 +574,23 @@ and context_insensitive_term_to_exp kf env t =
   | Tbase_addr(BuiltinLabel Here, t) ->
     let name = "base_addr" in
     let e, env = Memory_translate.call ~loc kf name Cil.voidPtrType env t in
-    e, env, C_number, name
+    e, env, Typed_number.C_number, name
   | Tbase_addr _ -> Env.not_yet env "labeled \\base_addr"
   | Toffset(BuiltinLabel Here, t) ->
     let size_t = Cil.theMachine.Cil.typeOfSizeOf in
     let name = "offset" in
     let e, env = Memory_translate.call ~loc kf name size_t env t in
-    e, env, C_number, name
+    e, env, Typed_number.C_number, name
   | Toffset _ -> Env.not_yet env "labeled \\offset"
   | Tblock_length(BuiltinLabel Here, t) ->
     let size_t = Cil.theMachine.Cil.typeOfSizeOf in
     let name = "block_length" in
     let e, env = Memory_translate.call ~loc kf name size_t env t in
-    e, env, C_number, name
+    e, env, Typed_number.C_number, name
   | Tblock_length _ -> Env.not_yet env "labeled \\block_length"
   | Tnull ->
-    Cil.mkCast (TPtr(TVoid [], [])) (Cil.zero ~loc), env, C_number, "null"
+    let e = Cil.mkCast (TPtr(TVoid [], [])) (Cil.zero ~loc) in
+    e, env, Typed_number.C_number, "null"
   | TUpdate _ -> Env.not_yet env "functional update"
   | Ttypeof _ -> Env.not_yet env "typeof"
   | Ttype _ -> Env.not_yet env "C type"
@@ -751,7 +605,7 @@ and context_insensitive_term_to_exp kf env t =
     let env = env_of_li li kf env loc in
     let e, env = term_to_exp kf env t in
     Interval.Env.remove li.l_var_info;
-    e, env, C_number, ""
+    e, env, Typed_number.C_number, ""
 
 (* Convert an ACSL term into a corresponding C expression (if any) in the given
    environment. Also extend this environment in order to include the generating
@@ -767,7 +621,7 @@ and term_to_exp kf env t =
         let env = if generate_rte then translate_rte kf env e else env in
         let cast = Typing.get_cast t in
         let name = if name = "" then None else Some name in
-        add_cast
+        Typed_number.add_cast
           ~loc:t.term_loc
           ?name
           env
@@ -878,7 +732,7 @@ and at_to_exp_no_lscope env kf t_opt label e =
   end
   in
   ignore (Visitor.visitFramacStmt o stmt);
-  res, !env_ref, C_number
+  res, !env_ref, Typed_number.C_number
 
 and env_of_li li kf env loc =
   let t = Misc.term_of_li li in
@@ -994,7 +848,7 @@ and predicate_content_to_exp ?name kf env p =
       (* convert [t'] to [e] in a separated local env *)
       let e, env = predicate_to_exp kf (Env.push env) p' in
       let e, env, sty = at_to_exp_no_lscope env kf None label e in
-      assert (sty = C_number);
+      assert (sty = Typed_number.C_number);
       e, env
     end
   | Pvalid_read(BuiltinLabel Here as llabel, t) as pc
@@ -1087,13 +941,13 @@ and predicate_to_exp ?name kf ?rte env p =
         let e, env = predicate_content_to_exp ?name kf env p in
         let env = if rte then translate_rte kf env e else env in
         let cast = Typing.get_cast_of_predicate p in
-        add_cast
+        Typed_number.add_cast
           ~loc:p.pred_loc
           ?name
           env
           kf
           cast
-          C_number
+          Typed_number.C_number
           None
           e
       )
@@ -1205,10 +1059,15 @@ let untyped_predicate_to_exp p =
   let env = Env.push Env.empty in
   let env = Env.rte env false in
   let e, env =
-    try generalized_untyped_predicate_to_exp ~must_clear_typing:false (Kernel_function.dummy ()) env p
+    try generalized_untyped_predicate_to_exp
+          ~must_clear_typing:false
+          (Kernel_function.dummy ())
+          env
+          p
     with Rtl.Symbols.Unregistered _ -> raise (No_simple_predicate_translation p)
   in
-  if not (Env.has_no_new_stmt env) then raise (No_simple_predicate_translation p);
+  if not (Env.has_no_new_stmt env)
+  then raise (No_simple_predicate_translation p);
   e
 
 (* This function is used by plug-in [Cfp]. *)
diff --git a/src/plugins/e-acsl/src/code_generator/typed_number.ml b/src/plugins/e-acsl/src/code_generator/typed_number.ml
new file mode 100644
index 0000000000000000000000000000000000000000..dfa8a4497a868038fade0ac52e77a056075c37cc
--- /dev/null
+++ b/src/plugins/e-acsl/src/code_generator/typed_number.ml
@@ -0,0 +1,109 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(** Manipulate the type of numbers. *)
+
+type strnum =
+  | Str_Z         (* integers *)
+  | Str_R         (* reals *)
+  | C_number      (* integers and floats included *)
+
+let add_cast ~loc ?name env kf ctx strnum t_opt e =
+  let mk_mpz e =
+    let _, e, env =
+      Env.new_var
+        ~loc
+        ?name
+        env
+        kf
+        t_opt
+        (Gmp_types.Z.t ())
+        (fun lv v -> [ Gmp.init_set ~loc (Cil.var lv) v e ])
+    in
+    e, env
+  in
+  let e, env = match strnum with
+    | Str_Z -> mk_mpz e
+    | Str_R -> Rational.create ~loc ?name e env kf t_opt
+    | C_number -> e, env
+  in
+  match ctx with
+  | None ->
+    e, env
+  | Some ctx ->
+    let ty = Cil.typeOf e in
+    match Gmp_types.Z.is_t ty, Gmp_types.Z.is_t ctx with
+    | true, true ->
+      (* Z --> Z *)
+      e, env
+    | false, true ->
+      if Gmp_types.Q.is_t ty then
+        (* R --> Z *)
+        Rational.cast_to_z ~loc ?name e env
+      else
+        (* C integer --> Z *)
+        let e =
+          if not (Cil.isIntegralType ty) && strnum = C_number then
+            (* special case for \null that must be casted to long: it is the
+               only non integral value that can be seen as an integer, while the
+               type system infers that it is C-representable (see
+               tests/runtime/null.i) *)
+            Cil.mkCast Cil.longType e (* \null *)
+          else
+            e
+        in
+        mk_mpz e
+    | _, false ->
+      if Gmp_types.Q.is_t ctx then
+        if Gmp_types.Q.is_t (Cil.typeOf e) then (* R --> R *)
+          e, env
+        else (* C integer or Z --> R *)
+          Rational.create ~loc ?name e env kf t_opt
+      else if Gmp_types.Z.is_t ty || strnum = Str_Z then
+        (* Z --> C type or the integer is represented by a string:
+           anyway, it fits into a C integer: convert it *)
+        let fname, new_ty =
+          if Cil.isSignedInteger ctx then "__gmpz_get_si", Cil.longType
+          else "__gmpz_get_ui", Cil.ulongType
+        in
+        let _, e, env =
+          Env.new_var
+            ~loc
+            ?name
+            env
+            kf
+            None
+            new_ty
+            (fun v _ ->
+               [ Smart_stmt.rtl_call ~loc
+                   ~result:(Cil.var v)
+                   ~prefix:""
+                   fname
+                   [ e ] ])
+        in
+        e, env
+      else if Gmp_types.Q.is_t ty || strnum = Str_R then
+        (* R --> C type or the real is represented by a string *)
+        Rational.add_cast ~loc ?name e env kf ctx
+      else
+        (* C type --> another C type *)
+        Cil.mkCastT ~force:false ~oldt:ty ~newt:ctx e, env
diff --git a/src/plugins/e-acsl/src/code_generator/typed_number.mli b/src/plugins/e-acsl/src/code_generator/typed_number.mli
new file mode 100644
index 0000000000000000000000000000000000000000..bf75cc1cfe617ed4ff73ce2f39f1632e5fa58362
--- /dev/null
+++ b/src/plugins/e-acsl/src/code_generator/typed_number.mli
@@ -0,0 +1,49 @@
+(**************************************************************************)
+(*                                                                        *)
+(*  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).            *)
+(*                                                                        *)
+(**************************************************************************)
+
+(** Manipulate the type of numbers. *)
+
+open Cil_types
+
+(** Type of a string that represents a number.
+    Used when a string is required to encode a constant number because it is not
+    representable in any C type  *)
+type strnum =
+  | Str_Z         (* integers *)
+  | Str_R         (* reals *)
+  | C_number      (* integers and floats included *)
+
+(** [add_cast ~loc ?name env kf ctx sty t_opt e] convert number expression [e]
+    in a way that it is compatible with the given typing context [ctx].
+    [sty] indicates if the expression is a string representing a number (integer
+    or real) or directly a C number type.
+    [t_opt] is the term that is represented by the expression [e]. *)
+val add_cast:
+  loc:location ->
+  ?name:string ->
+  Env.t ->
+  kernel_function ->
+  typ option ->
+  strnum ->
+  term option ->
+  exp ->
+  exp * Env.t