CECIL: using Eiffel from other languages

Eiffel Power (TM) from ISE

How to run a CECIL program

1 - Using CECIL

2 - Compiling your Eiffel system for CECIL

3 -Building a CECIL archive

4 - Using a CECIL archive

4.1 - Linking the CECIL archive into a program

4.2 - Initializing the Eiffel 4 run-time

5 - Restrictions

6 - Notes

Overview of the CECIL Interface

1 - Eiffel basic types

1.1 - More about EIF_OBJECT, EIF_REFERENCE, and basic expanded types

Back to index

2 - Protecting the Eiffel objects

Back to index

2.1 - Eiffel objects passed in a C external

Back to index

2.2 - Accessing the direct reference to an Eiffel object: eif_access

2.3 - Keeping a reference from C after an external call: eif_adopt

3 - Other CECIL functions:

3.1 - Creating Eiffel objects from C: eif_create

3.2 - Protecting the objects returned by Eiffel functions.

3.3 - Getting the type id of an Eiffel type: eif_type_id

 3.4 - Getting the type id of a generic type : eif_generic_type.

    Obsolete: see eif_type_id

3.5 - Raising an eiffel panic: eif_panic.

        # include "eif_except.h"

         void eif_panic(char *msg)

       #include "eif_threads.h"

         void eif_thr_panic (char *msg)

        Raise an Eiffel panic with Eiffel exception trace with message msg . In MT mode, use eif_thr_panic instead.

        Example.

        Back to index

3.6 - Releasing an Eiffel indirection pointer: eif_wean

        # include "eif_hector.h"

        EIF_REFERENCE eif_wean(EIF_OBJECT object)   

        Tells the GC to remove the artificial reference to the nested Eiffel reference returned by eif_access (object). Then, the GC will be able collect this nested object, as soon as it is not referenced from Eiffel any longer.
    Note that object must be previously created with eif_adopt, eif_protect or eif_create.
    eif_wean (object) returns an Eiffel reference, which corresponds to eif_access (object). After a call to eif_wean (object), eif_access (object) is NULL, which does not mean that the nested Eiffel object is Void, but that the indirection pointer does not reference it any longer. It is possible to reuse object later on.
    Calling eif_wean (external_argument) where external_argument is an Eiffel object given by a C external can cause erratic behaviors. Indeed, external_argument is an indirection pointer, which is automatically deleted after the external call (not the nested Eiffel object), deleting it prematuraly can corrupt the indirection pointers stack.
    See also eif_access.

    Example: C external returning an Eiffel string.

    In Eiffel:
        foo : STRING is
            external
               "C | %"a file.h%""
            end
    In C:

        EIF_REFERENCE foo () {
            EIF_REFERENCE str;
            EIF_OBJECT i_str;
            str = eif_string ("Hello world");
            i_str = eif_protect(str);
            /* Some operations on `i_str' */
            return eif_wean (i_str);    /* Returns direct reference to the Eiffel string.
                                                          * No need to keep an extra reference from the C. */

        }

    Back to index

