Super Prev Next

Multilanguage programming

XDS allows you to mix Modula-2, Oberon-2, C, and Assembler modules, libraries, and object files in one project.


Super Prev Next

Modula-2 and Oberon-2

It is not necessary to notify the compiler of using Modula-2 objects in Oberon-2 module and vice versa. The compiler will detect the language automatically when processing symbol files on IMPORT clause.


Super Prev Next

Basic types

In Oberon-2 the basic types have the same length on all platforms. In Modula-2 the size of types INTEGER, CARDINAL and BITSET may be different and depends on the value of the M2BASE16 option. The following table summarizes the correspondence between the basic types.

Type Size Oberon-2 Modula-2
      M2BASE16+ M2BASE16-
integer 8 SHORTINT
integer 16 INTEGER INTEGER
integer 32 LONGINT INTEGER
cardinal 8
cardinal 16 CARDINAL
cardinal 32 CARDINAL
bitset 16 BITSET
bitset 32 SET BITSET

The system types INT and CARD correspond to Modula-2 INTEGER and CARDINAL types respectively. We recommend to use INT and CARD in Oberon-2 when importing Modula-2 modules. For example, if the procedure Foo is defined in the Modula-2 definition module M as

    DEFINITION MODULE M;

    PROCEDURE Foo(VAR x: INTEGER);

    END M.

its portable usage in Oberon-2 is as follows:

    VAR x: SYSTEM.INT;
       .  .  .
      M.Foo(x);


Super Prev Next

Data structures

XDS allows any Modula-2 data structures to be used in Oberon-2 modules, even those that can not be defined in Oberon-2 (e.g. variant records, range types, set types, enumerations, etc).

However, usage of Modula-2 types in Oberon-2 and vice versa is restricted. Whenever possible XDS tries to produce the correct code. If a correct translation is impossible, an error is reported:

Standard procedures NEW and DISPOSE are always applied according to the language of a parameter’s type. For example, for the following declarations in an Oberon-2 module:

    TYPE
      Rec = RECORD END;
      MP  = POINTER ["Modula"] TO Rec; (* Modula pointer *)
      OP  = POINTER TO Rec;     (* Oberon pointer *)
    VAR
      m: MP;
      o: OP;

the call NEW(m) will be treated as a call to the Modula-2 default ALLOCATE, while NEW(o) will be treated as a call of the standard Oberon-2 run-time routine. See also Direct language specification.

Implicit memory deallocation (garbage collection) is applied to Oberon-2 objects only. If a variable of a Modula-2 pointer type is declared in an Oberon-2 module, it shall be deallocated explicitly.

Super Prev Next

Example: Using the Modula data type in Oberon

    (* Modula-2*) DEFINITION MODULE m2;
    TYPE
      Rec = RECORD  (* a record with variant parts *)
        CASE tag: BOOLEAN OF
          |TRUE:  i: INTEGER;
          |FALSE: r: REAL;
        END;
      END;
      Ptr = POINTER TO Rec;

    VAR
      r: Rec;
      p: Ptr;

    PROCEDURE Foo(VAR r: Rec);

    END m2.

    (* Oberon-2 *) MODULE o2;

    IMPORT m2; (* import of a Modula-2 module *)

    VAR
      r: m2.Rec;  (* using the Modula-2 record type *)
      p: m2.Ptr;  (* using the Modula-2 pointer type *)
      x: POINTER TO m2.Rec;

    BEGIN
      NEW(p);     (* Modula-2 default ALLOCATE *)
      NEW(x);     (* Oberon-2 NEW *)
      m2.Foo(r);
      m2.Foo(p^);
      m2.Foo(x^);
    END o2.


Super Prev Next

Garbage collection

It is important to remember that Modula-2 and Oberon-2 have different approaches to memory utilization. When a program contains both Modula-2 and Oberon-2 modules, garbage collection is used. See Memory management for more information.


Super Prev Next

Direct language specification

The compiler must know the implementation language of a module to take into account different semantics of different languages and to produce correct code.

In some cases, it is necessary for a procedure or data type to be implemented according to the rules of a language other than that of the whole module. In XDS, it is possible to explicitly specify the language of a type or object. Direct language specification (DLS) is allowed either if language extensions are enabled or if the module SYSTEM is imported.

