# Translation Rules

- Comments
- Identifiers
- Types
- Type synonyms
- Variables
- Function prototypes
- Non-standard qualifiers
- Preprocessor directives
- Non-standard preprocessor directives
- Module names

## Comments

All comments from the original C text are copied to generated definition modules. Their placement, however, is not preserved in some cases. The COMMENTPOS option may be used to align comments which are placed next to declarations.

C++ compilers are usually able to recognize C++-style comments (beginning with '`//`') even while operating in C mode. The CPPCOMMENTS option controls whether H2D recognizes such comments as well.

## Identifiers

In most cases, H2D preserves original C identifiers. Exceptions are structure, union, and enumeration tags, which constitute a separate name space in C. If there is a constant, type, variable, or function identifier which coincides with a tag, H2D appends "`_struct`", "`_union`" or "`_enum`" to that tag.

In some situations, H2D itself generates additional identifiers, e.g. for unnamed function arguments, derived types, and formal types.

H2D may append digits to generated identifiers to avoid conflicts with existent ones.

Identifiers matching Modula-2 keywords are not allowed in source files. However, Modula-2 pervasive identifiers (e.g. `INTEGER` or `HALT`) are permitted.

- Example

### Example

The following C declarations were taken from the `sys/stat.h` file:

    struct stat { ... };
    int stat( const char *, struct stat * );

    TYPE stat_struct = RECORD ... END;
         PtrChar = POINTER TO CHAR;
    PROCEDURE stat(arg0: PtrChar; arg1: stat_struct): SYSTEM.int;

## Types

C types are translated to Modula-2 types according to the following table:

C type | Modula-2 type
base (`int`, `char`, etc.) | (see Base types mapping)
`void*` | `SYSTEM.ADDRESS`
pointer | pointer
array | array
enumeration | (see Enumeration)
structure | record
union | variant record
pointer to function | procedure type

Notes:

- Structure, union, and enumeration tags are not preserved in cases of collision. It may cause problems with Modula-2 to C convertors (e.g. XDS-C). See Identifiers.

- Examples
- Derived types
- Enumeration

### Examples

    struct STRUCTURE{       TYPE STRUCTURE = RECORD
      int    field1;            field1: SYSTEM.int;
      char   field2;            field2: CHAR;
      double field3;            field3: LONGREAL;
    };                        END;

    union  UNION {          TYPE UNION = RECORD
      int    field1;            CASE : INTEGER OF
      char   field2;             0: field1: SYSTEM.int;
      double field3;            |1: field2: CHAR;
    };                          |2: field3: LONGREAL;
                                END;
                              END;

### Derived types

For objects declared as having derived types (pointer or array) either a new Modula-2 type is introduced or a previously declared type synonym is used to improve readability. For pointers to base types, a new type is always declared.

In particular, a C structure may contain fields which type is defined as pointer to that structure. In this case H2D also automatically inserts a necessary forward pointer type declaration.

This may cause type compatibility problems. Fortunately, in XDS, compatibility rules for foreign objects are relaxed, e.g. two "C" pointer types are compatible if their base types are the same. Additional setup or postprocessing may be required when H2D is used with third-party Modula-2 compilers.

    char *str1;             TYPE
    char *str1;               H2D_PtrSChar = POINTER TO CHAR;

                            VAR
                              str1: H2D_PtrSChar;
                              str2: H2D_PtrSChar;

    struct s {              TYPE
      int i;                  s = RECORD
    };                          i: SYSTEM.int;
                              END;
    struct s *p;              H2D_Ptrs = POINTER TO s;

                            VAR
                              p: H2D_Ptrs;

    struct s {              TYPE
      int i;                  s = RECORD
    };                          i: SYSTEM.int;
                              END;

    typedef struct s *ps;     ps = POINTER TO s;

    struct s *p;            VAR
                              p: ps;

    struct Node {           TYPE
       int i;                 PtrNode = POINTER TO Node;
       struct Node *next;     Node = RECORD
    };                          i: SYSTEM.int;
                                next: PtrNode;
                              END;

### Enumeration

An enumeration (`enum`) is not actually a distinct type in C --- it is just a convenient way to declare integer constants (but in C++ enumeration is a distinct type). Moreover, since it is possible in C to explicitly specify enumeration constant value, translation to Modula-2 enumeration type may be incorrect. H2D may translate C enumerations into either Modula-2 enumeration types or Modula-2 constant declarations, depending on the GENENUM option setting. For instance, if GENENUM is set to `"Const"` or `"Mixed"`, the following C type synonym declaration:

