Generating C from SPLash!

The SPLash! compiler has some ability to generate C output source code from SPLash! input source. (sample output)

This feature is still under development, and the final product disposition has not been determined. We have not determined if it will be bundled into the SPLash! product, or offered as a separate product. At present, all SPLash! customers on support receive the feature for free, as a way of saying "thank you".

Please note that this SPLash!-to-C translation currently has some significant limitations (most importantly, in the handling of address-equated variables, the loss of defines (they're expanded in-line), and the loss of equates (they're expanded in-line)).

The SPLash! to C conversion is triggered by specifying "$PPC" in the SPLash! source being compiled (see the example at the end of this note).

PPC causes the SPLash! compiler to generate a file named SPLC, which contains the C source. (Note: the normal assembler source output is also generated, unless $NOGENCODE is specified.) PPC stands for "PrettyPrint in C format".

The only indication in the compiler output listing that PPC is in effect is a note at the end of the compilation, reporting the number of lines written to the SPLC file. For example:

   130 lines of C code generated (to SPLC).

The compiler will purge any prior SPLC file at the start of the compilation.

The PPC feature of the SPLash! compiler is still being refined. It is not a perfect SPL to C translator, and can probably never be 100% perfect (e.g., there might be a problem handling all assembly statements).

The resulting C source code is for ANSI C. If 64-bit pointers are being used, and HP's C compiler, then the "-Aa +e" should be used as C compiler flags.

The following discusses various aspects of SPLash! that may be difficult for PPC to handle.

0. csplash.h

Some of the C code generated assumes that csplash.h is available at C compile time. This file is shipped with the SPLash! compiler and should be edited with care, because new versions may contain bug fixes and/or new features.

1. csplash.c

Some of the C code generated assumes that the resulting object file will be linked with SPLASH.O, which can be generated by compiling csplash.c. This file contains "millicode" routines which provide runtime support for some SPLash! constructs, like "move".

2. Subroutines

SPLash! has two levels of "procedures": procedures, and nested within them, subroutines. C has only one level of procedure.

SPLash! handles subroutines by converting them into top-level procedures with an extra parameter. The extra parameter is a pointer to a structure holding the local variables of the original parent procedure. Additionally, those local variables in the original procedure are emitted as being part of a structure.

3. Assembler

Only the following assembler opcodes are implemented:

   ADAX ADBX ADD  ADXA ADXB AND  BTOW CAB  CLCY DADD DDEL DDIV
   DDUP DECA DECB DECX DEL  DELB DFLT DIV  DIVL DLSZ DMUL DNEG
   DSUB DUP  DXCH DZRO INCA INCB INCX LADD LDIV LDXA LDXB LSUB
   MPY  NEG  NOP  NOT  OR   STAX STBX SUB  XAX  XBX  XCH  XOR
   ZERO ZROB ZROX

4. TOS

TOS is supported.

5. Outer Block Entry Points

Alternate entry points for the outer block are not fully supported, because C has no such concept. The entry points have a label emitted of the form: Entry_<entryname>.

6. Procedure Entry Points

SPLash! handles entry points for procedures, although some C compilers (but not the HP3000 C/iX compiler) are annoyed that we don't generate a "forward" declaration for them.

If the procedure FACT has an entry point of FAC2, SPLash! will generate P_fact, fact, and fac2, where P_fact is the majority of the original FACT with an additional 'entry point' integer parameter, and a label called Entry_fac2 where the entry point for fac2 should occur. In addition, fact & fac2 are generated as simple procedures that call P_fact with different entry point numbers.

7. 64-Bit Pointers

SPLash! currently tries to emit 64-bit pointers using the HP C extended syntax of "^" instead of "*". Unfortunately, not all C compilers support declaring and using 64-bit wide pointers (in addition to 32-bit wide pointers).

The $PPSHORTPTRS option tells SPLash! to treat all 64-bit pointers as though they had been declared as 32-bit pointers.

At the end of compilation, SPLash! will note how many occurrences of 64-bit pointers were noticed (or converted), with a message like:

   ** Note: saw 1 64-bit pointers in $PPC, will need editing.
or:
   ** Note: converted 1 64-bit pointers in $PPC.

8. Comments

By default, SPLash! will emit C source without carrying over the original source code comments. The $PPCOMMENTS directive tells SPLash! to try to save the original comment(s) text, and emit it as close as possible to the equivalent C source location.

When $PPCOMMENTS is on, a C comment will also be generated at the start and end of text from $INCLUDE files.

9. Equivalenced Pointers (address equation)

The PPC output has a known problem in dealing with pointers that are equivalenced to each other.

For example, given the following:

   virtual double pointer
      ptr'd;

   virtual integer pointer
      ptr'i       = ptr'd;

   ...

   @ptr'i := @ptr'i (2);      ! equiv to @ptr'd := @ptr'd (1)

The PPC output does not know how to correctly initialize ptr'i, nor how to make changes to ptr'i reflect changes to ptr'd (and vice versa). SPLash! will generate an "unimplemented" warning at the point where ptr'i is declared (in the generated C source).