In a record, pointer, or procedure type declaration, or in a procedure declaration, the desired language (or, more precisely, the way in which that declaration is treated by the compiler) can be specified as "[" language "]" immediately following the keyword RECORD, POINTER, or PROCEDURE. language can be a string or integer constant expression /We recommend to use strings, integer values are preserved for backward compatibility./ :

Convention String Integer
Oberon-2 "Oberon" 0
Modula-2 "Modula" 1
C "C" 2
Pascal "Pascal" 5
Win32 API "StdCall" 7
OS/2 API "SysCall" 8

Examples:

    TYPE
      UntracedPtr = POINTER ["Modula"] TO Rec;

Here UntracedPtr is defined as a Modula-2 pointer, hence all variables of that type will not be traced by garbage collector.

    PROCEDURE ["C"] sig_handler (id : SYSTEM.int);
     .  .  .
      signal.signal(signal.SYSSEGV, sig_handler);

Here sig_handler has C calling and naming conventions, so it can be installed as a signal handler into C run-time support.

A direct language specification clause placed after a name of a field, constant, type, or variable points out that the name of the object will be treated according to the rules of the specified language.

    TYPE
      Rec ["C"] = RECORD
        name ["C"]: INTEGER;
      END;

    CONST pi ["C"] = 3.14159;

    VAR buffer[]["C"]: POINTER TO INTEGER;

Note: In ISO Modula-2, an absolute address may be specified for a variable after its name in square brackets, so the empty brackets are required in the last line.

A procedure name is treated according to the language of its declaration, so in the following declaration:

    PROCEDURE ["C"] Foo;

both the procedure type and the procedure name are treated according to the C language rules. Note: If you are using a C++ compiler, the Foo function should be declared with C name mangling style. Consult your C++ manuals for further information.


Super Prev Next

Interfacing to C

Special efforts were made in XDS to provide convenient interface to other languages, primarily to the C language. The main goal is to allow direct usage of existing C libraries and APIs in Modula-2/Oberon-2 programs.


Super Prev Next

Foreign definition module

A direct language specification clause may appear immediately after keywords DEFINITION MODULE. The effect is that all objects defined in that module are translated according to the specified language rules, thus making unnecessary direct language specifications for each object.

Several options are often used in foreign definition modules.

Super Prev Next

Example

    <*+ M2EXTENSIONS *>
    <*+ CSTDLIB *>      (* C standard library *)
    <*+ NOHEADER *>     (* we already have header file *)
    DEFINITION MODULE ["C"] string;

    IMPORT SYSTEM;

    PROCEDURE strlen(s: ARRAY OF CHAR): SYSTEM.size_t;
    PROCEDURE strcmp(s1: ARRAY OF CHAR;
                     s2: ARRAY OF CHAR): SYSTEM.int;
    END string.

Take the following considerations into account when designing your own foreign definition module:


Super Prev Next

External procedures specification

In some cases, it may be desirable not to write a foreign definition module but to use some C or API functions directly. XDS compilers allow a function to be declared as external.

The declaration of an external procedure consists of a procedure header only. The procedure name in the header is prefixed by the symbol "/".

    PROCEDURE ["C"] / putchar(ch: SYSTEM.int): SYSTEM.int;


Super Prev Next

Relaxation of compatibility rules

The compiler performs all semantic checks for an object or type according to its language specification. Any object declared as that of Modula-2 or Oberon-2 is subject to Modula-2 or Oberon-2 compatibility rules respectively. The compiler uses relaxed compatibility rules for objects and types declared as "C", "Pascal", "StdCall", and "SysCall".


Super Prev Next

Assignment compatibility

Two pointer type objects are considered assignment compatible, if

    VAR
      x: POINTER TO T;
      y: POINTER TO T;
      z: POINTER ["C"] TO T;
    BEGIN
      x := y;       -- error
      y := z;       -- ok
      z := y;       -- ok


Super Prev Next

Parameter compatibility

For procedures declared as "C", "Pascal", "StdCall", or "SysCall", the type compatibility rules for parameters are significantly relaxed:

If a formal value parameter is of the type declared as POINTER TO T, the actual parameter can be of any of the following types:

If a formal parameter is an open array of type T, the actual parameter can be of any of the following types:

