let rec reduce_expression e =
    let loc = e.expr_pr.ctt_loc in
    let reduce = function
        CTTexpComma( e1, e2 ) ->
          begin
              match e1.expr_t with
                  CTTexpConstant _ -> e2
                | _ -> e
          end
      |        CTTexpConditional( e1, e2, e3 ) ->
          (* When e2 or e3 has an invalid and never-executed expression,
             such an expression should be excluded. *)

          begin
              match e1.expr_t with
                  CTTexpConstant (CTTconstInteger n) ->
                    if n = zero_big_int then e3 else e2
                | CTTexpConstant (CTTconstFloat n) ->
                    if n = 0.0 then e3 else e2
                | CTTexpConstant _ -> e2
                | _ -> e
          end
      | CTTexpBinExpr( operator, e1, e2 ) ->
          begin
              match e1.expr_t, e2.expr_t with
              CTTexpConstant (CTTconstInteger n1), CTTexpConstant (CTTconstInteger n2) ->
                { e with expr_t = compute_const_ii operator n1 n2 }
            | CTTexpConstant (CTTconstInteger n1), CTTexpConstant (CTTconstFloat n2) ->
                { e with expr_t = compute_const_fi operator n2 n1 }
            | CTTexpConstant (CTTconstFloat n1), CTTexpConstant (CTTconstInteger n2) ->
                { e with expr_t = compute_const_fi operator n1 n2 }
            | CTTexpConstant (CTTconstFloat n1), CTTexpConstant (CTTconstFloat n2) ->
                { e with expr_t = compute_const_ff operator n1 n2 }
            | _ -> e
          end
      | CTTexpCoerce( t, e1 ) ->
          let numeric = function
              Tbuiltin _ -> true | _ -> false
          in
          let is_int = function
              Tbuiltin Tfloat -> false | Tbuiltin Tdouble -> false
            | Tbuiltin Tlongdouble -> false
            | _ -> true
          in
          if numeric t.ct_ty then
              match e1.expr_t, is_int t.ct_ty with
                  CTTexpConstant (CTTconstInteger n), true ->
                    let n = coerce_int_constant n t in
                    make_expr (CTTexpConstant (CTTconstInteger n)) t ~loc
                | CTTexpConstant (CTTconstInteger n), false ->
                    make_expr (CTTexpConstant (CTTconstFloat (float_of_big_int n))) t ~loc
                | CTTexpConstant (CTTconstFloat n), true ->
                    make_expr (CTTexpConstant (CTTconstInteger (big_int_of_float n))) t ~loc
                | CTTexpConstant (CTTconstFloat _), false ->
                    { e with expr_type = t }
                | _ -> e
          else
              e
      | CTTexpUnaryExpr( operator, e1 ) ->
          begin
              match e1.expr_t with
                CTTexpConstant(CTTconstInteger n) ->
                  begin
                    match operator with
                            UnaryPlus -> e1
                          | UnaryMinus -> { e with expr_t = 
                                            CTTexpConstant(CTTconstInteger (minus_big_int n)) }
                          | LogNot ->
                              let n =
                                  if n = zero_big_int then unit_big_int else zero_big_int
                              in
                              { e with expr_t = CTTexpConstant(CTTconstInteger n) }
                          | IntNot ->
                              { e with expr_t = 
                                CTTexpConstant(CTTconstInteger 
                                                 (minus_big_int (add_int_big_int 1 n))) }
                    end
                | CTTexpConstant(CTTconstFloat n) ->
                    begin
                        match operator with
                            UnaryPlus -> e1
                          | UnaryMinus  -> { e with expr_t = CTTexpConstant(CTTconstFloat (-. n)) }
                          | LogNot -> assert false
                          | IntNot -> assert false
                    end
                | _ -> e
          end
      | CTTexpConstant _ -> e
      |        _ -> e
    in
    reduce e.expr_t