# Using H2D

- Headers merging
- Fitting a Modula-2 compiler
- Modifying translation rules

## Headers merging

A C header file may contain one or more `#include` directives. H2D offer the following translation variants for included headers:

- All headers are merged and translated into a single definition module (the MERGEALL option is set ON).
- Each included header is translated into a separate definition module which name is added to the import list (the MERGEALL option is set OFF).
- The headers which have to be merged are explicitly specified using the `#merge` directive (the MERGEALL option must be OFF).

If the GENSEP option is set ON, H2D separates pieces of Modula-2 text, which correspond to different merged headers, with comments containing header file names.

The `#merge directive` provides more flexible method of merging control than the MERGEALL option. The example illustrates situation in which this directive is very helpful.

- Example

### Example

    /* m1.h */                      /* m2.h */
    typedef int INTEGER;            struct descriptor{
    #include <m2.h>                   INTEGER handl;
    #include <m3.h>                 };
    #include <m4.h>                 typedef int far * RETVAL;
    RETVAL handler();               /* end m2.h */
    /* end m1.h */

In this example, the `RETVAL` declaration from `m2.h` is used in `m1.h`. On the other hand, `m2.h` uses the declaration from `m1.h` (`INTEGER`). Setting the MERGEALL option ON results in all headers (`m1.h`, `m2.h`, `m3.h`, and `m4.h`) being merged and translated into the single definition module `m1`. If this is not a desired behaviour, the `#merge directive` should be used instead. If the MERGEALL option is OFF and the line

`#merge <m2.h>`

is added to either `m1.h` or the corresponding `#header` directive in a project file, H2D produces three definition modules `m1`, `m3` and `m4`, where `m1` is a result of translation of two merged headers `m1.h` and `m2.h`.

## Fitting a Modula-2 compiler

Some of H2D translation rules depend on the target Modula-2 compiler; even XDS-C and Native XDS require different definition modules. The BACKEND option is used to reflect the major difference: whether the target Modula-2 compiler is a native code compiler (`-BACKEND = Native`) or a convertor to C (`-BACKEND = C`). It is also possible to produce definition modules suitable for both XDS-C and Native XDS (`-BACKEND = Common`). In this case H2D encloses target-dependent parts with XDS conditional compilation directives.

- Native code
- Convertor to C

### Native code

C headers often contain a number of useful function-like macros. These macros are translated into procedure declarations with parameters having type `ARRAY OF SYSTEM.BYTE`, which is assignment compatible with any other type. But C macros exist only at compile-time and are not present in object files. Therefore, a Modula-2 compiler is unable to handle them properly unless it is implemented as a convertor to C. Nevertheless, H2D provides a technique which allows to use C function-like macros even with a native code Modula-2 compiler.

If the BACKEND option is set to either `Native` or `Common` and the GENMACRO option is set ON, H2D produces an additional module containing macro prototypes --- procedures corresponding to function-like macros, which bodies consist of a comment with C macro definition and are expected to be written by a programmer. These procedures are then declared as external in the main definition module. Thus, a macro prototype module need not to be imported, it should be just linked into an executable which uses the generated definition module.

A macro prototype module name is constructed from a header module name and a prefix specified by the MACPFX option.

- Example

#### Example

    /* macro.h */
        ...
    #define cube(x) (x*x*x)
        ...

    (* macro.def  Sep 20  2:38:9  1996 *)
        ...
    DEFINITION MODULE ["C"] macro;
        ...
    PROCEDURE  / cube ( x: ARRAY OF SYSTEM.BYTE );
        ...
    END macro.

    (* m_macro.def  Sep 20  2:38:9  1996 *)
        ...
    DEFINITION MODULE m_macro;

    IMPORT SYSTEM;
        ...
    PROCEDURE ["C"] cube ( x: ARRAY OF SYSTEM.BYTE );
        ...
    END m_macro.

    (* m_macro.mod  Sep 20  2:38:9  1996 *)
        ...
    IMPLEMENTATION MODULE m_macro;

    IMPORT SYSTEM;
        ...
    PROCEDURE ["C"] cube ( x: ARRAY OF SYSTEM.BYTE );
    (*
    #define cube(x) (x*x*x)
    *)
    BEGIN
    END cube;
        ...
    END m_macro.

### Convertor to C

A Modula-2 compiler implemented as a convertor to C (e.g. XDS-C) converts definition modules written by a programmer to C headers. But headers corresponding to definition modules generated by H2D already exist. To prevent them from being overridden, H2D inserts the NOHEADER XDS option, which disables header file generation, at the beginning of each definition module.

For all included header files, which are not merged (see Headers merging), H2D also sets the CSTDLIB XDS option according to the parenthesis used in the `#include` directive -- double quotes or angle brackets. For top-level header files, this option is set equal to the value of the CSTDLIB option.

H2D usually has to introduce a number of additional types in the definition module (see Function prototypes and Types). These types are absent in the original header file, and their usage would cause C compilation to fail. To solve this problem, H2D constructs a resulting definition module name from a header file name and a prefix specified by the DEFPFX option. Then, it produces a "wrapper" header file, which name corresponds to the name of a definition module, containing an `#include` directive with original header name, followed by required type declarations. Type declarations from a project file are copied to a wrapper file as well.

- Example

#### Example

    /* type.h */

    struct Node {
      struct Node *next;
      struct Node *prev;
      int          hash;
    };

    int Hash(char * str);

    (* h2d_type.def  Sep 20  2:51:7  1996 *)
        ...
    DEFINITION MODULE ["C"] h2d_type;

    IMPORT SYSTEM;
        ...
    <*- GENTYPEDEF *>

    TYPE
      PtrNode = POINTER TO Node;

    <*+ GENTYPEDEF *>

      Node = RECORD
        next: PtrNode;
        prev: PtrNode;
        hash: SYSTEM.int;
      END;

    <*- GENTYPEDEF *>

      PtrSChar = POINTER TO CHAR;

    PROCEDURE Hash ( str: PtrSChar ): SYSTEM.int;

    END h2d_type.

    /* h2d_type.h  Sep 20  2:51:7  1996 */
        ...
    #include "type.h"

    #ifndef h2d_type_H_
    #define h2d_type_H_

    typedef struct Node * PtrNode;
    typedef signed char * PtrSChar;

    #endif  /* h2d_type_H_ */

## Modifying translation rules

- Base types mapping
- Pointer type function parameters
- Preserving constant names

### Base types mapping

The CTYPE and M2TYPE options in conjunction with the `#variant directive` provide complete control over mapping of C base types to Modula-2 types.

The CTYPE option specifies sizes (in bytes) of C base types, and their default mapping to Modula-2:

`-CTYPE = float = 4, REAL`
`. . .`
`-CTYPE = unsigned short int = 2, SYSTEM.CARD16`

The M2TYPE option specifies Modula-2 types supported by a particular compiler, with their sizes and families to which they belong:

`-M2TYPE = CARDINAL = 4, UNSIGNED`
`-M2TYPE = CHAR = 1, CHAR`
`. . .`
`-M2TYPE = SYSTEM.SET16 = 2, SET`

Finally, the `#variant directive` allows to explicitly specify a Modula-2 type for a particular object:

`void f(unsigned short mask) PROCEDURE f(mask : SYSTEM.SET16);`
`#variant f(0) : SYSTEM.SET16`

Note: In order to keep original headers intact, `#variant` directives may be placed into the project file inside the corresponding `!header directive`.

H2D checks type mappings for correctness using the following rules:

- type sizes must match
- floating point C types may only be mapped to Modula-2 types defined as REAL by M2TYPE option.
- signed integer C types may be mapped to any Modula-2 type except REAL and UNSIGNED.
- unsigned integer C types may be mapped to any Modula-2 type except REAL and SIGNED.

One of the most advanced features of this mechanism is the ability to use Modula-2 set types for C objects. The C programming language, as well as C++, has no built-in set type. The common practice is to treat unsigned integer types as bit scales and to use bitwise logical operators to manipulate them. Since Modula-2 provides set types (and no bitwise operators), it would be more convenient to translate individual integer constants and types to set constants and types.

- Example

#### Example

    struct s{
      unsigned int field;
    };
    typedef unsigned long BITSCALE;
    int variable;
    void long function(unsigned argument);
    char bitarray[10];
    #define constant 0x0011

    #variant s.field     : BITSET
    #variant BITSCALE    : BITSET
    #variant variable    : BITSET
    #variant function(0) : BITSET
    #variant bitarray[]  : SYSTEM.SET8
    #variant constant    : SYSTEM.SET16

    TYPE
      s = RECORD
        field: BITSET;
      END;

      BITSCALE = BITSET;

    VAR
      variable: BITSET;

    PROCEDURE function ( argument: BITSET );

    VAR
      bitarray: ARRAY [0..9] OF SYSTEM.SET8;

    CONST
      constant = SYSTEM.SET16{0, 4};

### Pointer type function parameters

In C, the actual semantics of a pointer type function parameter depends on that function and cannot be determined automatically. A function may interpret its parameter of type `T*` as either:

- pointer to T (type defined as `POINTER TO T`)
- single value passed by reference (`VAR T`)
- array (`ARRAY OF T`)
- array passed by reference (`VAR ARRAY OF T`)

where the corresponding Modula-2 formal types are given in parenthesis.

The `#variant directive` may be used to explicitly point out the semantics of each pointer type parameter.

Note: In order to keep original headers intact, `#variant` directives may be placed into the project file inside the corresponding `!header directive`.

- Example

#### Example

    #variant function(0) : VAR
    #variant function(1) : ARRAY
    #variant function(2) : VAR ARRAY

    void function(int*, int*, int*, int*);

is translated to:

    TYPE
      PtrSInt = POINTER TO SYSTEM.int;

    PROCEDURE function ( VAR arg0: SYSTEM.int;
                             arg1: ARRAY OF SYSTEM.int;
                         VAR arg2: ARRAY OF SYSTEM.int;
                             arg3: PtrSInt );

### Preserving constant names

By default, a `#define` directive introducing a constant is translated to a constant declaration:

`#define ENOTEXIST 10 CONST`
`ENOTEXIST = 10;`

This is the only way in case of a native code Modula-2 compiler, since such constants are substituted by a C preprocessor and do not appear in object files. But in case of a convertor to C, the original C headers will be used after conversion and it would be useful to refer to their names in the generated C text. Setting the GENROVARS option ON forces constants to be translated to read-only variables (Note: this is an XDS language extension). This option has no effect on generation for a native-code Modula-2 compiler.

The `#variant directive` may be used to specify a type for a variable:

`#define ENOTEXIST 10 VAR`
`#variant ENOTEXIST : CARDINAL ENOTEXIST-: CARDINAL;`