3.7 - Getting the attribute from an Eiffel object: eif_attribute

         # include "eif_cecil.h"

        EIFFEL_TYPE eif_attribute (EIF_REFERENCE object, char *name, EIFFEL_TYPE, int *status)

    Return the attribute of an Eiffel object.

    The `eif_attribute' macro returns the attribute of object of name name, which is of type EIFFEL_TYPE.

    EIFFEL_TYPE is the type of the Eiffel attribute. It can be: EIF_INTEGER, EIF_POINTER, EIF_CHARACTER, EIF_BOOLEAN, EIF_DOUBLE, EIF_REAL or EIF_REFERENCE.

    If status is NULL then no status is set. Otherwise the status of the function is put in *status:
    *status = EIF_NO_ATTRIBUTE => no attribute found.
    *status = EIF_CECIL_OK => attribute found.
    *status = EIF_CECIL_ERROR => an undefined error occured, object may be invalid.

    If the visible exception is enabled, then a visible exception is raised upon failure (EIF_NO_ATTRIBUTE, EIF_CECIL_ERROR).

    RETURN VALUE:

      upon failure, it returns (EIFFEL_TYPE) 0, otherwise, the attribute is returned. If the return value is not a basic types, you must protect it with eif_protect

    COMPATIBILITY:

      eif_attribute (object, name, type, NULL) is equivalent to eif_field (object, name, type)

    NOTE:

      you cannot access a constant attribute, or the result of a function (once or not) with eif_attribute.

    OTHER:

      EIF_BOOLEAN attribute_exists (EIF_REFERENCE object, char *name) returns EIF_TRUE or EIF_FALSE depending if the attribute exists or not, is visible or not.

    See also eif_procedure, eif_xx_function.

        Example

    Back to index

3.8 - Getting the address of an Eiffel routine

        #include "eif_cecil.h"
     

       
        EIF_PROCEDURE eif_procedure (char *rout_name, EIF_TYPE_ID type_id)
        EIF_REFERENCE_FUNCTION eif_reference_function (char *rout_name, EIF_TYPE_ID type_id)
        EIF_INTEGER_FUNCTION eif_integer_function (char *rout_name, EIF_TYPE_ID type_id)
        EIF_CHARACTER_FUNCTION eif_character_function (char *rout_name, EIF_TYPE_ID type_id)
        EIF_REAL_FUNCTION eif_real_function (char *rout_name, EIF_TYPE_ID type_id)
        EIF_DOUBLE_FUNCTION eif_double_function (char *rput_name, EIF_TYPE_ID type_id)
        EIF_BIT_FUNCTION eif_bit_function (char *rout_name, EIF_TYPE_ID type_id)
        EIF_BOOLEAN_FUNCTION eif_boolean_function (char *rout_name, EIF_TYPE_ID type_id)
        EIF_POINTER_FUNCTION eif_pointer_function (char *rout_name, EIF_TYPE_ID type_id)

        Returns the address of the Eiffel routine by giving its name rout_name and the type id type_id of the class, in which it is declared. Returns a NULL pointer or raises a visible exception (if enabled) when there is no corresponding routine with name rout_name or the routine is not visible. The first argument of an Eiffel routine has to be the target of the Eiffel routine.

    The  Eiffel object returned by an Eiffel function  must be protected afterwards with 'eif_protect' (this only applies for functions, which address is returned by `eif_reference_function' since the other function types returns  basic types, which are not Eiffel objects).

    NOTES:

      The address returned by these functions must be called between parenthesis.

      Be sure that the Eiffel routine is not a C External. In this case, you must call directly the C External instead of its Eiffel wrapper.

            Example

        See also Declaring routines taking real as argument, Cast of the Eiffel routines in C, Bad macros in eif_cecil.h.

    Back to index

3.9 - Enabling/Disabling the visible exception

        #include "eif_cecil.h"

        void eif_enable_visible_exception ()   
        void eif_disable_visible_exception ()   

        Respectively, enables and disables the visible exception. See visible exception
         By default, the visible exception is disabled (since v4.5).

        Back to index

3.10 - Creating an Eiffel string: eif_string

        #include "eif_plug.h"

        EIF_REFERENCE eif_string (char *string)    /* Macro */

        Returns the direct reference to an Eiffel string by giving the corresponding C string string . The result of eif_string does not reference the C string passed as argument: it copies it, before creating the Eiffel string.

    NOTE:

      The return value must be protected with eif_protect for later use. The C string must be manually freed by the user, if it has been dynamically allocated.

    COMPATIBILITY:

      eif_string ("ABC") is equivalent to RTMS ("ABC") and eif_make_string ("ABC", strlen ("ABC")).

       Example

        Back to index

