--          This file is part of SmartEiffel The GNU Eiffel Compiler.
--       Copyright (C) 1994-2002 LORIA - INRIA - U.H.P. Nancy 1 - FRANCE
--          Dominique COLNET and Suzanne COLLIN - SmartEiffel@loria.fr
--                       http://SmartEiffel.loria.fr
-- SmartEiffel is  free  software;  you can  redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the Free
-- Software  Foundation;  either  version  2, or (at your option)  any  later
-- version. SmartEiffel 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 General Public License
-- for  more  details.  You  should  have  received a copy of the GNU General
-- Public  License  along  with  SmartEiffel;  see the file COPYING.  If not,
-- write to the  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-- Boston, MA 02111-1307, USA.
--
class C_PRETTY_PRINTER
   --
   -- Singleton in charge of handling C code pretty printing.
   -- This singleton is shared via the GLOBALS.`cpp' once function.
   --

inherit CODE_PRINTER

feature

   on_h: BOOLEAN is
      require
	 smart_eiffel.is_ready
      do
	 Result := current_out = out_h
      end

   on_c: BOOLEAN is
      require
	 smart_eiffel.is_ready
      do
	 Result := current_out = out_c
      end

   swap_on_c is
      do
	 current_out := out_c
      ensure
	 on_c
      end

   swap_on_h is
      do
	 current_out := out_h
      ensure
	 on_h
      end

   put_string_on_h(string: STRING) is
      do
	 out_h.put_string(string)
      end

   put_extern1(decl: STRING) is
      do
	 out_h.put_string(fz_extern)
	 out_h.put_string(decl)
	 out_h.put_string(fz_00)
	 out_c.put_string(decl)
	 out_c.put_string(fz_00)
      end

   put_extern2(decl: STRING; init: CHARACTER) is
      do
	 out_h.put_string(fz_extern)
	 out_h.put_string(decl)
	 out_h.put_string(fz_00)
	 out_c.put_string(decl)
	 out_c.put_character('=')
	 out_c.put_character(init)
	 out_c.put_string(fz_00)
      end

   put_extern3(var, value: STRING) is
      do
	 out_c.put_string(once "char ")
	 out_c.put_string(var)
	 out_c.put_string(once "[]=%"")
	 out_c.put_string(value)
	 out_c.put_string(once "%";%N")
	 out_h.put_string(once "extern char ")
	 out_h.put_string(var)
	 out_h.put_character('[')
	 out_h.put_character(']')
	 out_h.put_string(fz_00)
      end

   put_extern4(t, var: STRING; value: INTEGER) is
      do
	 out_c.put_string(t)
	 out_c.put_character(' ')
	 out_c.put_string(var)
	 out_c.put_character('[')
	 out_c.put_integer(value)
	 out_c.put_string(once "];%N")
	 out_h.put_string(fz_extern)
	 out_h.put_string(t)
	 out_h.put_character(' ')
	 out_h.put_string(var)
	 out_h.put_character('[')
	 out_h.put_character(']')
	 out_h.put_string(fz_00)
      end

   put_extern5(decl: STRING; init: STRING) is
      do
	 out_h.put_string(fz_extern)
	 out_h.put_string(decl)
	 out_h.put_string(fz_00)
	 out_c.put_string(decl)
	 out_c.put_character('=')
	 out_c.put_string(init)
	 out_c.put_string(fz_00)
      end

   put_extern6(decl: STRING; init: INTEGER) is
      do
	 out_h.put_string(fz_extern)
	 out_h.put_string(decl)
	 out_h.put_string(fz_00)
	 out_c.put_string(decl)
	 out_c.put_character('=')
	 out_c.put_integer(init)
	 out_c.put_string(fz_00)
      end

   put_extern7(decl: STRING) is
      do
	 out_h.put_string(fz_extern)
	 out_h.put_string(decl)
	 out_h.put_string(fz_00)
	 out_c.put_string(decl)
	 out_c.put_character('=')
      end

   put_c_heading(heading: STRING) is
      do
	 out_h.put_string(heading)
	 out_h.put_string(fz_00)
	 out_c.put_character('%N')
	 out_c.put_string(heading)
	 out_c.put_string(fz_11)
      end

   put_c_function(heading, body:STRING) is
      require
	 not heading.is_empty
	 body /= Void
      do
	 put_c_heading(heading)
	 out_c.put_string(body)
	 out_c.put_string(fz_12)
      end

   put_string(c: STRING) is
      require
	 smart_eiffel.is_ready
      do
	 current_out.put_string(c)
      end

   put_string_c(s: STRING) is
      require
	 on_c
      do
	 tmp_string.clear
	 once_manifest_string_pool.string_to_c_code(s,tmp_string)
	 out_c.put_string(tmp_string)
      end

   put_character(c: CHARACTER) is
      require
	 smart_eiffel.is_ready
      do
	 current_out.put_character(c)
      end

   put_integer(i: INTEGER_64) is
      require
	 smart_eiffel.is_ready
      do
	 current_out.put_integer(i)
      end

   put_real(r: REAL) is
      require
	 smart_eiffel.is_ready
      do
	 current_out.put_real(r)
      end

   put_array1(array_name: CHARACTER; value: INTEGER) is
      do
	 current_out.put_character(array_name)
	 current_out.put_character('[')
	 current_out.put_integer(value)
	 current_out.put_character(']')
      end

   put_se_string(c_string: STRING) is
      do
	 current_out.put_string(once "se_string(")
	 put_string_c(c_string)
	 current_out.put_character(')')
      end

   put_position(p: POSITION) is
      require
	 on_c
      do
	 out_c.put_integer(p.mangling.to_integer)
	 put_position_comment_on(out_c,p)
      end

   put_position_in_ds(p: POSITION) is
      require
	 on_c
      do
	 out_c.put_string(once "ds.p=")
	 put_position(p)
	 out_c.put_string(fz_00)
      end

   current_target: EXPRESSION is
      local
         code: INTEGER
      do
         code := stack_code.item(top)
	 inspect
	    code
         when C_same_target then
            top := top - 1
            Result := current_target
            top := top + 1
         else
            Result := stack_target.item(top)
         end
      end

   target_type: E_TYPE is
      do
         Result := current_target.result_type
      end

   put_target_as_target is
	 -- Produce C code to pass the current stacked target as
	 -- a target of a new call : user expanded are passed with
	 -- a pointer and class invariant code is produced.
      require
	 smart_eiffel.is_ready
      local
	 code: INTEGER; rf: RUN_FEATURE; target: EXPRESSION
	 args: EFFECTIVE_ARG_LIST; ct: E_TYPE; ivt_flag: BOOLEAN
      do
	 code := stack_code.item(top)
	 inspect
	    code
	 when C_direct_call then
	    target := stack_target.item(top)
	    rf := stack_rf.item(top)
	    ct := rf.current_type
	    target.mapping_c_target(ct)
	 when C_check_id then
	    target := stack_target.item(top)
	    rf := stack_rf.item(top)
	    ct := rf.current_type
	    check
	       ct.is_reference
	    end
	    if ace.boost then
	       target.mapping_c_target(ct)
	    else
	       ivt_flag := call_invariant_start(ct)
	       check_id(target,rf.id)
	       if ivt_flag then
		  call_invariant_end
	       end
	    end
	 when C_inline_dca then
	    ct := stack_rf.item(top).current_type
	    ct := ct.run_class.run_time_set.first.current_type
	    check
	       ct.run_class.run_time_set.count = 1
	    end
	    put_character('(')
	    ct.mapping_cast
	    put_character('(')
	    put_target_as_value
	    put_string(fz_13)
	 when C_same_target then
	    rf := stack_rf.item(top)
	    args := stack_args.item(top)
	    top := top - 1
	    put_target_as_target
	    top := top + 1
	    stack_code.put(code,top)
	    stack_rf.put(rf,top)
	    stack_args.put(args,top)
	 else
	    common_put_target
	 end
      end

   put_target_as_value is
	 -- Produce C code for a simple access to the stacked target.
	 -- User's expanded values are not given using a pointer.
	 -- There is no C code to check the class invariant.
      require
	 smart_eiffel.is_ready
      local
	 code: INTEGER
	 rf, static_rf: RUN_FEATURE
	 target: EXPRESSION
	 args: EFFECTIVE_ARG_LIST
	 c0c: CALL_0_C
	 direct_rf: RUN_FEATURE
      do
	 code := stack_code.item(top)
	 inspect
	    code
	 when C_direct_call then
	    stack_target.item(top).compile_to_c
	 when C_check_id then
	    stack_rf.item(top).current_type.mapping_cast
	    stack_target.item(top).compile_to_c
	 when C_inline_dca then
	    rf := stack_rf.item(top)
	    target := stack_target.item(top)
	    args := stack_args.item(top)
	    static_rf := stack_static_rf.item(top)
	    top := top - 1
	    c0c ?= target
	    direct_rf := c0c.run_feature
	    direct_rf.mapping_c
	    top := top + 1
	    stack_code.put(code,top)
	    stack_rf.put(rf,top)
	    stack_target.put(target,top)
	    stack_args.put(args,top)
	    stack_static_rf.put(static_rf,top)
	 when C_same_target then
	    rf := stack_rf.item(top)
	    args := stack_args.item(top)
	    top := top - 1
	    put_target_as_value
	    top := top + 1
	    stack_code.put(code,top)
	    stack_rf.put(rf,top)
	    stack_args.put(args,top)
	 else
	    common_put_target
	 end
      end

   put_error0(msg: STRING) is
	 -- Print `msg' and then stop execution.
	 -- Also print stack when not -boost.
      do
	 if ace.boost then
	    put_comment(msg)
	    put_string(
               "%Nse_signal_handler(14/*System_level_type_error*/);%N")
	 else
	    put_string(once "error0(")
	    put_string_c(msg)
	    put_string(once ",NULL);%N")
	 end
      end

   put_position_comment(p: POSITION) is
      do
	 put_position_comment_on(current_out,p)
      end

   put_comment(str: STRING) is
      do
	 put_string(fz_open_c_comment)
	 put_string(str)
	 put_string(fz_close_c_comment)
      end

   put_comment_line(str: STRING) is
      do
	 put_character('%N')
	 put_comment(str)
	 put_character('%N')
      end

   define_main(rf3: RUN_FEATURE_3) is
      do
	 swap_on_c
	 -- Declare eiffel_root_object :
	 tmp_string.clear
	 tmp_string.extend('T')
	 rf3.run_class.id.append_in(tmp_string)
	 tmp_string.append(once "*eiffel_root_object")
	 put_extern5(tmp_string,fz_null)
	 -- Save argv argc :
	 put_extern1(once "int se_argc")
	 put_extern1(once "char**se_argv")
	 define_initialize_eiffel_runtime(rf3)
	 if not ace.no_main then
	    next_bunch_size(1)
	    really_define_c_main(rf3)
	 end
      end

   trace_boolean_expression(e: EXPRESSION) is
	 -- Produce a C boolean expression including trace code.
      require
	 e.result_type.is_boolean ; ace.no_check
      do
	 put_character('(')
	 put_trace_or_sedb_expression(e.start_position)
	 put_character(',')
	 e.compile_to_c
	 put_character(')')
      end

   next_bunch_size(size: INTEGER) is
      do
	 if not ace.no_split then
	    if bunch_counter = 1 and then bunch_size >= 200 then
	       split_c_file_now(size)
	    elseif size >= 200 then
	       split_c_file_now(size)
	    elseif bunch_size >= 400 then
	       split_c_file_now(size)
	    else
	       bunch_counter := bunch_counter + 1
	       bunch_size := bunch_size + size
	    end
	 end
      end

