12. User-supplied header files

Relogix can be used to port assembler to C with little or no manual intervention. Sometimes, however, you may want to improve the quality of the translation by providing your own data types and function prototypes, or by cleaning up the header files which Relogix automatically produces, and feeding the results back to improve the whole translation. You may also need to tell Relogix about external interfaces which it cannot analyze itself.

You can do this by providing your own header files (these are of the same format as standard C headers, with some additional #pragma information). These can contain six types of extra information to help Relogix in its translation or to fine-tune the generated code:

  • You can optionally provide type definitions for variables and function parameters. Any type information you provide in these header files takes precedence over types which Relogix determines itself.
  • You can optionally provide your own function prototypes for the C functions corresponding to assembler subroutines, together with #pragma statements to specify the mapping between assembler subroutines and C functions.
  • If the original assembler called external C functions, or included subroutines originally called from C, you will need to provide your own header-file entries for them. This is necessary because Relogix is not able to analyze external interfaces as part of its normal assembler translation, and so it will not be able to see the how the external code interfaced to the original assembler code.
  • You can also use the header file to tell Relogix about operating-system calls which the original assembler code accessed by using exceptions or software interrupts. (In the 680x0 family, these are the TRAP instruction or an 'A-line' or 'F-line' trap; in the x86 family, the INT instruction.) These will be replaced by standard C calls in the form you specify.
  • You can provide your own enum or #define statements to define the C versions of assembler equates. Although this is never essential, you may prefer to provide your own definitions, for example to define them in a consistent style or to allow the same headers to be used in different projects.
  • You can provide #pragma statements to specify that you want to use a different name in the translated files for a particular assembler symbol.

Example of translation supplying your own header file

As an example of how supplying your own header file changes the translation, suppose we re-translate the file sample.sa as described at the start of this tour, but supplying this header file, tokens.h:

/* User-supplied header file for sample.sa */

// Define our own C version of the structure
struct obj_token 
      char   tokchar;
      char   tokalt;
      unsigned long *tokbuf;
      long   tokctr;

// Define our own equate
#define  ENDMARK 0x80000000 // Marker for end of token list

// Define our function prototype
void copy_token_block (unsigned long *dest, struct obj_token *ot);

// Tell Relogix where the function parameters are to be found
// and how the name of our prototype corresponds to the 
// assembler label
#pragma rlx internal copy_token_block, asm_name=MOVETOK
#pragma rlx parameter void copy_token_block (A1, A0)

The translation shown at the beginning of this tour would now be changed as follows:

*                                                              *
*       "sample.c" - Translated from file "sample.sa"          *
*                                                              *
*                                                              *
*    Relogix Code Translator Copyright (c) MicroAPL 1990-2017  *
*                All Rights Reserved Worldwide                 *
*                                                              *
* Translated on Fri Mar 17 11:35:20 2017 by Relogix version 1.8.1
* Relogix Licence Number #10000
* Non-default options specified:
*     -header tokens.h    - Filename(s) of C header files to read

#include "rlx68k.h"
#include "tokens.h"
#include "sample.h"

* copy_token_block                                            *
* Routine to move token block to buffer
* Parameters:
*    unsigned long *dest                [Originally in a1; In]
*    struct obj_token *ot               [Originally in a0; In]
void copy_token_block (unsigned long *dest, struct obj_token *ot)
    long i;                          /* [Originally in d0] */
    unsigned long *p;                /* [Originally in a0] */
    unsigned long token;             /* [Originally in d1] */

    i = ot->tokctr;

    if (i != 0 && ot->tokbuf != NULL) {
        p = ot->tokbuf;
        do {
            token = *p++;            /* Get token  */

            /* Hit end marker?
            if (token == ENDMARK)
            *dest++ = token;         /* Move into destination */
        } while (--i != 0);

If you compare this with the original translation, you will see that:

  • Relogix has included an extra #include statement, to include the user-supplied header file in the final code;
  • The name of the function has been changed to copy_token_block;
  • The order of the parameters has been reversed, and they have been renamed;
  • The structure name has been changed. In addition, it will no longer be defined in sample.h because the user-supplied header file already contains the definition.