3.11 - Getting the return-type of an attribute: eif_attribute_type

        #include "eif_cecil.h"

        int eif_attribute_type (char *attr_name, EIF_TYPE_ID tid)   

        #define EIF_REFERENCE_TYPE   1
        #define EIF_CHARACTER_TYPE  2
        #define EIF_BOOLEAN_TYPE      3
        #define EIF_INTEGER_TYPE        4
        #define EIF_REAL_TYPE              5
        #define EIF_DOUBLE_TYPE         6
        #define EIF_EXPANDED_TYPE     7
        #define EIF_BIT_TYPE                  8
        #define EIF_POINTER_TYPE        0
        #define EIF_NO_TYPE                  (-1)
     

        Returns the type of the  attribute described by its name attr_name and the type identifier of the class where it is defined tid. The return type is an int (see above for correspondances). In case of failure, EIF_NO_TYPE is returned - not such given attribute name, routine name instead of attribute name, or so on.

        Example: Get the type of  count from  STRING

        int i;

        i = eif_attribute_type ("count", eif_type_id ("STRING");
        printf ("type is %d\n");    /*
    Should be EIF_INTEGER_TYPE since it returns an Eiffel Integer */

    OTHER:

      *(EIFFEL_TYPE *) eif_attribute_safe (EIF_REFERENCE object, char *name, int type_int, int *status) can be used for debugging or type checking. It returns the attribute reference of name name from the object object of type type_int. status contains the status of the function call: it can be EIF_CECIL_OK, EIF_CECIL_ERROR, EIF_NO_ATTRIBUTE, or EIF_WRONG_TYPE (type_int does not match with real type of object).

    See also:

    Back to index

3.12 - Getting the class name corresponding to a type id: eif_name

        #include "eif_cecil.h"

        char *eif_name (EIF_TYPE_ID tid)

        Returns the corresponding name (C string) of the Eiffel class, given a type identifier type_id. If the type identifier is a generic type identifier, no generic parameter type is given. Returns NULL if an invalid type idientifer is given.

        Example:

        printf ("the class name with type id 1 is %s\n", eif_name (1);    /* Should print "PLATFORM"  on most compiler versions*/

    COMPATIBILITY:

      eif_name is equivalent to eif_name_by_tid

        See also eif_type, eif_type_id

    Back to index

3.13 - Getting the type id of an Eiffel object: eif_type, eif_type_by_reference.

        #include "eif_cecil.h"

        EIF_TYPE_ID eif_type (EIF_OBJECT object)   

        EIF_TYPE_ID eif_type_by_reference (EIF_REFERENCE reference)   

        eif_type returns the type identifier, given an indirection pointer to an Eiffel object.

    eif_type_by_reference returns the type identifier, given the direct reference to an Eiffel object reference.

    COMPATIBILITY:

      eif_type is equivalent to eif_type_by_object. eif_type (object) is equivalent to eif_type_by_reference (eif_access (object)).
    See also eif_name, eif_type_id

        Back to index

3.14 - Converting a C array into an Eiffel array: eif_make_from_c.

4 - Restrictions in CECIL

4.1 - Declaring routines taking real as argument

     
    The EIF_PROCECURE, EIF_XX_FUNCTION types match to most of the procedures and functions. However, if you want to use an Eiffel routine taking a real as one of its arguments, you must be very careful. You need to define explicitely a typedef that corresponds to the exact signature of the routine.

    Example: call to put (r: REAL ; index: INTEGER) from ARRAY [REAL])

    typedef void (*EIF_PROCEDURE_REAL_INTEGER)(EIF_REFERENCE, EIF_REAL, EIF_INTEGER);
    EIF_PROC_REAL_INTEGER eput;

    /* some code */
    eput = (EIF_PROCEDURE_REAL_INTEGER) eif_procedure ("put", eif_type_id ("ARRAY [REAL]"));

    Back to index

4.2 - Cast of the Eiffel routines in C.

    There are nine typedefs defined for the Eiffel routines.
    EIF_PROCEDURE: Eiffel procedure
    EIF_INTEGER_FUNCTION: Eiffel functions returning an Eiffel Integer
    EIF_BOOLEAN_FUNCTIONL: Eiffel functions returning an Eiffel Boolean
    EIF_CHARACTER_FUNCTION Eiffel functions returning an Eiffel Character
    EIF_REAL_FUNCTION: Eiffel functions returning an Eiffel real
    EIF_DOUBLE_FUNCTION Eiffel functions returning an Eiffel double
    EIF_REFERENCE_FUNCTION: Eiffel functions returning an Eiffel references (e.g an Eiffel object, which is not an instance of a basic type)
    EIF_POINTER_FUNCTION: Eiffel functions returning an Eiffel pointer
    EIF_BIT_FUNCTION: Eiffel functions returning an Eiffel bit.

    These typedefs do not perform  the type checking of the arguments. The typedefs only cast the result of the Eiffel routine (void if it is an Eiffel procedure). For more information on the previous definitions, see their definitions in $EIFFEL4/bench/spec/$PLATFORM/include/eif_cecil.h.

    CECIL can not generate relevant typedefs for every type of routine that is exported to C through CECIL. Consequently, you must define manually the typedefs to properly cast the pointer type to the Eiffel routine. This way, during compilation, a warning or an error is raised if arguments with incorrect types are passed to the Eiffel routine.

    Example:

    Let the Eiffel function `foo' :

    foo (c: CHARACTER; a: ARRAY [INTEGER]): POINTER is

      do ... end
    It is declared in C:

    typedef EIF_POINTER (*EIF_FOO_TYPE)(EIF_REFERENCE /* Current object */,

                EIF_CHARACTER /* 1rst argument */,

                EIF_REFERENCE /* 2d argument */);
                 

    The first argument of an Eiffel routine is always the current object - the target of the call. This object is either the one, which precedes the ".foo(..)" if it is a nested call, or Current if it is called without the "."

    NOTE:

      Do not forget to call all the Eiffel routines from C within parenthesis. Otherwise, they will return the address of the Eiffel routine, instead of performing an action.

      You cannot use the Eiffel routine types for the routines, which are Eiffel External routines. The cast would be incorrect since these routines do not take an EIF_REFERENCE as first argument, but the actual first argument of the Eiffel signature. It is recommended to use directly the C function instead.

      Back to index
       

    4.3 - Visible classes

      You must declare in your Ace file all the Eiffel types you want to use in CECIL as visible.  See also ETL appendice D.

      - Using a non-generic type, declare:
              dummy: SIMPLE_TYPE

          in your root class.

      a_cluster: "A_PATH"
              visible
                  SIMPLE_TYPE
              end
      end;

      in your Ace file.

      - Using Generic types , declare for example:
              dummy1: GEN_TYPE [INTEGER]
              dummy2: GEN_TYPE [OTHER_TYPE]

          in the root class.

      and

      an_other_cluster:    "AN_OTHER_PATH"
          visible
              GEN_TYPE    -- Do not specify any generic parameter.
          end
      end;

      in your Ace file.

      This is necessary to tell the compiler to generate the C code corresponding to GEN_TYPE[INTEGER] or GEN_TYPE[OTHER_TYPE] and make it available to CECIL.  Otherwise, eif_type_id will returns EIF_NO_TYPE, and eif_procedure/eif_function_xx will return a NULL pointer or raise a visible exception.

      Visible exception:

         
        If you try to access a feature, which is not exported in the visible clause of an Ace file (through its class or an export clause in the visible clause), then a visible exception is raised. This exception can also be triggered when you mistyped the name of a class (routine renamed, attribute instead of a routine, or so on) , when the routine is not exported (see visible features), or when you forgot to declare an instance of the class that implements the routine (see above).

        You can disable this exception by calling eif_disable_visible_exception. You can also enable it with eif_enable_visible_exception.

        If you try to call eif_procedure or eif_xx_function to get the pointer on a non visible routine, they will return a NULL pointer.

        Back to index

    4.4 - Visible features

      Only the Eiffel features, with no export clause (even if it is {ANY}), and which are declared in a visible class, are available (visible) to CECIL. The creation procedure of a visible class is automatically exported to CECIL (unless there is an export clause in the Ace file, which does not specify to export it)

      Exporting features to CECIL, overriding the export clause in the Ace file:

            You can specify the CECIL routines you want to export to CECIL in your Ace file by adding a custom export clause in your Ace file. This overrides all the export clauses specified in the Eiffel code. When there is an export clause in a visible clause, all the feature of the class are not visible by default, even its creation procedure.

        Example: export the feature foo from  class A which has an export clause.

        In Eiffel:
            feature {B,C}    -- Only exported to classes B and C
                 foo is
                    do
                        ...
                    end

        In the Ace file:
            ....
            visible
                A
                    export
                        "make",    -- creation procedure
                        "foo"
                    end
            end
            ...
         

        In this case, only foo and make are exported to CECIL. All other features from class A are no longer available.  See also ETL Part E,  appendice D and bug in export clause.
         

      Back to index

    5 - Bugs

    5.1 - Bug in export clause

      Be very careful when enumerating the Eiffel features that you want to export in the visible clause. The compiler does not check the validity of the feature names. If  you put a wrong name (typo, or if you are not taking care of the renaming in Eiffel, for example).  All features of the class will be invisible from CECIL.

      The name of the features to export should be put between " " to avoid any confusion with Lace keywords.

      By default, the creation procedure(s) of a visible class is/are exported and visible in CECIL. However, if the creation procedure is defined in a parent and has an export clause in the Eiffel code, you must explicitely export it to CECIL in the Ace file.

    Back to index

    5.2 - Bad macros in eif_cecil.h

      Some new macros have been incorrectly set in v4.3. In the file
        $EIFFEL4/bench/spec/$PLATFORM/include/eif_cecil.h (unix)
      or
        /bench/spec/windows/include/eif_cecil.h (windows)

      replace the lines:

        #define eif_double_function eifreal /* Get an Eiffel function returning an Eiffel Double */
        #define eif_reference_function eifreal /* Get an Eiffel function returning an Eiffel Double */
      by
        #define eif_double_function eifdouble /* Get an Eiffel function returning an Eiffel Double */
        #define eif_reference_function eifref /* Get an Eiffel function returning an Eiffel Reference */

      the line:

        #define eif_fn_pointer eifpointer /* Use `eif_pointer_function' instead */

      by

        #define eif_fn_pointer eifptr /* Use `eif_pointer_function' instead */

      the line:

        #define EIF_FN_INT EIF_INTEGER_PROCEDURE /* Use EIF_INTEGER_PROCEDURE instead */
      by

        #define EIF_FN_INT EIF_INTEGER_FUNCTION /* Use EIF_INTEGER_FUNCTION instead */

      and the lines:

        #define eif_fn_float eifreal /* Use `eif_double_function' instead */
        #define eif_fn_double eifreal /* Use `eif_double_function' instead *
      by
        #define eif_fn_float eifreal /* Use `eif_real_function' instead */
        #define eif_fn_double eifdouble /* Use `eif_double_function' instead */

    Back to index