feature {SMART_EIFFEL}

   get_started is
      require
	 smart_eiffel.is_ready
      do
	 echo.file_removing(path_make)
	 top := -1
	 if ace.no_split then
	    echo.tfw_connect(out_c,path_c)
	 else
	    backup_tfw_connect(out_c,path_c)
	 end
	 current_out := out_c
	 begin_c_linkage (out_c)
	 add_first_include(path_h)
	 !!out_h.make
	 echo.tfw_connect(out_h,path_h)
	 current_out := out_h
	 begin_c_linkage (out_h)
	 put_banner(out_h)
	 out_h.put_character('%N')
	 sys_runtime_h_and_c(fz_base)
	 current_out := out_c
      ensure
	 on_c
      end

   cecil_define is
      local
	 save_out_h: like out_h
      do
	 save_out_h := out_h
	 cecil_pool.c_define_users
	 out_h := save_out_h
      end

   define_used_basics is
	 -- Produce C code only when used.
      do
	 echo.put_string(once "Define used basics.%N")
	 assignment_handler.c_definitions
	 bit_constant_definition
	 if sure_void_count > 0 then
	    echo.put_string(once "Calls with a Void target : ")
	    echo.put_integer(sure_void_count)
	    echo.put_string(once " (yes it is dangerous).%N")
	 end
	 echo.print_count(once "Direct Call",direct_call_count)
	 echo.print_count(once "Direct (Stupid-Switch) Call",
			  stupid_switch_call_count)
	 echo.print_count(once "Check Id Call",check_id_call_count)
	 echo.print_count(once "Switched Call",switched_call_count)
	 echo.print_count(once "Inlined Procedure",inlined_procedure_count)
	 echo.print_count(once "Inlined Function",inlined_function_count)
	 echo.print_count(once "Static Expression",static_expression_count)
	 echo.print_count(once "Procedure",procedure_count)
	 echo.print_count(once "Function",function_count)
	 echo.print_count(once "Procedure without Current",real_procedure_count)
	 echo.print_count(once "Function without Current",real_function_count)
	 echo.print_count(once "Precursor routine",precursor_routine_count)
	 echo.put_string(once "Internal stacks size used : ")
	 echo.put_integer(stack_code.count)
	 echo.put_character('%N')
	 end

   customize_runtime(sys_runtime_basic: SET[STRING]) is
      require
	 sys_runtime_basic /= Void
      local
	 i: INTEGER; item: STRING
      do
	 if ace.no_check then
	    sys_runtime_h_and_c(fz_no_check)
	    if ace.sedb then
	       put_extern2(once "int se_general_trace_switch",'0')
	       sys_runtime_h_and_c(fz_sedb)
	    end
	 else
	    sys_runtime_h_and_c(fz_boost)
	 end
	 exceptions_handler.customize_c_runtime
	 gc_handler.customize_c_runtime
	 agent_pool.customize_c_runtime
	 if smart_eiffel.deep_twin_used then
	    sys_runtime_h_and_c(as_deep_twin)
	 end
	 from
	    i := sys_runtime_basic.lower
	 until
	    i > sys_runtime_basic.upper
	 loop
	    item := sys_runtime_basic.item(i)
	    if item.has_prefix(once "basic_picasso") then
	       system_tools.add_lib_basic_picasso
	    end
	    sys_runtime_h_and_c(item)
	    i := i + 1
	 end
      end

feature {RUN_FEATURE,NATIVE}

   target_cannot_be_dropped: BOOLEAN is
	 -- True when top target cannot be dropped because we are
	 -- not sure that target is non Void or that target has
	 -- no side effects. When Result is true, printed
	 -- C code is : "(((void)(<target>))"
      require
	 smart_eiffel.is_ready
      local
	 target: EXPRESSION
	 type_of_target: E_TYPE
      do
	 inspect
	    stack_code.item(top)
	 when C_direct_call, C_check_id then
	    target := stack_target.item(top)
	    type_of_target := target.result_type
	    Result := not target.can_be_dropped
	 when C_inline_dca then
	    Result := true
	 when C_same_target then
	    top := top - 1
	    Result := target_cannot_be_dropped
	    top := top + 1
	 else
	 end
	 if Result then
	    put_string(once "((/*UT*/(void)(")
	    if type_of_target = Void then
	       put_target_as_target
	    elseif type_of_target.is_user_expanded then
	       put_target_as_value
	    else
	       put_target_as_target
	    end
	    put_string(fz_13)
	 end
      end

   arguments_cannot_be_dropped: BOOLEAN is
	 -- True when arguments cannot be dropped.
	 -- Printed C code is like :
	 --  "(((void)<exp1>),((void)<exp2>),...((void)<expN>)"
      do
	 if not no_args_to_eval then
	    Result := true
	    put_string(once "((/*UA*/(void)(")
	    put_arguments
	    put_string(fz_13)
	 end
      end

   cannot_drop_all: BOOLEAN is
	 -- Result is true when something (target or one argument)
	 -- cannot be dropped. Thus when something cannot be dropped,
	 -- Result is true and C code is printed :
	 --  "(((void)<exp1>),((void)<exp2>),...((void)<expN>)"
      do
	 if target_cannot_be_dropped then
	    Result := true
	    put_character(',')
	    if arguments_cannot_be_dropped then
	       put_character(')')
	    else
	       put_character('0')
	    end
	 else
	    Result := arguments_cannot_be_dropped
	 end
      end

feature

   put_arguments is
	 -- Produce code to access effective arguments list.
      require
	 smart_eiffel.is_ready
      local
	 i: INTEGER; fal: FORMAL_ARG_LIST
      do
	 from
	    fal := stack_rf.item(top).arguments
	    i := 1
	 until
	    i > fal.count
	 loop
	    put_ith_argument(i)
	    if i < fal.count then put_character(',') end
	    i := i + 1
	 end
      end

   put_ith_argument(index: INTEGER) is
	 -- Produce code to access to the ith argument.
      require
	 smart_eiffel.is_ready ; index >= 1
      local
	 code: INTEGER; rf, static_rf: RUN_FEATURE; target: EXPRESSION
	 args: EFFECTIVE_ARG_LIST; fal: FORMAL_ARG_LIST; switch: SWITCH
	 unwrap_buffer: STRING
      do
	 code := stack_code.item(top)
	 inspect
	    code
	 when C_switch then
	    fal := stack_rf.item(top).arguments
	    static_rf := stack_static_rf.item(top)
	    switch.put_ith_argument(static_rf,fal,index)
	 when C_create_expression, C_scoop_wrapper then
	    put_character('a')
	    put_integer(index)
	 when C_inline_dca then
	    rf := stack_rf.item(top)
	    target := stack_target.item(top)
	    args := stack_args.item(top)
	    static_rf := stack_static_rf.item(top)
	    top := top - 1
	    if rf /= Void then
	       args.dca_inline_ith(rf.arguments,index)
	    else
	       -- No rf for "=" and "/=".
	       args.dca_inline_ith(static_rf.arguments,index)
	    end
	    top := top + 1
	    stack_code.put(code,top)
	    stack_rf.put(rf,top)
	    stack_target.put(target,top)
	    stack_args.put(args,top)
	    stack_static_rf.put(static_rf,top)
	 when C_inline_one_pc then
	    print_argument(index)
	 when C_inside_twin then
	    check
	       index = 1
	    end
	    if stack_rf.item(top).current_type.is_reference then
	       put_string(once "((T0*)C)")
	    else
	       put_string(once "*C")
	    end
	 when
	    C_create_instruction,
	    C_direct_call,
	    C_check_id,
	    C_same_target,
	    C_precursor
	  then
	    fal := stack_rf.item(top).arguments
	    stack_args.item(top).compile_to_c_ith(fal,index)
	 when C_scoop_unwrapper then
	    unwrap_buffer := once "                "
	    unwrap_buffer.clear
	    unwrap_buffer.append(once "((Tw")
	    stack_rf.item(top).id.append_in(unwrap_buffer)
	    stack_rf.item(top).name.mapping_c_in(unwrap_buffer)
	    unwrap_buffer.append(once "*)data)->_")
	    unwrap_buffer.append(stack_rf.item(top).arguments.name(index).to_string)
	    out_c.put_string(unwrap_buffer)
	 end
     end