`typedef enum{ one=1, two } Number;`

will be translated to

        (* H2D: enumerated type: Number *)
        CONST
          one = 1;
          two = 2;
        TYPE
          Number = SYSTEM.int;
        (* H2D: End of enumerated type: Number *)

If GENENUM is set to `"Enum"`, the same declaration will be translated unsafely (a warning comment will be added):

        TYPE
          Number = (
            one, (* H2D: integer value was 1 *)
            two
          );

## Type synonyms

C declarations of type synonyms (`typedef`) are translated to Modula-2 type declarations. If there are multiple synonyms declared for a type, their equivalence is preserved:

    typedef char String[256];  TYPE String = ARRAY [0..255] OF CHAR;
    typedef String *PString;        PString = POINTER TO String;
    typedef String *Buffer;         Buffer = PString;

Note: In C, function type synonyms may be used in function declarations. These synonyms are processed in a way they are processed by a C compiler and do not appear in output files (see Function prototypes).

## Variables

Variables are translated to variables. Variables declared with the `const` qualifier are translated to read-only variables (XDS extension). The `volatile` qualifier is currently ignored.

    extern int i;              VAR i  : SYSTEM.int;
    extern const int j;        VAR j- : SYSTEM.int;

## Function prototypes

C function prototypes declared as `void` are translated to proper procedure declarations; other are translated to function procedure declarations. If there is no name specified for a function parameter, `arg` x is substituted, where x is a number unique for each unnamed parameter.

In C, a derived type (more precisely, pointer or array) may be specified for a function parameter. In Modula-2, the formal type of a procedure parameter have to be either type name or open array type. H2D translates parameters of array type to open array value parameters.

The translation procedure for pointers is more complicated. By default, H2D searches for a type synonym, previously declared via `typedef`. The synonym, if found, is used as formal type; otherwise H2D automatically declares one. If automatic declaration is undesirable, required synonyms may be declared in the project file. Other variants of translation may be explicitly specified by means of the `#variant directive`.

See also Non-standard qualifiers.

- Examples

### Examples

    void p(int,int);              PROCEDURE p ( arg0 : SYSTEM.int;
                                                arg1 : SYSTEM.int );

    int f(char c);                PROCEDURE f ( c : CHAR ): SYSTEM.int;

    void P(T *t);                 TYPE PtrT = POINTER TO T;
                                  PROCEDURE P ( t : PtrT );

    void Q(T t[])                 PROCEDURE Q ( t : ARRAY OF T );

    int strlen(char *);           PROCEDURE strlen ( arg0 : ARRAY OF CHAR )
    #variant strlen(0) : ARRAY                     : SYSTEM.int;

## Non-standard qualifiers

In practice, header files are not "pure" ANSI C. The most common extension is a set of additional keywords (qualifiers) which may be used to specify calling/naming conventions used in a particular library or API.

Since XDS provides the similar mechanism called direct language specification (DLS), H2D recognizes a number of such keywords, which are translated to the following DLS strings:

C keyword | DLS String
`cdecl` | none
`fortran` | none
`interrupt` | none
`pascal` | `"Pascal"` for types and variables
| `"StdCall"` for functions
`syscall` | `"Syscall"`

`near`, `far`, and `huge` qualifiers are recognized but ignored.

## Preprocessor directives

- Macro definitions
- File inclusion
- Conditional compilation
- Other directives

### Macro definitions

A `#define` C preprocessor directive may contain an object-like definition or a function-like definition which are translated differently.

`#define identifier Text`

If `Text` is a constant expression, the directive is translated to a constant declaration or a read-only variable declararion (see Preserving constant names). If `Text` is a type identifier, the directive is translated to a type declaration. If `Text` is an identifier of a function, a macro definition, or a constant, the directive is translated to a constant declaration. In all other cases, it is interpreted in a C preprocessor manner.

`#define identifier"(" idenifier, { identifier } ")" Text`

Translated to a proper procedure declaration with all parameters having type `ARRAY OF SYSTEM.BYTE`. These declarations are marked with a special comment and may be corrected after translation to reflect the actual semantics of a macro by changing parameter types and/or adding return types. See also Native code for information about macro prototype modules.

`#undef identifier`

Undefines `identifier` as it is done by a C preprocessor.

- Example