10. Intrinsics

By default, PPC emits "#pragma intrinsic" directives for each intrinsic used by the SPLash! source. This is desirable if the C source is being compiled on an HP3000, or on an HP9000 (assuming you have a /usr/local/lib/sysintr for the C compiler to access), but is not desirable for other target computers.

The $PPEXPANDINTRIN option tells the compiler to emit C-style headers for intrinsics instead of pragma directives.


Example (ugly) source code, for "FAC.SOURCE":
(With HTML links that point to the corresponding C output source)

$ppc              ! sends "C" source to file: SPLC
$ppcomments       ! sends comments to SPLC
begin integer array buf(0: 39); integer i,j,k,len,rslt;
fullvirtual byte pointer fvp;
byte array buf'(*)=buf; intrinsic ascii, print;
! Forward declarations
integer Procedure fac2(n); value n; integer n; option forward;
integer Procedure fact(n); value n; integer n; option forward;
procedure report; begin
@fvp := @buf'; len := move fvp:="Result = ";
len:=len+ascii(rslt,10,buf'(len)); print(buf,-len,0); end;
integer procedure fact(n); value n; integer n; begin
byte array foo'(*)=pb:="this is a test"; double dummyreg=reg;
entry fac2; subroutine sub; begin len:=move buf':="N = ";
len:=len+         ! add ascii's len
ascii(n,10,buf'(len)); print(buf,-len,0); end; sub; fac2:  if
logical(n).(15:01) then rslt:=n*(if n>1 then fac2(n-1) else 1)
else rslt:=n*(if n>1 then fact(n-1) else 1); report; fact:=rslt;
end; rslt:=fact(6); report; end.

Unedited output from SPLash! $PPC option: (well, edited for HTML links that point to the corresponding ugly SPLash! source)

/* C-code generated by SPLash! 96H on WED, OCT 23, 1996, 11:57 AM */
/* PPC PPCOMMENTS noPPEXPANDINTRIN PPLONGPTRS */

#include <ctype.h>
#include <setjmp.h>
#include <string.h>
#include "csplash.h"

INT16
   buf            [40];

INT16
   i,
   j,
   k,
   len,
   rslt;

char 
   ^fvp;

char
   *buf_          = (char *) (buf);

#pragma intrinsic ASCII
#pragma intrinsic PRINT /* Forward declarations*/

INT16 fac2 (INT16 n);
INT16 fact (INT16 n);
/*********************************************************/
void report ()
   {
   fvp = (char  ^) buf_;
   len = SPLash_move (fvp, "Result = ", 9);
   len = len + ASCII (rslt, 10, (void *) (&buf_ [len]));
   PRINT ((void *) (buf), -(len), 0);

   } /* end report proc */

/*********************************************************/

/* Start of typedef and subrs for procedure fact */

typedef struct    /* for subroutines of fact */
   {
   INT16
      Ret_fact;

   INT16
      n;

   char
      *foo_;

   INT32
      dummyreg;

   } VARS_fact;

   /* subroutine sub of procedure fact ... */
/*-------------------------------------------------------*/
static void fact_S_sub (VARS_fact *VARS)
   {
      {
      len = SPLash_move (buf_, "N = ", 4);
      len = len + ASCII (VARS->n, 10, (void *) (&buf_ [len]));
          /* add ascii's len*/
      PRINT ((void *) (buf), -(len), 0);
      }
   } /* end fact_S_sub subr */

   /*--- end of subroutines for fact ---*/
   /* start of main header for fact */
/*********************************************************/
INT16 P_fact (INT32 Entry, INT16 n)
   {
   VARS_fact
      VARS;

   VARS.Ret_fact = 0;

   VARS.n = n;
   VARS.foo_ = "this is a test";  /* PB */

      /* end of VARS init */

   switch (Entry)
      {
      case 1: goto Entry_fac2;
      }

   fact_S_sub (&VARS);

Entry_fac2:

   if (SPLash_extract ((UINT16) VARS.n, 31, 1))
      {
      rslt = VARS.n * ((VARS.n > 1) ? fac2 ( (VARS.n - 1)) : 1);
      }
   else
      {
      rslt = VARS.n * ((VARS.n > 1) ? fact ( (VARS.n - 1)) : 1);
      }
   report ();
   VARS.Ret_fact = rslt;
   return VARS.Ret_fact;

   } /* end P_fact proc */

INT16 fact (INT16 n)
   {
   P_fact (0, n);
   } /* end fact proc */

INT16 fac2 (INT16 n)
   {
   P_fact (1, n);

   } /* end fac2 (entry in fact) proc */

/*********************************************************/
INT32 main (INT32 argc, char *argv [], char **envp)
   {
   rslt = fact (6);
   report ();

   return 0;

   } /* end main proc */
/*********************************************************/
/* Note: saw 2 64-bit pointers, will need editing */

(Updated 2001-12-20)

Updated [3khat16.ico]HP3000 [3khat16.ico]3kMail [archive16.gif]