XTRAN Example — PL/M $INCLUDE Implies Typedef'd Data Type

The PL/M language doesn't have a mechanism like C's typedef.  In order to share STRUCTURE declarations across modules, some PL/M programmers use an $INCLUDE statement to fill in the body of a STRUCTURE.  Furthermore, PL/M programmers sometimes combine many such STRUCTURE bodies in one $INCLUDE file; the desired body is then selected using a $SET variable prior to the $INCLUDE statement.

When we translate such code to C, what we want is to use a typedef to establish each structure, and put those typedef declarations into %include files.

To facilitate this, XTRAN provides a mechanism, via a primitive in XTRAN's rules language ("meta-code"), called "include implies typedef".  Using this mechanism, we can tell XTRAN that when it sees a given combination of (optional) $SET statement and $INCLUDE statement, it is to parse a named $INCLUDE file for the corresponding TYPEDEF declaration, and is to ensure an appropriate #include statement in the resulting C code.  XTRAN also provides TYPEDEF as an extension to the PL/M language, for use with this feature.

The following example uses the standard set of XTRAN rules for parsing PL/M and translating it to C.  The input and output are untouched except for the parenthetical remarks added to the input.

NOTE that the translation shown below was done with default conditions.  XTRAN provides many options for controlling the way it translates.


Rules:

Rules that tell XTRAN to infer TYPEDEF declared structures from combinations of $INCLUDE files and $SET variables, using XTRAN's built-in primitive:

$INCLUDE file in
original source
TYPEDEF name to infer File to $INCLUDE to
declare
TYPEDEF
$SET name
foo:str1.plm str1_t demitd1.plm  
foo:str23.plm str2_t demitd2.plm setv2
foo:str23.plm str3_t demitd2.plm setv3
foo:str4.plm str4_t demitd4.plm setv4



Process Flowchart

Here is a flowchart for this process, in which the elements are color coded:

process flowchart

Input to XTRAN:  demitd.plm