#### Example

    #define str_constant "Hello World!\n"

    #define constant 0x10
    #define constant_synonym constant

    #define macro_with_params(p1,p2,p3) p1+p2+p3
    #define macro_with_params_synonym macro_with_params

    int function(int);
    #define function_synonym function

    typedef int INT;
    #define INTEGER INT

    CONST
      str_constant = 'Hello World!' + 12C;
      constant = 10H;
      constant_synonym = constant;

    <* IF __GEN_C__ THEN *>

    (* H2D: this procedure was generated from Macro. *)
    PROCEDURE macro_with_params ( p1, p2, p3: ARRAY OF SYSTEM.BYTE );

    <* ELSE *>

    PROCEDURE  / macro_with_params ( p1, p2, p3: ARRAY OF SYSTEM.BYTE );

    <* END *>

    <* IF __GEN_C__ THEN *>

    CONST
      macro_with_params_synonym = macro_with_params;

    <* END *>

    PROCEDURE function ( arg0: SYSTEM.int ): SYSTEM.int;

    CONST
      function_synonym = function;

    TYPE
      INT = SYSTEM.int;

      INTEGER = SYSTEM.int;

### File inclusion

    #include <file_name>
    #include "file_name"

If the file specified by `file_name` has to be merged with the current file (see Headers merging), H2D treats this directive exactly as a C preprocessor, i.e. replaces it with contents of a specified file. Otherwise, `file_name` is added to the import list and the file specified by it is translated into a separate definition module. If `file_name` contains directories, the output files are placed to the same subdirectory.

The GENLONGNAMES option controls conversion of included header file names which contain path:

`#include <sys/stat.h>`

is translated to

`IMPORT stat;`

if GENLONGNAMES is OFF and to

`IMPORT sys_stat;`

if GENLONGNAMES is ON.

See also Module names.

### Conditional compilation

H2D handles conditional compilation directives `#if`, `#ifdef`, `#ifndef`, `#else`, and `#endif` the same way as a C preprocessor does. A project file may be used to define constants which are used in arguments of these directives.

### Other directives

H2D recognizes and ignores `#line`, `#error`, and `#pragma` C preprocessor directives.

## Non-standard preprocessor directives

H2D recognizes two non-standard preprocessor directives: `#merge` and `#variant`. These directives are related to definiton module generation only and do not affect the C text, so they may be placed arbitrarily in a header file. Typically they are collected in project files inside a corresponding `!header directive`.

The advanced technique is to put these directives right into working copies of header files, next to the corresponding declarations. Then, after successful translation of all headers, these directives may be extracted with the help of GENDIRS option and moved to the project file. Now original headers may be used for translation.

- #merge
- #variant

### #merge

    #merge ( <file_name> | "file_name" )

This directive lists included header files which should be merged even if the MERGEALL option is OFF. This feature may be useful in some cases (see Headers merging).

When placed in a header file, this directive has effect only in this file. When placed in a project file, it has effect in all headers matching the surrounding `!header directive`.

### #variant

    #variant Designator ":" Type
    Designator = identifier { "^" | "[ ]" | "." identifier } |
                 Parameter
    Parameter  = identifier "(" number ")"
    Type       = qualident

This form of the `#variant` directive allows to explicitly specify a Modula-2 `Type` for an object denoted by `Designator`. See Base types mapping for more information.

`Designator` specifies a named object or its element which is subject to the `#variant` directive:

`"^"` | pointer dereference
`"[ ]"` | array indexing
`"." identifier` | structure or union field selection

`Parameter` specifies a function `identifier` and its parameter `number` (zero-based).

    #variant Parameter  ":" ( "VAR" | "ARRAY" | "VAR ARRAY" )

This form is used to control translation of a function `Parameter`, which has a pointer type.

By default, pointer type function parameters are translated to pointer type procedure parameters (see Function prototypes). The `#variant` directive allows to specify one of the following alternative rules for a particular parameter:

`Modifier` | `T *p` is translated to
`VAR` | `VAR p: T`
`ARRAY` | `p: ARRAY OF T`
`VAR ARRAY` | `VAR p: ARRAY OF T`

See also Pointer type function parameters.

    #variant f(0) : VAR ARRAY
    void f(char*);

    PROCEDURE f ( VAR arg0: ARRAY OF CHAR );

A `#variant` directive has effect only in the file where it is located, or, if specified in a project file, in all files matching the surrounding `!header` directive. Therefore, `Designator` should specify an object declared in this file or in one of the files which it includes. If an object specified by `Designator` is not present, an error message is displayed.

## Module names

By default, H2D uses a header file name without "`.h`" extension as a definition module name. If a file name contains characters which are not allowed in identifiers, the `!name directive` must be used in a project file to specify a proper identifier.