Go to the previous, next section.

Using ILU with C++

This document is for the C++ programmer who wishes to use ILU.

The ISL Mapping to C++

Names

In general, ILU constructs C++ names from ISL names by replacing hyphens with underscores. Type names are prepended with their interface name and the string "_T_". Enumeration value namess are formed by prepending the enumeration type name and "_" to the ISL enumeration value name. Records turn directly into C++ structs. Unions consist of a record with two fields: the type descriminator, a field called "descriminator", and a union of the possible values, called "value". Arrays map directly into C++ arrays. Sequences become a C++ class that is a subclass of the pre-defined class iluSequence. Objects become C++ classes that are subclasses of the pre-defined class iluObject.

Exception names are prepended with their interface name and "_E_". Because of the scarcity of implementation of the C++ exception mechanism, exceptions are passed by adding an additional argument to the beginning of each method, which is a pointer to a status struct, which contains an exception code, and a union of all the possible exception value types defined in the interface. Method implementations set the exception code, and fill in the appropriate value of the union, to signal an exception. Exception codes are represented in C++ with values of the type ilu_Exception.

Constant names are prepended with their interface name and "_C_". They are implemented with #define.

Here's a sample ISL spec, and the resulting C++ mappings:

INTERFACE Foo;

TYPE String = ilu.CString;
TYPE UnsignedInt = CARDINAL;

TYPE E1 = ENUMERATION val1, val2, val3=40 END;
TYPE R1 = RECORD field1 : CARDINAL, field2 : E1 END;
TYPE A1 = ARRAY OF 200 BYTE;
TYPE A2 = ARRAY OF 41, 3 R1;
TYPE S1 = SEQUENCE OF E1;
TYPE U1 = UNION R1, A2 END;

EXCEPTION Except1 : String;

CONSTANT Zero : CARDINAL = 0;

TYPE O1 = CLASS METHODS M1 (arg1 : R1) : UnsignedInt RAISES Except1 END;

The C++ mapping:

typedef ilu_CString Foo_T_String;
typedef ilu_Cardinal Foo_T_UnsignedInt;

typedef enum _Foo_T_E1_enum {
  Foo_T_E1_val1 = 1,
  Foo_T_E1_val2 = 2,
  Foo_T_E1_val3 = 40
} Foo_T_E1;
typedef struct _Foo_T_R1_struct {
  ilu_Cardinal field1;
  Foo_T_E1 field2;
} Foo_T_R1;
typedef ilu_Byte Foo_T_A1[200];
typedef Foo_T_R1 Foo_T_A2[41][3];
class _Foo_T_S1_sequence {
 private:
  ilu_Cardinal _maximum;
  ilu_Cardinal _length;
  Foo_T_E1 *_buffer;
 public:
  _Foo_T_S1_sequence ();
  virtual ~_Foo_T_S1_sequence ();
  static class _Foo_T_S1_sequence *Create (ilu_Cardinal initial_size, Foo_T_E1 *initial_data);
  virtual ilu_Cardinal Length();
  virtual void Append(Foo_T_E1);
  virtual Foo_T_E1 RemoveHead();
  virtual Foo_T_E1 RemoveTail();
  virtual ilu_Cardinal RemoveAll(ilu_Boolean (*matchproc)(Foo_T_E1));
  virtual Foo_T_E1 * Array();
  virtual Foo_T_E1 Nth(ilu_Cardinal index);
};
typedef class _Foo_T_S1_sequence * Foo_T_S1;
enum Foo_T_U1_allowableTypes { Foo_T_U1_R1, Foo_T_U1_A2 };
typedef struct _Foo_T_U1_union {
  enum Foo_T_U1_allowableTypes descriminator;
  union {
    Foo_T_R1 R1;
    Foo_T_A2 A2;
  } value;
} Foo_T_U1;

extern ilu_Exception Foo_E_Except1;     /* exception code Except1 */

typedef struct _Foo_Status_struct {
  ilu_Exception returnCode;
  union {
    ilu_Cardinal anyvalue;
    Foo_T_String Except1;
  } values;
} FooStatus;

class Foo_T_O1 : public iluObject {
 public:
  Foo_T_UnsignedInt M1 (FooStatus *_status, Foo_T_R1 *arg1);
};

Some functions global to the use of the interface are placed in a class called interface-name_G(8). In particular, these include

void RaiseException (interface-nameStatus *status, ilu_Exception code...)
which implementors of true methods use to signal exceptions and a Create method for each sequence type defined in the interface,
sequence-type Create_sequence-name (iluSequenceDestroyProc dp)
For the above example, these would look like

class Foo_G {
 public:

  static void RaiseException (FooStatus *status, ilu_Exception code...);

  ... /* other utility methods omitted */

  static Foo_T_S1 Create_S1 (iluSequenceDestroyProc dp);

};

Stub Generation

To generate C++ stubs from an ISL file, you use the program c++-stubber. Three files are generated from the `.isl' file:

Typically, clients of a module never have a need for the `interface-name-server-stubs.cc' file.

% c++-stubber foo.isl
header file interface foo to ./foo.H...
code for interface foo to ./foo.cc...
code for server stubs of interface foo to ./foo-server-stubs.cc...
%

The option -renames renames-filename may be used with c++-stubber to specify particular C++ names for ISL types. See section ??? for more details.

Tailoring C++ Names

It is sometimes necessary to have the C++ names of an ILU interface match some other naming scheme. A mechanism is provided to allow the programmer to specify the names of C++ language artifacts directly, and thus override the automatic ISL to C++ name mappings.

To do this, you place a set of synonyms for ISL names in a renames-file, and invoke the c++-stubber program with the switch -renames, specifying the name of the renames-file. The lines in the file are of the form

construct ISL-name C++-name
where construct is one of method, exception, type, interface, or constant; ISL-name is the name of the construct, expressed either as the simple name, for interface names, the concatenation interface-name.construct-name for exceptions, types, and constants, or interface-name.type-name.method-name for methods; and C++-name is the name the construct should have in the generated C++ code. For example:

# change "Foo_T_R1" to plain "R1"
type Foo.R1 R1
# change name of method "M1" to "Method1"
method Foo.O1.M1 Method1

Lines beginning with the `hash' character `#' are treated as comment lines, and ignored, in the renames-file.

This feature of the c++-stubber should be used as little and as carefully as possible, as it can cause confusion for readers of the ISL interface, in trying to follow the C++ code. It can also create name conflicts between different modules, unless names are carefully chosen.

Libraries and Linking

For clients of an ILU module, it is only necessary to link with the `interface-name.o' file compiled from the `interface-name.cc' file generated for the interface or interfaces being used, and with the two libraries `ILUHOME/lib/libilu-c++.a' and `ILUHOME/lib/libilu.a' (in this order, as `libilu-c++.a' uses functions in `libilu.a').

For implementors of true classes, or servers, the code for the server-side stubs, in the file `interface-name-server-stubs.o', compiled from `interface-name-server-stubs.cc', should be included along with the other files and libraries.

Makefiles

ILU uses the imake system from X11R? to produce `Makefile's from `Imakefile's. For more details on this process, section Using Imake with ILU.

Go to the previous, next section.