(The following $INCLUDE statement will be translated as is, and will create an #include of demitd4.h in this module's C translation.)

$INCLUDE (foo:demitd0.plm)

        DECLARE ptr POINTER;

(The following DECLARE statements should turn into typedef declared declarations.)

        DECLARE extstr1 STRUCTURE
$INCLUDE (foo:str1.plm)
        EXTERNAL;

        DECLARE str1 STRUCTURE
$INCLUDE (foo:str1.plm)
        ;

        DECLARE str2
$NOLIST
$SET(setv2) INCLUDE (foo:str23.plm)
$LIST
        EXTERNAL;

        DECLARE str3
$NOLIST
$SET(setv3) INCLUDE (foo:str23.plm)
$LIST
        ;

        DECLARE str4 STRUCTURE (
$INCLUDE (foo:str1.plm)
        );

        DECLARE str5 BASED ptr
$NOLIST
$SET(setv3) INCLUDE (foo:str23.plm)
        ;
$LIST

$SET(setv2)
        DECLARE str6
$NOLIST
$INCLUDE (foo:str23.plm)
        ;
$LIST

(The following DECLARE statements are not in a legal form for "include implies type" processing, and therefore should not turn into typedef declared declarations.  XTRAN will parse the include files (issuing messages that it is doing so) and discard the $SET and $INCLUDE statements.)

        DECLARE str7 STRUCTURE (
$SET(setv4) $INCLUDE(foo:demitd5.plm)
          ,
$SET(setv5) $INCLUDE(foo:demitd6.plm)
          );

        DECLARE str8 STRUCTURE (
$SET(setv4) $INCLUDE(foo:demitd5.plm)
          ,
          str_memb3 DWORD,
$SET(setv5) $INCLUDE(foo:demitd6.plm)
          );
$SET (setv5)
        DECLARE str8a STRUCTURE (
$INCLUDE(foo:demitd6.plm)
          );

(The following case is a legal "include implies type" construction but hasn't been so described.  XTRAN will issue a warning and parse the include file.)

        DECLARE str9
$NOLIST
$SET(setv4) INCLUDE (foo:demitd3.plm)
$LIST
        EXTERNAL;

(Now some references to the declared STRUCTURE members, to show that they parse correctly.)

        str0.s4_memb2 = 0;
        str1.s1_memb1 = 1;
        extstr1.s1_memb2 = 2;
        str2.s2_memb1 = 3;
        str3.s3_memb1 = 4;
        str4.s1_memb1 = 5;
        str5.s3_memb1 = 6;
        str6.s2_memb1 = 7;
        str7.str_memb1 = 8;
        str7.str_memb5 = 9;
        str8.str_memb1 = 10;
        str8.str_memb3 = 11;
        str8.str_memb5 = 12;
        str9.str9_memb2 = 13;


Input to XTRAN:  demitd0.plm

(This file is unconditionally included by demitd.plm.)

        DECLARE str0
$NOLIST

(The following $INCLUDE contains spaces before and after the file name.  This is yet another undocumented PL/M "feature".)

$SET(setv4) INCLUDE ( foo:str4.plm )
$LIST
        ;


Input to XTRAN:  demitd1.plm

(This file is used by demitd.plm to declare a TYPEDEF data type.)

        DECLARE str1_t TYPEDEF STRUCTURE (
            s1_memb1 WORD,
            s1_memb2 DWORD
            );


Input to XTRAN:  demitd2.plm

(This file is used by demitd.plm to declare TYPEDEF data types.)

$IF (setv2)
        DECLARE str2_t TYPEDEF STRUCTURE (
            s2_memb1 WORD,
            s2_memb2 DWORD
            );
$RESET(setv2)
$ENDIF

$IF (setv3)
        DECLARE str3_t TYPEDEF STRUCTURE (
            s3_memb1 WORD,
            s3_memb2 DWORD
            );
$RESET(setv3)
$ENDIF


Input to XTRAN:  demitd3.plm

(This file will be parsed by XTRAN, because it hasn't been described via XTRAN's "include implies typedef" mechanism.)

$IF (setv4)
        STRUCTURE (
            str9_memb1 WORD,
            str9_memb2 DWORD
            )
$RESET(setv4)
$ENDIF


Input to XTRAN:  demitd4.plm

(This file is used by demitd.plm to declare a TYPEDEF data type.)

        DECLARE str4_t TYPEDEF STRUCTURE (
            s4_memb1 WORD,
            s4_memb2 DWORD
            );


Input to XTRAN:  demitd5.plm

(This file will be parsed by XTRAN, because it is used in DECLARE statements in a way that doesn't allow TYPEDEF inference via XTRAN's "include implies typedef" mechanism.)

            str_memb1 WORD,
            str_memb2 DWORD


Input to XTRAN:  demitd6.plm

(This file will be parsed by XTRAN, because it is used in DECLARE statements in a way that doesn't allow TYPEDEF inference via XTRAN's "include implies typedef" mechanism.)

$IF setv5
$LIST
        str_memb5 BYTE,
        str_memb6 WORD
$NOLIST
$RESET (setv5)
$ENDIF



Output from XTRAN:

#undef PP_SETV4
#define PP_SETV4 0xFF
#include "demitd4.h"
#include "demitd1.h"
#undef PP_SETV2
#define PP_SETV2 0xFF
#include "demitd2.h"
#undef PP_SETV3
#define PP_SETV3 0xFF
#include "demitd2.h"
#include "demitd0.h"

        static void *ptr;
        extern Str1_t extstr1;

        static Str1_t str1;

        extern Str2_t str2;

        static Str3_t str3;

        static Str1_t str4;

        static Str2_t str6;

        static struct
            {
            unsigned short str_memb1;

            unsigned long str_memb2;
            unsigned char str_memb5;

            unsigned short str_memb6;
            }
            str7;

        static struct
            {
            unsigned short str_memb1;

            unsigned long str_memb2;
            unsigned long str_memb3;
            unsigned char str_memb5;

            unsigned short str_memb6;
            }
            str8;
#undef PP_SETV5
#define PP_SETV5 0xFF
        static struct
            {
            unsigned char str_memb5;
            unsigned short str_memb6;
            }
            str8a;

        extern struct
            {
            unsigned short str9_memb1;
            unsigned long str9_memb2;
            }

            str9;

        str0.s4_memb2 = 0;
        str1.s1_memb1 = 1;
        extstr1.s1_memb2 = 2;
        str2.s2_memb1 = 3;
        str3.s3_memb1 = 4;
        str4.s1_memb1 = 5;
        ((Str3_t *) ptr)->s3_memb1 = 6;
        str6.s2_memb1 = 7;
        str7.str_memb1 = 8;
        str7.str_memb5 = 9;
        str8.str_memb1 = 10;
        str8.str_memb3 = 11;
        str8.str_memb5 = 12;
        str9.str9_memb2 = 13;


Messages from the run:

demitd.plm(92):  XTRAN -- Substituting INCLUDE file demitd5.plm
demitd.plm(94):  XTRAN -- Substituting INCLUDE file demitd6.plm
demitd.plm(98):  XTRAN -- Substituting INCLUDE file demitd5.plm
demitd.plm(101):  XTRAN -- Substituting INCLUDE file demitd6.plm

demitd.plm(106):  ?XTRAN nonfatal error; status = -162:
          );
            ^
%No typedef rule for this [[$SET and]] $INCLUDE in a DECLARE; will substitute!

demitd.plm(104):  XTRAN -- Substituting INCLUDE file demitd6.plm

demitd.plm(116):  ?XTRAN nonfatal error; status = -162:
        EXTERNAL;
                 ^
%No typedef rule for this [[$SET and]] $INCLUDE in a DECLARE; will substitute!

demitd.plm(112):  XTRAN -- Substituting INCLUDE file demitd3.plm