feature {NATIVE_SMART_EIFFEL}

   put_c_inline_h is
      local
	 c_code: STRING
      do
	 c_code := get_inline_ms.to_string
	 if not c_inline_h_mem.fast_has(c_code) then
	    c_inline_h_mem.add_last(c_code)
	    out_h.put_string(c_code)
	    out_h.put_character('%N')
	 end
      end

   put_c_inline_c is
      local
	 c_code: MANIFEST_STRING
      do
	 c_code := get_inline_ms
	 out_c.put_string(c_code.to_string)
      end

   put_trace_switch is
	 -- The GENERAL.trace_switch feature
      do
	 if ace.sedb then
	    put_string(once "se_general_trace_switch=(")
	    put_ith_argument(1)
	    put_string(fz_14)
	 end
      end

   put_sedb_breakpoint is
      require
	 on_c
      local
	 e: EXPRESSION; p: POSITION
      do
	 if ace.sedb then
	    out_c.put_string(once "sedb_breakpoint(&ds,")
	    e := stack_target.item(top)
	    if e /= Void then
	       p := e.start_position
	    end
	    put_position(p)
	    put_string(once ");%N")
	 end
      end

   put_generating_type(t: E_TYPE) is
      local
	 rc: RUN_CLASS
      do
	 put_string(fz_cast_t0_star)
	 put_character('(')
	 put_character('t')
	 put_character('[')
	 if t.is_reference then
	    rc := t.run_class
	    if rc.is_tagged then
	       put_character('(')
	       put_target_as_value
	       put_character(')')
	       put_string(fz_arrow_id)
	    else
	       put_integer(rc.id)
	    end
	 else
	    put_integer(t.id)
	 end
	 put_character(']')
	 put_character(')')
      end

   put_generator(t: E_TYPE) is
      require
	 t.is_run_type
      local
	 rc: RUN_CLASS
      do
	 put_string(fz_cast_t0_star)
	 put_character('(')
	 put_character('g')
	 put_character('[')
	 if t.is_reference then
	    rc := t.run_class
	    if rc.is_tagged then
	       put_character('(')
	       put_target_as_value
	       put_character(')')
	       put_string(fz_arrow_id)
	    else
	       put_integer(rc.id)
	    end
	 else
	    put_integer(t.id)
	 end
	 put_character(']')
	 put_character(')')
      end

   target_position_in_error_handler is
	 -- Add the target position into the `error_handler'.
      local
	 target: EXPRESSION
      do
	 target := stack_target.item(top)
	 if target /= Void then
	    error_handler.add_position(target.start_position)
	 end
      end

   put_object_size(t: E_TYPE) is
      require
	 t.is_run_type
      local
	 tcbd: BOOLEAN
      do
	 tcbd := target_cannot_be_dropped
	 if tcbd then
	    out_c.put_character(',')
	 end
	 out_c.put_string(once "sizeof(T")
	 out_c.put_integer(t.id)
	 out_c.put_character(')')
	 if tcbd then
	    out_c.put_character(')')
	 end
      end

feature {CECIL_FILE}

   connect_cecil_out_h(user_path_h: STRING) is
      do
	 !!out_h.make
	 echo.tfw_connect(out_h,user_path_h)
	 system_tools.mandatory_sys_runtime(fz_base,'h')
	 put_file(tmp_file_read,out_h)
	 out_h.put_string(
			  once "extern void*eiffel_root_object;%N%N%
			  %typedef char* T9;%N%
			  %/* Available Eiffel routines via -cecil:%N*/%N")
      end

   disconnect_cecil_out_h is
      do
	 out_h.disconnect
      end

feature {CECIL_POOL,RUN_FEATURE}

   push_scoop_unwrapper(rf: RUN_FEATURE) is
      require
	 rf /= Void
      do
	 stack_push(C_scoop_unwrapper)
	 stack_rf.put(rf,top)

	 -- *** IS IT CORRECT ?
	 -- direct_call_count := direct_call_count + 1
	 -- *** IS DYNAMIC DISPATCH POSSIBLE HERE ?
      end

   push_scoop_wrapper(rf: RUN_FEATURE) is
      require
	 rf /= Void
      do
	 stack_push(C_scoop_wrapper)
	 stack_rf.put(rf,top)

	 -- *** IS IT CORRECT ?
	 -- direct_call_count := direct_call_count + 1
	 -- *** IS DYNAMIC DISPATCH POSSIBLE HERE ?
      end

feature {CECIL_POOL,RUN_FEATURE}

   push_direct(rf: RUN_FEATURE; t: EXPRESSION; args: EFFECTIVE_ARG_LIST) is
      require
	 rf /= Void
	 t /= Void
      do
	 stack_push(C_direct_call)
	 stack_rf.put(rf,top)
	 stack_target.put(t,top)
	 stack_args.put(args,top)
	 direct_call_count := direct_call_count + 1
      end

feature {RUN_FEATURE_3}

   push_inline_one_pc(rf: RUN_FEATURE) is
      do
	 stack_push(C_inline_one_pc)
	 stack_rf.put(rf,top)
      end

feature {RUN_FEATURE_3,RUN_FEATURE_4}

   push_inline_dca(relay_rf: RUN_FEATURE; dpca: CALL_PROC_CALL) is
	 -- Where `dpca' is inside `relay_rf'.
      require
	 relay_rf /= Void
	 dpca /= Void
      do
	 stack_push(C_inline_dca)
	 stack_rf.put(dpca.run_feature,top)
	 stack_static_rf.put(relay_rf,top)
	 stack_target.put(dpca.target,top)
	 stack_args.put(dpca.arguments,top)
	 direct_call_count := direct_call_count + 1
      end

   push_same_target(rf: RUN_FEATURE; args: EFFECTIVE_ARG_LIST) is
      require
	 rf /= Void
      do
	 stack_push(C_same_target)
	 stack_rf.put(rf,top)
	 stack_args.put(args,top)
      end

feature {CECIL_POOL}

   push_cpc(up_rf: RUN_FEATURE; run_time_set: RUN_TIME_SET
	    t: EXPRESSION; args: EFFECTIVE_ARG_LIST) is
      require
	 run_time_set = up_rf.run_class.run_time_set
      local
	 dyn_rf: RUN_FEATURE
      do
	 check
	    not up_rf.current_type.is_type_of_agent
	    -- Because agent execution handled in class 
	    -- AGENT_INSTRUCTION and AGENT_EXPRESSION.
	 end
	 if run_time_set.count = 0 then
	    se_evobt(up_rf,t)
	 elseif run_time_set.count = 1 then
	    dyn_rf := run_time_set.first.dynamic(up_rf)
	    push_check(dyn_rf,t,args)
	    dyn_rf.mapping_c
	    pop
	 else
	    use_switch(up_rf,run_time_set,t,args)
	 end
      end