This relaxation, in conjunction with the SYSTEM.REF function procedure, simplifies Modula-2/Oberon-2 calls to C libraries and the target operating system API, preserving the advantages of the type checking mechanism provided by that languages.

Super Prev Next

Example

    TYPE
      Str = POINTER TO CHAR;
      Rec = RECORD ... END;
      Ptr = POINTER TO Rec;

    PROCEDURE ["C"] Foo(s: Str); ... END Foo;
    PROCEDURE ["C"] Bar(p: Ptr);  ... END Bar;
    PROCEDURE ["C"] FooBar(a: ARRAY OF CHAR);  ... END FooBar;

    VAR
      s: Str;
      a: ARRAY [0..5] OF CHAR;
      p: POINTER TO ARRAY OF CHAR;
      R: Rec;
      A: ARRAY [0..20] OF REC;
      P: POINTER TO REC;

      Foo(s);    (* allowed - the same type *)
      Foo(a);    (* allowed for the "C" procedure *)
      Foo(p^);   (* allowed for the "C" procedure *)
      Bar(R);    (* the same as Bar(SYSTEM.REF(R)); *)
      Bar(A);    (* allowed for the "C" procedure *)
      Bar(P);    (* allowed for the "C" procedure *)
      FooBar(s); (* allowed for the "C" procedure *)


Super Prev Next

Ignoring function result

It is a standard practice in C programming to ignore the result of a function call. Some standard library functions are designed taking that practice into account. E.g. the string copy function accepts the destination string as a variable parameter (in terms of Modula-2) and returns a pointer to it:

    extern char *strcpy(char *, const char *);

In many cases, the result of the strcpy function call is ignored.

In XDS, it is possible to ignore results of functions defined as "C", "Pascal", "StdCall", or "SysCall". Thus, the function strcpy defined in the string.def foreign definition module as

    PROCEDURE ["C"] strcpy(VAR d: ARRAY OF CHAR;
                               s: ARRAY OF CHAR): ADDRESS;

can be used as a proper procedure or as function procedure:

    strcpy(d,s);
    ptr:=strcpy(d,s);


Super Prev Next

Configuring XDS for a C Compiler

Different C compilers have different naming and calling conventions. If you use C functions or libraries in your projects, you have to specify your C compiler using the CC equation in order to have all C functions to be called in a way compatible with that compiler. The compiler also sets the default values of some other options and equations according to the value of the CC equation. See Additional configuration options.

For Windows NT and Windows 95 XDS supports the MSVC++ and Watcom (stack convention) compilers. The corresponding values of the CC equation are "MSVC" and "WATCOM", written in any case. If the equation is not set, the compiler will assume "WATCOM" by default. Add the line

    -cc=Watcom

or

    -cc=MSVC

to your configuration file.

Alignment of data structures is controlled by the ALIGNMENT equation.

Names in an object file produced by a C compiler may have leading underscore. If you are going to use C modules and libraries, you have to force XDS to use the same naming rules. To do this, turn the GENCPREF option ON in the foreign definition modules:

    <* +GENCPREF *>
    DEFINTION MODULE ["C"] stdio;


Super Prev Next

Possible problems

To use a C function or a data type from Modula-2 or Oberon-2 you have to express its type in one of these languages. Usually it is done in a foreign definition module (See Interfacing to C). The current version of XDS does not support all calling conventions, so direct usage of some functions is not possible, namely:

XDS does not support usage of data structures with non-standard alignments. If the ALIGNMENT equation is set to n, use the option "-zpn" for Watcom C and "-Zpn" for MSVC.

Both Modula-2 and C/C++ have exception handling and finalization facilities. Unpredictable results may occur if you try to utilize that facilities from both languages in one program.


Super Prev Next

Using an unsupported compiler

XDS does not support all available C compilers. You can use additional configuration options (See Additional configuration options) to adapt XDS to your C compiler. The DEFLIBS option should be switched off in that case.

It may be necessary to make some changes in the run-time support or to build a special version of the library for a particular C compiler. It can be done under terms of a special support program.


Super Prev Next

Additional configuration options

The following options can be used to adapt XDS to an unsupported C compiler. We recommend to use these options with care.

The table below shows the default values of these options for the supported C compilers:

CC setting WATCOM MSVC
GENCPREF OFF ON
ONECODESEG OFF ON