feature {SWITCH}

   inside_switch_call(dyn_rf, static_rf: RUN_FEATURE) is
	 -- Call the `dyn_rf' inside switching function for `static_rf'.
      require
	 dyn_rf /= Void
	 static_rf /= Void
	 dyn_rf.run_class.dynamic(static_rf) = dyn_rf
      local
	 dyn_result, static_result: E_TYPE; msg: STRING
	 cast, no_code, need_se_tmp, assign_call: BOOLEAN
      do
	 -- Extra comment to debug C code:
	 -- put_comment(dyn_rf.current_type.run_time_mark)
	 --
	 static_result := static_rf.result_type
	 if static_result /= Void then
	    static_result := static_result.run_type
	    dyn_result := dyn_rf.result_type
	    if static_result.is_user_expanded then
	       if dyn_result.is_user_expanded then
		  if dyn_result.run_class /= static_result.run_class then
		     no_code := true
		  end
	       end
	    end
	 end
	 if no_code then
	    msg := "Conversion from: "
	    msg.append(dyn_result.run_time_mark)
	    msg.append(once " to: ")
	    msg.append(static_result.run_time_mark)
	    msg.append(once " not yet implemented (sorry). %
			    %Please report on SmartEiffel@loria.fr.)")
	    put_error0(msg)
	 else
	    dyn_rf.collect_c_tmp
	    need_se_tmp := se_tmp_open_declaration
	    -- Opening section for Result:
	    if static_result /= Void then
	       if static_result.is_boolean then
		  out_c.put_string(once "R=(T6)(")
	       else
	          out_c.put_string(fz_26)
	       end
	       if (static_result.is_native_array
		  or else
	          (dyn_result.is_none and then
		   static_result.is_expanded))
		then
		  cast := true
		  out_c.put_string(fz_b7)
		  out_c.put_integer(static_result.id)
		  out_c.put_character(')')
		  out_c.put_character('(')
	       end
	       if dyn_result.is_expanded then
		  if static_result.is_reference then
		     assignment_handler.c_conversion_call(dyn_result,
                                                          static_result)
                     assign_call := true
		  end
               elseif static_result.is_separate then
                  assignment_handler.c_conversion_call(dyn_result,
		                                       static_result)
                  assign_call := true
	       end
	    end
	    stack_push(C_switch)
	    stack_rf.put(dyn_rf,top)
	    stack_static_rf.put(static_rf,top)
	    dyn_rf.mapping_c
	    pop
	    -- Closing section for Result:
	    if static_result /= Void then
	       if assign_call then
		  out_c.put_character(')')
	       end
	       if cast then
		  out_c.put_character(')')
		  out_c.put_character(')')
	       end
	       out_c.put_string(fz_14)
	    end
	    if need_se_tmp then
	       se_tmp_close_declaration
	    end
	 end
      end

feature

   put_proc_call_0(rf3: RUN_FEATURE_3; writable: EXPRESSION; c_name: STRING) is
	 -- To call the expanded initializer `rf3' (ie. a procedure without
	 -- arguments) using `writable' or `c_name' as target.
      require
	 rf3.current_type.is_expanded
	 rf3.arguments = Void
	 (writable /= Void) xor (c_name /= Void)
      do
	 stack_push(C_expanded_initialize)
	 stack_target.put(writable,top)
	 stack_string.put(c_name,top)
	 stack_rf.put(Void,top)
	 direct_call_count := direct_call_count + 1
	 rf3.mapping_c
	 pop
	 if call_invariant_start(rf3.current_type) then
	    put_character('&')
	    writable.compile_to_c
	    call_invariant_end
	    put_string(fz_00)
	 end
      end

feature {RUN_CLASS}

   push_create_expression(rf: RUN_FEATURE) is
      require
	 rf /= Void
      do
	 stack_push(C_create_expression)
	 stack_rf.put(rf,top)
	 direct_call_count := direct_call_count + 1
      end

feature {CREATE_TOOLS}

   push_create_instruction(rf: RUN_FEATURE; args: EFFECTIVE_ARG_LIST) is
      require
	 rf /= Void
      do
	 stack_push(C_create_instruction)
	 stack_rf.put(rf,top)
	 stack_args.put(args,top)
	 direct_call_count := direct_call_count + 1
      end

   expanded_attributes(rt: E_TYPE) is
	 -- Produce C code to initialize expanded attribute
	 -- of the new object juste created in variable "n".
      require
	 smart_eiffel.is_ready
	 rt.is_run_type
      local
	 wa: ARRAY[RUN_FEATURE]; a: RUN_FEATURE; at: E_TYPE
	 i: INTEGER; rf3: RUN_FEATURE_3
      do
	 wa := rt.run_class.writable_attributes
	 if wa /= Void then
	    from
	       i := wa.upper
	    until
	       i = 0
	    loop
	       a := wa.item(i)
	       at := a.result_type.run_type
	       if at.is_user_expanded then
		  rf3 := at.run_class.a_default_create
		  if rf3 /= Void then
		     stack_push(C_expanded_initialize)
		     stack_string.put(Void,top)
		     stack_target.put(Void,top)
		     stack_rf.put(a,top)
		     direct_call_count := direct_call_count + 1
		     rf3.mapping_c
		     pop
		  end
	       end
	       i := i - 1
	    end
	 end
      end

feature {NATIVE}

   inside_twin(cpy: RUN_FEATURE) is
      do
	 stack_push(C_inside_twin)
	 stack_rf.put(cpy,top)
	 cpy.mapping_c
	 pop
      end

feature {ASSERTION}

   check_assertion(e: EXPRESSION; tag_name: TAG_NAME) is
	 -- Produce a C boolean expression including trace code
	 -- and assertion check.
      require
	 e.result_type.is_boolean
      do
	 put_trace_or_sedb_instruction(e.start_position)
	 put_string(once "ac_")
	 put_string(check_assertion_mode)
	 put_character('(')
	 if e.is_static then
	    static_expression_count := static_expression_count + 1
	 end
	 e.compile_to_c
	 put_character(',')
	 if tag_name /= Void then
	    put_string_c(tag_name.to_string)
	 else
	    put_string(fz_null)
	 end
	 put_string(fz_14)
      end

feature {ASSERTION_LIST}

   set_check_assertion_mode(s: STRING) is
      require
	 s /= Void
      do
	 check_assertion_mode := s
      ensure
	 check_assertion_mode = s
      end

   increment_static_expression_count(increment: INTEGER) is
      do
	 static_expression_count := static_expression_count + increment
      end

feature

   put_trace_or_sedb_expression(position: POSITION) is
	 -- Writes on `out_c' an `sedb(...)' call or some `ds.p' 
	 -- update according to the ACE mode of the given `position'. 
      require
	 not ace.boost ; not position.is_unknown
      do
	 if position.sedb_trace then
	    out_c.put_string(once "sedb(&ds,")
	 else
	    out_c.put_string(once "(ds.p=")
	 end
	 put_position(position)
	 out_c.put_character(')')
      end
   
   put_trace_or_sedb_instruction(position: POSITION) is
      require
	 not ace.boost ; not position.is_unknown
      do
	 put_trace_or_sedb_expression(position)
	 out_c.put_string(fz_00)
      end
   
feature -- Numbering of inspect variables :

   inspect_incr is
      do
	 inspect_level := inspect_level + 1
      end

   inspect_decr is
      do
	 inspect_level := inspect_level - 1
      end

   put_inspect is
      do
	 put_character('z')
	 put_integer(inspect_level)
      end

feature -- Printing Current, local or argument :

   inline_level_incr is
      do
	 inline_level := inline_level + 1
      end

   inline_level_decr is
      do
	 inline_level := inline_level - 1
      end

   print_current is
      require
	 on_c
      local
	 level: INTEGER
      do
	 out_c.put_character('C')
	 level := inline_level
	 if level > 0 then
	    out_c.put_integer(level)
	 end
      end

   print_argument(rank: INTEGER) is
      require
	 on_c
      local
	 code: INTEGER
      do
	 code := ('a').code + inline_level
	 out_c.put_character(code.to_character)
	 out_c.put_integer(rank)
      end

   print_local(name: STRING) is
      require
	 on_c
      local
	 level: INTEGER
      do
	 from
	    level := inline_level + 1
	 until
	    level = 0
	 loop
	    out_c.put_character('_')
	    level := level - 1
	 end
	 out_c.put_string(name)
      end

feature {E_LOOP}

   variant_check(e: EXPRESSION) is
      require
	 e /= Void
      do
	 put_trace_or_sedb_instruction(e.start_position)
	 put_string(once "v=ac_lvc(c++,v,")
	 e.compile_to_c
	 put_string(fz_14)
      end

feature {RUN_FEATURE}

   current_class_invariant(current_type: E_TYPE) is
	 -- Add some C code to check class invariant with Current
	 -- at the end of a routine for `Current'.
      require
	 current_type.is_run_type
      local
	 rc: RUN_CLASS
      do
	 rc := need_invariant(current_type)
	 if rc /= Void then
	    if rc.current_type.is_reference then
	       out_c.put_string(once "if(se_rci(caller,C))")
	    end
	    out_c.put_string(fz_se_i)
	    out_c.put_integer(rc.id)
	    out_c.put_string(once "(&ds,C);%N")
	 end
      end

feature

   call_invariant_start(type_of_target: E_TYPE): BOOLEAN is
	 -- Start printing call of invariant only when it is needed
	 -- (`type_of_target' really has an invariant and when mode is
	 -- `-invariant_check').
	 -- When Result is true, `call_invariant_end' must be called to
	 -- finish the job.
      require
	 type_of_target.is_run_type
      local
	 rc: RUN_CLASS
      do
	 rc := need_invariant(type_of_target)
	 if rc /= Void then
	    out_c.put_string(fz_se_i)
	    out_c.put_integer(rc.id)
	    out_c.put_string(once "(&ds,")
	    Result := true
	 end
      end

   call_invariant_end is
      do
	 out_c.put_character(')')
      end

feature

   macro_def(str: STRING; id: INTEGER) is
      do
	 tmp_string.clear
	 tmp_string.extend('#')
	 tmp_string.append(fz_define)
	 tmp_string.extend(' ')
	 tmp_string.append(str)
	 tmp_string.extend(' ')
	 id.append_in(tmp_string)
	 tmp_string.extend('%N')
	 out_h.put_string(tmp_string)
      end

feature

   write_make_file is
      local
	 score: DOUBLE
      do
	 --
	 out_h.put_character('%N')
	 end_c_linkage(out_h)
	 out_h.disconnect
	 out_c.put_character('%N')
	 end_c_linkage(out_c)
	 out_c.disconnect
	 --
	 c_plus_plus_definitions
         --
         system_tools.default_c_compiler_options(false)
         --
         echo.tfw_connect(out_make,path_make)
	 if ace.no_split then
	    write_make_file_no_split
	 else
	    write_make_file_split
	 end
	 if not executable_is_up_to_date and then
	    system_tools.strip_executable(tmp_string)
	  then
	    echo_make
	 end
	 out_make.disconnect
	 if nb_errors > 0 then
	    echo.file_removing(path_make)
	 else
	    echo.put_string(once "Type inference score : ")
	    score := direct_call_count + check_id_call_count
	    score := (score / (score + switched_call_count)) * 100.0
	    echo.put_double_format(score,2)
	    echo.put_character('%%')
	    echo.put_character('%N')
	 end
      end

feature {CALL_PROC_CALL, E_AGENT}

   put_cpc(cpc: CALL_PROC_CALL) is
      local
	 target: EXPRESSION; type_of_target: E_TYPE; run_feature: RUN_FEATURE
      do
	 target := cpc.target
	 type_of_target := target.result_type.run_type
	 run_feature := cpc.run_feature
         if type_of_target.is_expanded or else
            target.is_current or else
            target.is_manifest_string
	  then
	    push_direct(run_feature,target,cpc.arguments)
	    run_feature.mapping_c
	    pop
	 else
	    push_cpc(run_feature,
		     type_of_target.run_class.run_time_set,
		     target,
		     cpc.arguments)
	 end
      end

feature

   sys_runtime_h_and_c(name: STRING) is
	 -- Inline corresponding SmartEiffel/sys/runtime/`name'.[hc]
	 -- file. (At least, one file should be found.)
      local
	 ok: BOOLEAN
      do
	 system_tools.sys_runtime(name,'h')
	 if tmp_file_read.is_connected then
	    ok := true
	    put_file(tmp_file_read,out_h)
	 end
	 system_tools.sys_runtime(name,'c')
	 if tmp_file_read.is_connected then
	    ok := true
	    put_file(tmp_file_read,out_c)
	 end
	 if not ok then
	    error_handler.append("No support found in directory sys/runtime for %"")
	    error_handler.append(name)
	    error_handler.append("%" (i.e. file(s) %"")
	    tmp_path.remove_last(1)
	    error_handler.append(tmp_path)
	    error_handler.append("[hc]%" not found).")
	    error_handler.print_as_fatal_error
	 end
      end

feature {SYSTEM_TOOLS}

   put_c_file(tfr: TEXT_FILE_READ) is
      require
	 not tfr.end_of_input
      do
	 put_file(tfr,out_c)
      ensure
	 not tfr.is_connected
      end

feature

   put_recompilation_comment(key: INTEGER) is
      do
	 out_c.put_string(fz_open_c_comment)
	 out_c.put_integer(key)
	 out_c.put_string(fz_close_c_comment)
      end

   put_recompilation_comment_in(buffer: STRING; key: INTEGER) is
      do
	 buffer.append(fz_open_c_comment)
	 key.append_in(buffer)
	 buffer.append(fz_close_c_comment)
      end

feature {COMPOUND,ASSERTION_LIST,E_LOOP,RUN_CLASS,CREATE_TOOLS}

   se_tmp_open_declaration: BOOLEAN is
	 -- True if some `se_tmpXX' temporay is needed.
      local
	 i: INTEGER; t: E_TYPE
      do
	 from
	    tmp_string.clear
	    tmp_string.extend('{')
	    i := se_tmp_list.upper
	 until
	    i < 0
	 loop
	    t := se_tmp_list.item(i)
	    if t /= Void then
	       Result := true
	       if t.is_expanded then
		  t.c_type_for_result_in(tmp_string)
	       else
		  t.c_type_for_target_in(tmp_string)
	       end
	       tmp_string.append(once " se_tmp")
	       i.append_in(tmp_string)
	       tmp_string.append(fz_00)
	    end
	    i := i - 1
	 end
	 if Result then
	    se_tmp_level := se_tmp_level + 1
	    out_c.put_string(tmp_string)
	 end
      end

   se_tmp_close_declaration is
      do
	 check
	    se_tmp_level > 0
	 end
	 se_tmp_level := se_tmp_level - 1
	 out_c.put_string(fz_12)
	 if se_tmp_level = 0 then
	    se_tmp_list.clear
	 end
      end

feature {RUN_FEATURE}

   se_tmp_register(t: E_TYPE) is
      require
	 (t.is_expanded and not t.is_dummy_expanded)
	 or else
	  t.is_separate
      do
	 se_tmp_list.add_last(t)
      end

   se_tmp_open_expanded(t: E_TYPE): INTEGER is
	 -- The `Result' is the index of the `se_tmp' variable, because this
	 -- variable may be used more than once. Result >= 0 implies that
	 -- a temporary variable is used and thus that 
	 -- `se_tmp_close_expanded' must be called. Result < 0 indicate that 
	 -- `t' is not registered.
      local
	 stop: BOOLEAN; t2: E_TYPE; rtm1: STRING
      do
	 from
	    Result := se_tmp_list.upper
	    rtm1 := t.run_time_mark
	 until
	    stop
	 loop
	    if Result < 0 then
	       stop := true
	    else
	       t2 := se_tmp_list.item(Result)
	       if t2 /= Void and then rtm1 = t2.run_time_mark then
		  stop := true
		  se_tmp_list.put(Void,Result)
		  out_c.put_string(once "(*(/*expanded*/se_tmp")
		  out_c.put_integer(Result)
		  out_c.put_character('=')
	       else
		  Result := Result - 1
	       end
	    end
	 end
      end

   se_tmp_close_expanded(se_tmp_idx: INTEGER) is
	 -- Assume `se_tmp_idx' is the value obtained with 
	 -- `se_tmp_open_expanded'.
      require
	 se_tmp_idx >= 0
      do
	 check -- Obtained with `se_tmp_open_expanded':
	    se_tmp_list.item(se_tmp_idx) = Void
	 end
	 out_c.put_character(',')
	 out_c.put_character('&')
	 out_c.put_string(once "se_tmp")
	 out_c.put_integer(se_tmp_idx)
	 out_c.put_character(')')
	 out_c.put_character(')')
      end

   se_tmp_open_separate(t: E_TYPE): INTEGER is
	 -- The `Result' is the index of the `se_tmp' variable, because this
	 -- variable may be used more than once. Result >= 0 implies that
	 -- a temporary variable is used and thus that 
	 -- `se_tmp_close_separate' must be called. Result < 0 indicate that 
	 -- `t' is not registered.
      require
	 t.is_separate
      local
	 stop: BOOLEAN
      do
	 from
	    Result := se_tmp_list.upper
	 until
	    stop
	 loop
	    if Result < 0 then
	       stop := true
	    elseif t = se_tmp_list.item(Result) then
	       stop := true
	       se_tmp_list.put(Void,Result)
	       out_c.put_string(once "(((void)(/*separate*/se_tmp")
	       out_c.put_integer(Result)
	       out_c.put_character('=')
	       put_target_as_target
	       out_c.put_string(once ")),")
	    else
	       Result := Result - 1
	    end
	 end
      end

   se_tmp_close_separate(se_tmp_idx: INTEGER) is
	 -- Assume `se_tmp_idx' is the value obtained with 
	 -- `se_tmp_open_separate'.
      require
	 se_tmp_idx >= 0
      do
	 check -- Obtained with `se_tmp_open_separate':
	    se_tmp_list.item(se_tmp_idx) = Void
	 end
	 out_c.put_character(')')
      end

feature {BIT_CONSTANT}

   register_bit_constant(bc: BIT_CONSTANT) is
      require
	 bc.result_type.is_c_unsigned_ptr
      do
	 if bit_constant_pool = void then
	    !!bit_constant_pool.with_capacity(4)
	 end
	 bit_constant_pool.add_last(bc)
	 out_c.put_string(fz_se_bit_constant)
	 out_c.put_integer(bit_constant_pool.upper)
      end

   bit_constant_definition is
      local
	 i: INTEGER
	 bc: BIT_CONSTANT
	 type_bit: TYPE_BIT
      do
	 if bit_constant_pool /= Void then
	    from
	       i := bit_constant_pool.upper
	    until
	       i < 0
	    loop
	       tmp_string.clear
	       bc := bit_constant_pool.item(i)
	       type_bit := bc.result_type
	       tmp_string.clear
	       type_bit.c_type_for_argument_in(tmp_string)
	       tmp_string.extend(' ')
	       tmp_string.append(fz_se_bit_constant)
	       i.append_in(tmp_string)
	       put_extern7(tmp_string)
	       out_c.put_character('{')
	       bc.c_define
	       out_c.put_character('}')
	       out_c.put_character(';')
	       out_c.put_character('%N')
	       i := i - 1
	    end
	 end
      end

feature {NATIVE}

   include_register(origin: POSITION; include_name: STRING) is
      do
	 if include_memory = Void then
	    create include_memory.make
	 end
	 if not include_memory.has(include_name) then
	    include_memory.add(include_name)
	    put_position_comment_on(out_h,origin)
	    add_include_on(out_h,include_name)
	    put_position_comment_on(out_h,origin)
	 end
      end

feature {NATIVE_C_PLUS_PLUS}

   c_plus_plus_register(native: NATIVE_C_PLUS_PLUS) is
      do
	 if c_plus_plus = Void then
	    !!c_plus_plus.with_capacity(64)
	 end
	 c_plus_plus.add_last(native)
      end

   add_include(include: STRING) is
      do
	 add_include_on(out_h,include)
      end

   add_include_on(output: TEXT_FILE_WRITE; include: STRING) is
      do
	 end_c_linkage (output)
	 output.put_string(once "#include ")
	 inspect
	    include.first
	 when '%"', '<' then
	 else
	    output.put_character('%"')
	 end
	 output.put_string(include)
	 inspect
	    include.last
	 when '%"', '>' then
	 else
	    output.put_character('%"')
	 end
	 output.put_character('%N')
	 begin_c_linkage (output)
      end

feature {RUN_FEATURE_2}

   attribute_read_removal(up_rf: RUN_FEATURE
			  run_time_set: RUN_TIME_SET): BOOLEAN is
      require
	 smart_eiffel.is_ready
	 run_time_set.count > 1
      local
	 rf2a, rf2b: RUN_FEATURE_2; offseta, offsetb: INTEGER
	 rta, rtb: E_TYPE; i: INTEGER; rc: RUN_CLASS
      do
	 from
	    Result := true
	    i := run_time_set.count
	 until
	    not Result or else i = 0
	 loop
	    rc := run_time_set.item(i)
	    rf2b ?= rc.dynamic(up_rf)
	    if rf2b /= Void then
	       offsetb := rc.offset_of(rf2b)
	    end
	    if rf2a = Void then
	       rf2a := rf2b
	       offseta := offsetb
	    end
	    if rf2b = Void then
	       Result := false
	    else
	       Result := offseta = offsetb
	       if Result then
		  rta := rf2a.result_type.run_type
		  rtb := rf2b.result_type.run_type
		  if rta.is_reference then
		     Result := rtb.is_reference
		  elseif rta.run_time_mark = rtb.run_time_mark then
		  elseif rta.is_native_array then
		     if rta.generic_list.first.is_reference then
			Result := rtb.generic_list.first.is_reference
		     end
		  else
		     Result := false
		  end
	       end
	    end
	    i := i - 1
	 end
      end

feature {NONE}

   stupid_switch(up_rf: RUN_FEATURE): BOOLEAN is
      require
	 smart_eiffel.is_ready
	 up_rf.run_class.run_time_set.count >= 1
      local
	 run_time_set: RUN_TIME_SET
      do
	 run_time_set := up_rf.run_class.run_time_set
	 if run_time_set.count > 1 then
	    smart_eiffel.push(up_rf)
	    Result := stupid_switch_n(up_rf,run_time_set)
	    smart_eiffel.pop
	 else
	    Result := true
	 end
      end

   stupid_switch_n(up_rf: RUN_FEATURE; run_time_set: RUN_TIME_SET): BOOLEAN is
      require
	 smart_eiffel.is_ready
	 smart_eiffel.top_rf = up_rf
	 run_time_set.count > 1
      local
	 stupid: STRING
      do
	 if smart_eiffel.same_base_feature(up_rf,run_time_set) then
	    stupid := up_rf.stupid_switch(run_time_set)
	    if stupid /= Void then
	       put_comment(stupid)
	       Result := true
	    end
	 else
	    Result := attribute_read_removal(up_rf,run_time_set)
	    if Result then
	       put_comment(once "SSWA2")
	    end
	 end
      end

   c_plus_plus: FIXED_ARRAY[NATIVE_C_PLUS_PLUS]

   begin_c_linkage (output: TEXT_FILE_WRITE) is
		 -- Begin wrap for C linkage
      do
	 output.put_string (once "#ifdef __cplusplus%Nextern %"C%" {%N#endif%N")
      end

   end_c_linkage (output: TEXT_FILE_WRITE) is
		 -- End wrap for C linkage
      do
	 output.put_string (once "#ifdef __cplusplus%N}%N#endif%N")
      end

   c_plus_plus_definitions is
      local
	 cpp_path_h, cpp_path_c: STRING
	 i: INTEGER
	 no_split_save: BOOLEAN
      do
	 if c_plus_plus /= Void then
	    no_split_save := ace.no_split
	    ace.set_no_split(true)
	    echo.put_string(once "C++ external definitions.%N")
	    cpp_path_h := system_tools.path_h.twin
	    cpp_path_h.remove_last(2)
	    cpp_path_h.append(once "_external_cpp")
	    cpp_path_c := cpp_path_h.twin
	    cpp_path_h.append(h_suffix)
	    cpp_path_c.append(c_plus_plus_suffix)
	    echo.tfw_connect(out_h,cpp_path_h)
	    echo.tfw_connect(out_c,cpp_path_c)
	    begin_c_linkage (out_c)
	    begin_c_linkage (out_h)
	    add_first_include(cpp_path_h)
	    system_tools.add_c_plus_plus_file(cpp_path_c)
	    sys_runtime_h_and_c(once "c_plus_plus")
	    if c_plus_plus /= Void then
	       from
		  i := c_plus_plus.upper
	       until
		  i < 0
	       loop
		  c_plus_plus.item(i).c_plus_plus_definition
		  i := i - 1
	       end
	    end
	    end_c_linkage (out_c)
	    end_c_linkage (out_h)
	    out_h.disconnect
	    out_c.disconnect
	    ace.set_no_split(no_split_save)
	 end
      end

   echo_make is
      do
	 out_make.put_string(tmp_string)
	 out_make.put_character('%N')
      end

   out_c: TEXT_FILE_WRITE is
	 -- The current *.c output file.
      once
	 !!Result.make
      end

   out_h: TEXT_FILE_WRITE
	 -- The *.h output file.

   current_out: TEXT_FILE_WRITE
	 -- Is `out_c' or `out_h'.

   out_make: TEXT_FILE_WRITE is
	 -- The *.make output file.
      once
	 !!Result.make
      end

   no_args_to_eval: BOOLEAN is
	 -- True if there is no C code to produce to eval arguments.
	 -- For example because there are  no arguments or because
	 -- we are inside a switching function for example.
      require
	 smart_eiffel.is_ready
      local
	 code: INTEGER
	 args: EFFECTIVE_ARG_LIST
      do
	 code := stack_code.item(top)
	 inspect
	    code
	 when C_direct_call, C_check_id, C_create_instruction, C_same_target
	  then
	    args := stack_args.item(top)
	    if args = Void then
	       Result := true
	    else
	       Result := args.can_be_dropped
	    end
	 when C_inline_dca then
	    top := top - 1
	    Result := no_args_to_eval
	    top := top + 1
	 else
	    Result := true
	 end
      end

   c_inline_h_mem: FIXED_ARRAY[STRING] is
      once
	 !!Result.with_capacity(4)
      end

   se_evobt(rf: RUN_FEATURE; target: EXPRESSION) is
      require
	 rf /= Void
	 target /= Void
	 on_c
      local
	 rt: E_TYPE; p: POSITION
      do
	 sure_void_count := sure_void_count + 1
	 rt := rf.result_type
	 if rt /= Void then
	    if rt.is_reference then
	       -- Because of a Borland C compiler bug we have to add
	       -- this extra cast:
	       out_c.put_string(once "(T0*)")
	    end
	    out_c.put_character('(')
	 end
	 if ace.no_check then
	    out_c.put_string(once "se_evobt")
	    out_c.put_character('(')
	    target.compile_to_c
	    out_c.put_character(',')
	    put_position(target.start_position)
	    out_c.put_character(')')
	 else
	    out_c.put_string(once "/*se_evobt*/")
	    p := target.start_position
	    put_position_comment_on(out_c,p)
	    target.compile_to_c
	    out_c.put_character(',')
	    exceptions_handler.se_evobt
	 end
	 if rt /= Void then
	    out_c.put_character(',')
	    if rt.is_reference then
	       rt.c_initialize
	    else
	       out_c.put_character('M')
	       out_c.put_integer(rt.id)
	    end
	    out_c.put_character(')')
	 end
	 if rt = Void then
	    out_c.put_character(';')
	    out_c.put_character('%N')
	 end
      end

   push_check(rf: RUN_FEATURE; t: EXPRESSION; args: EFFECTIVE_ARG_LIST) is
      require
	 rf /= Void; t /= Void
      do
	 stack_push(C_check_id)
	 stack_rf.put(rf,top)
	 stack_target.put(t,top)
	 stack_args.put(args,top)
      end

   use_switch(up_rf: RUN_FEATURE; run_time_set: RUN_TIME_SET
	      t: EXPRESSION; args: EFFECTIVE_ARG_LIST) is
      require
	 up_rf.run_class.run_time_set = run_time_set
	 run_time_set.count > 1
	 t /= Void
	 on_c
      local
	 rt: E_TYPE; rc: RUN_CLASS; rf: RUN_FEATURE
	 switch: SWITCH; se_tmp_idx: INTEGER; cast: BOOLEAN
      do
	 rt := up_rf.result_type
	 if ace.boost and then stupid_switch(up_rf) then
	    stupid_switch_call_count := stupid_switch_call_count + 1
	    switch_collection.remove(up_rf)
	    out_c.put_string(fz_open_c_comment)
	    out_c.put_character('X')
	    out_c.put_integer(up_rf.current_type.id)
	    out_c.put_string(up_rf.name.to_string)
	    out_c.put_string(fz_close_c_comment)
	    if rt /= Void and then rt.run_type.is_native_array then
	       cast := true
	       out_c.put_string(fz_b7)
	       out_c.put_integer(rt.id)
	       out_c.put_character(')')
	       out_c.put_character('(')
	    end
	    rc := run_time_set.item(1)
	    rf := rc.dynamic(up_rf)
	    push_direct(rf,t,args)
	    rf.mapping_c
	    pop
	    if cast then
	       out_c.put_character(')')
	       out_c.put_character(')')
	    end
	 else
	    switched_call_count := switched_call_count + 1
	    if rt /= Void then
	       se_tmp_idx := se_tmp_open_expanded(rt)
	       -- Because the result of the dispatch function may be 
	       -- a complex expanded.
	    end
	    out_c.put_string(switch.name(up_rf))
	    out_c.put_character('(')
	    if ace.no_check then
	       out_c.put_string(fz_85)
	       put_position(t.start_position)
	       out_c.put_character(',')
	    end
	    t.compile_to_c
	    if args /= Void then
	       out_c.put_character(',')
	       args.compile_to_c(up_rf.arguments)
	    end
	    put_character(')')
	    if rt = Void then
	       out_c.put_string(fz_00)
	    elseif se_tmp_idx >= 0 then
	       se_tmp_close_expanded(se_tmp_idx)
	    end
	 end
      end

   define_initialize_eiffel_runtime(rf3: RUN_FEATURE_3) is
      require
	 on_c
	 rf3.is_root
      local
	 no_check: BOOLEAN; rc: RUN_CLASS; ct: E_TYPE; atexit: RUN_FEATURE
      do
	 no_check := ace.no_check
	 ct := rf3.current_type
	 rc := rf3.run_class
	 echo.put_string(once "Define initialize stuff.%N")
	 smart_eiffel.define_extern_tables
	 atexit := once_routine_pool.std_output_flush_atexit
	 if atexit /= Void then
	    put_c_heading(once "void std_output_flush(void)")
	    out_c.put_string(once "void*C=(void*)oBC")
	    out_c.put_integer(id_provider.item(as_general))
	    out_c.put_string(once "std_output;%N")
	    if no_check then
	       out_c.put_string(
		   "[
                 se_frame_descriptor fd={"<atexit-wrapper>",0,0,"",1};
                 se_dump_stack ds;
                 ds.fd=&fd;
                 ds.p=0;
                 ds.caller=NULL;
                    ]")
	    end
	    stack_push(C_switch)
	    stack_rf.put(atexit,top)
	    if ace.sedb then
	       -- calling eiffel function flush would result in runing 
	       -- sedb again whereas user said he want to exit.
	       out_c.put_string("if (sedb_status != SEDB_EXIT_MODE) ")
	    end
	    atexit.mapping_c
	    pop
	    out_c.put_string(once "}%N")
	 end
	 put_c_heading(once
	        "void initialize_eiffel_runtime(int argc,char*argv[])")
	 if smart_eiffel.scoop then
            out_c.put_string(once "init_scoop_thread();%N")
            out_c.put_string(once
	     "se_init_separate_root(SE_SCOOP_THREAD_TYPE, %"<root>%");%N{%N")
         end
         if no_check then
            if smart_eiffel.scoop then
               out_c.put_string(once
	        "se_subsystem_t* self = se_current_subsystem_thread();%N")
            end
	    out_c.put_string(
               once "[
                se_frame_descriptor irfd={"Initializing runtime.",0,0,"",1};
                se_dump_stack ds = {NULL,NULL,0,NULL,NULL};
                ds.fd=&irfd;
                     ]")
	    rf3.c_set_dump_stack_top(once "&ds", fz_link)
	 end
	 out_c.put_string(once "se_argc=argc;%Nse_argv=argv;%N")
	 if atexit /= Void then
	    out_c.put_string(once "atexit(std_output_flush);%N")
	 end
	 gc_handler.initialize_runtime
	 exceptions_handler.initialize_runtime
	 if no_check then
	    smart_eiffel.initialize_path_table
	 end
	 if smart_eiffel.generator_used then
	    smart_eiffel.initialize_generator
	 end
	 if smart_eiffel.generating_type_used then
	    smart_eiffel.initialize_generating_type
	 end
	 if not exceptions_handler.used then
	    out_c.put_string(once "[
               #ifdef SIGINT
               signal(SIGINT,se_signal_handler);
               #endif
               #ifdef SIGQUIT
               signal(SIGQUIT,se_signal_handler);
               #endif
               #ifdef SIGTERM
               signal(SIGTERM,se_signal_handler);
               #endif
               #ifdef SIGBREAK
               signal(SIGBREAK,se_signal_handler);
               #endif
               #ifdef SIGKILL
               signal(SIGKILL,se_signal_handler);
               #endif

                                    ]")
	 end
	 once_manifest_string_pool.c_call_initialize
	 once_routine_pool.c_pre_compute
	 if ace.sedb then
	    out_c.put_string(once "se_general_trace_switch=1;%N")
	 end
	 if not gc_handler.is_off then
	    out_c.put_string(fz_48)
	 end
	 out_c.put_string(once "{%N")
	 gc_handler.declare_allocate_n(rc)
	 out_c.put_string(once "eiffel_root_object=n;%N}%N")
	 if ace.no_check then
	    rf3.c_set_dump_stack_top(fz_null, fz_unlink)
	 end
	 out_c.put_string(fz_12)
         if smart_eiffel.scoop then
            out_c.put_string(fz_12)
         end
      ensure
	 on_c
      end

   check_assertion_mode: STRING

   inspect_level: INTEGER

   inline_level: INTEGER

   check_id(e: EXPRESSION; id: INTEGER) is
	 -- Produce a C expression checking that `e' is not void and
	 -- that `e' is really of type `id'.
	 -- The result of the C expression is the pointer to the
	 -- corresponding Object.
      require
	 e.result_type.run_type.is_reference
	 id > 0
      do
	 if ace.no_check then
	    put_string(once "((T")
	    put_integer(id)
	    put_string(once "*)ci(")
	    put_integer(id)
	    put_character(',')
	    e.compile_to_c
	    put_character(',')
	    put_position(e.start_position)
	    put_string(fz_13)
	    check_id_call_count := check_id_call_count + 1
	 else
	    e.compile_to_c
	    direct_call_count := direct_call_count + 1
	 end
      end

   tmp_string: STRING is
      once
	 !!Result.make(256)
      end

   tmp_string2: STRING is
      once
	 !!Result.make(128)
      end

   tmp_string3: STRING is
      once
	 !!Result.make(128)
      end

   need_invariant(type_of_target: E_TYPE): RUN_CLASS is
	 -- Give the good RUN_CLASS when `type_of_target' need some
	 -- class invariant checking.
      require
	 type_of_target.is_run_type
      do
	 Result := type_of_target.run_type.run_class
	 if Result.at_run_time and then
	    Result.class_invariant /= Void then
	 else
	    Result := Void
	 end
      end

   split_count: INTEGER
	 -- Number of *.c files.

   path_h: STRING is
      once
	 Result := system_tools.path_h
      ensure
	 Result.has_suffix(h_suffix)
      end

   path_c: STRING is
      once
	 if ace.no_split then
	    Result := path_h.twin
	    Result.remove_last(1)
	    Result.extend('c')
	 else
	    split_count := 1
	    !!Result.make(path_h.count + 4)
	    path_c_in(Result,split_count)
	 end
      ensure
	 Result.has_suffix(c_suffix)
      end

   path_make: STRING is
      once
	 Result := path_h.twin
	 Result.remove_last(2)
	 Result.append(system_tools.make_suffix)
      ensure
	 Result.has_suffix(system_tools.make_suffix)
      end

   add_first_include(the_first_include: STRING) is
      do
	 put_banner(out_c)
	 add_include_on(out_c,the_first_include)
      end

   put_banner(output: TEXT_FILE_WRITE) is
      require
	 output.is_connected
      do
	 output.put_string(once "/*%NANSI C code generated by ")
	 output.put_string(smart_eiffel.copyright)
	 output.put_string(once "C Compiler options used: ")
	 output.put_string(system_tools.c_compiler_options)
	 output.put_string(once "%N*/%N")
      end

   c_code_saved: BOOLEAN

   get_inline_ms: MANIFEST_STRING is
      local
	 e, o: EXPRESSION
         i: IMPLICIT_CAST
      do
	 e := stack_args.item(top).expression(1)
         if e.is_manifest_string then
            Result ?= e
            if Result = Void then
               i ?= e
               if i /= Void then
                  o := i.original_expression
                  Result ?= o
               end
            end
         end
         if Result = Void then
            error_handler.add_position(e.start_position)
            fatal_error("Bad usage of C inlining (argument%
                        % is not a manifest string).")
	 end
      end

   backup_tfw_connect(sfw: TEXT_FILE_WRITE; c_path: STRING) is
      require
	 not ace.no_split
      do
	 tmp_path.copy(c_path)
	 tmp_path.remove_last(2)
	 tmp_path.append(system_tools.object_suffix)
	 if file_exists(tmp_path) then
	    if file_exists(c_path) then
	       c_path.put('d',c_path.count)
	    end
	 end
	 echo.tfw_connect(sfw,c_path)
      end

   path_c_in(str: STRING; number: INTEGER) is
      do
	 str.clear
	 str.append(path_h)
	 str.remove_last(2)
	 number.append_in(str)
	 str.extend('.')
	 str.extend('c')
      end

   write_make_file_split is
      require
	 not ace.no_split
      local
	 i: INTEGER
	 no_change, recompile: BOOLEAN
	 executable_name: STRING
      do
	 from
	    no_change := true
	    i := split_count
	 until
	    i = 0
	 loop
	    recompile := true
	    path_c_in(tmp_path,i)
	    tmp_string.copy(tmp_path)
	    tmp_string.put('d',tmp_string.count)
	    if file_exists(tmp_string) then
	       if file_tools.same_files(tmp_path,tmp_string) then
		  echo.put_string(fz_01)
		  echo.put_string(tmp_path)
		  echo.put_string(once "%" not changed.%N")
		  echo.file_removing(tmp_string)
		  recompile := false
	       else
		  echo.file_renaming(tmp_string,tmp_path)
	       end
	    end
	    if recompile then
	       tmp_string2.copy(path_h)
	       tmp_string2.remove_last(2)
	       i.append_in(tmp_string2)
	       tmp_string2.extend('.')
	       tmp_string2.extend('c')
	       system_tools.split_mode_c_compiler_command(tmp_string,
							  tmp_string2)
	       echo_make
	       no_change := false
	    end
	    i := i - 1
	 end
	 executable_name := ace.executable_name
	 if no_change and then executable_name /= Void then
	    no_change := file_exists(executable_name)
	 else
	    no_change := false
	 end
	 if no_change and then not system_tools.is_linking_mandatory then
	    executable_is_up_to_date := true
	    echo.put_string(once "Executable is up-to-date %
			    %(no C compilation, no linking done).%N")
	 else
	    tmp_string2.copy(path_h)
	    tmp_string2.remove_last(2)
	    system_tools.split_mode_linker_command(tmp_string,
						   tmp_string2,split_count)
	    echo_make
	 end
      end

   executable_is_up_to_date: BOOLEAN
	 -- When the executable seems to be already correct (no C
	 -- compilation and no linking is to be done).

   write_make_file_no_split is
      require
	 ace.no_split
      do
	 system_tools.no_split_mode_command(tmp_string,path_c)
	 echo_make
      end

   common_put_target is
      local
	 rf: RUN_FEATURE; flag: BOOLEAN; e: EXPRESSION; ct: E_TYPE
	 c_name: STRING; unwrap_buffer: STRING; mem_id: INTEGER
      do
	 inspect
	    stack_code.item(top)
	 when C_inside_twin then
	    rf := stack_rf.item(top)
	    ct := rf.current_type
	    if ct.is_reference then
	       out_c.put_character('(')
	       ct.mapping_cast
	       out_c.put_character('R')
	       out_c.put_character(')')
	    else
	       out_c.put_character('&')
	       out_c.put_character('R')
	    end
	 when C_create_instruction, C_create_expression then
	    out_c.put_character('n')
	 when C_switch then
	    rf := stack_rf.item(top)
	    flag := call_invariant_start(rf.current_type)
	    out_c.put_string(once "((T")
	    out_c.put_integer(rf.id)
	    out_c.put_string(once "*)C)")
	    if flag then
	       call_invariant_end
	    end
	 when C_expanded_initialize then
	    out_c.put_character('&')
	    e := stack_target.item(top)
	    if e /= Void then
	       e.compile_to_c
	    else
	       c_name := stack_string.item(top)
	       if c_name /= Void then
		  out_c.put_string(c_name)
	       else
		  out_c.put_string(once "n->_")
		  out_c.put_string(stack_rf.item(top).name.to_string)
	       end
	    end
	 when C_inline_one_pc then
	    print_current
	 when C_precursor then
	    out_c.put_character('C')
	 when C_scoop_wrapper then
	    out_c.put_string(once "C->ref")
	 when C_scoop_unwrapper then
	    mem_id := stack_rf.item(top).id
	    unwrap_buffer := once "                "
	    unwrap_buffer.clear
            unwrap_buffer.append(once "((T")
            mem_id.append_in(unwrap_buffer)
            unwrap_buffer.append(once "*)((Tw")
            mem_id.append_in(unwrap_buffer)
            stack_rf.item(top).name.mapping_c_in(unwrap_buffer)
            unwrap_buffer.append(once "*)data)->C)")
	    out_c.put_string(unwrap_buffer)
	 end
      end

   put_file(tfr: TEXT_FILE_READ; output: TEXT_FILE_WRITE) is
      require
	 not tfr.end_of_input
      do
	 from
	    tfr.read_character
	 until
	    tfr.end_of_input
	 loop
	    output.put_character(tfr.last_character)
	    tfr.read_character
	 end
	 tfr.disconnect
      ensure
	 not tfr.is_connected
      end

   really_define_c_main(rf3: RUN_FEATURE_3) is
      require
	 not ace.no_main
      local
	 id: INTEGER; rc: RUN_CLASS; ct: E_TYPE; od: BOOLEAN
      do
	 echo.put_string(once "Define C main function.%N")
	 ct := rf3.current_type
	 rc := rf3.run_class
	 id := rc.id
	 system_tools.put_c_main_function_type(out_c)
	 out_c.put_string(once " main(int argc,char*argv[]){%N%
			  %initialize_eiffel_runtime(argc,argv);%N")
	 out_c.put_string(once "{T")
	 out_c.put_integer(id)
	 out_c.put_string(once "*n=eiffel_root_object;%N")
         if smart_eiffel.scoop then
	    out_c.put_string(once "se_subsystem_t* self = n->subsystem;%N")
         end
	 if ace.no_check then
	    out_c.put_string(once "se_frame_descriptor root={%"System root.%",1,0,%"")
	    tmp_string.clear
	    ct.c_frame_descriptor_in(tmp_string)
	    out_c.put_string(tmp_string)
	    out_c.put_string(once "%",1};%N%
			       %se_dump_stack ds;%N%
			       %ds.fd=&root;%N%
			       %ds.current=((void**)(&n));%N")
	    put_position_in_ds(rf3.start_position)
	    out_c.put_string(once "ds.caller=NULL;%N")
            if smart_eiffel.scoop then
               out_c.put_string(once "(void)(self->vft.get_dst_and_lock(self));%N%
                                     %self->vft.set_dst_and_unlock(self,&ds);/*link*/%N")
            else
               out_c.put_string(once "se_dst=&ds;/*link*/%N")
            end
	 end
	 expanded_attributes(ct)
	 push_create_instruction(rf3,Void)
         od := se_tmp_open_declaration
         if od then
            out_c.put_string(once "se_subsystem_t* self=se_current_subsystem_thread();%N")
         end
	 rf3.mapping_c_root
         if od then
            se_tmp_close_declaration
         end
	 pop
	 if rc.class_invariant /= Void then
	    out_c.put_string(fz_se_i)
	    out_c.put_integer(id)
	    out_c.put_string(once "(&ds,n);%N")
	 end
	 gc_handler.gc_info_before_exit
         if ace.no_check then
            if smart_eiffel.scoop then
               out_c.put_string(once "(void)(self->vft.get_dst_and_lock(self));%N%
                                     %self->vft.set_dst_and_unlock(self,NULL);/*unlink*/%N")
            else
               out_c.put_string(once "se_dst=NULL;/*unlink*/%N")
            end
         end
	 system_tools.put_c_main_function_exit(out_c)
      end

   bit_constant_pool: FIXED_ARRAY[BIT_CONSTANT]

   fz_se_bit_constant: STRING is "se_bit_constant"

   se_tmp_level: INTEGER

   se_tmp_list: FIXED_ARRAY[E_TYPE] is
      once
	 create Result.with_capacity(4)
      end

   fz_base: STRING is "base"

   bunch_counter, bunch_size: INTEGER

   split_c_file_now(new_bunch_size: INTEGER) is
      do
	 split_count := split_count + 1
	 out_c.put_character('%N')
	 out_c.disconnect
	 path_c_in(path_c,split_count)
	 backup_tfw_connect(out_c,path_c)
	 add_first_include(path_h)
	 if current_out /= out_h then
	    current_out := out_c
	 end
	 bunch_counter := 1
	 bunch_size := new_bunch_size
      end

   include_memory: SET[STRING]

   put_position_comment_on(output: TEXT_FILE_WRITE; p: POSITION) is
      local
	 i: INTEGER; path: STRING; stop: BOOLEAN
      do
	 if p.is_unknown then
	    output.put_string(once "/*unknown position*/")
	 else
	    output.put_string(fz_open_c_comment)
	    output.put_character('l')
	    output.put_integer(p.line)
	    output.put_character('c')
	    output.put_integer(p.column)
	    path := p.path
	    from
	       i := path.count
	    until
	       stop
	    loop
	       if i <= 1 then
		  output.put_character(' ')
		  stop := true
	       else
		  inspect
		     path.item(i)
		  when '/', '\' then
		     stop := true
		  else
		     i := i - 1
		  end
	       end
	    end
	    from until
	       i > path.count
	    loop
	       output.put_character(path.item(i))
	       i := i + 1
	    end
	    output.put_string(fz_close_c_comment)
	 end
      end
   
end -- C_PRETTY_PRINTER
