[comp.sys.m6809] piped c compiler source

harmon@abvax.UUCP (Larry Harmon) (10/21/87)

	A few months ago I started toying with the C compiler and found
that compiles could be significantly (30 - 40%) speeded up by using os9 pipes
between the first few passes instead of using temporary files.  So for
the last couple of months I have worked on the included program which replaces
the Microware cc1 program with an equivalent program which uses
pipes.  The program still needs touched up in places but it works fairly
well as is.
	One problem I have discovered is, when using piped and errors are
found in the source code the compiler doesn't exit cleanly, and sometimes
its necessary to use "Ctrl-e" to abort.  This seems to be a design limitation
of the C compiler in that succcessive passes were not intended to be
run if errors are encountered, but when all the passes are piped together
the later passes receive unexpected input.  What this means is this
compiling known good sources (Downloads / minor changes) works well with pipes
developing new code may be better off using temporary files until clean
compiles are obtained.

	If and when you find problems with this program please let me know.

					Larry Harmon

------------------------Start of Source code-----------------------------------

/*  Piped C Compiler                      "PCC"
 *
 *  Larry Harmon    (Copyright)           initial version        10/21/87
 *
 *
 *  This program is a replacement for the standard "cc1" C compiler driver
 *  suppilied by Microware. The program is completely compatable with
 *  "cc1" and provides two enhancements.  The first enhancement is the 
 *  utilization of OS9 pipes in the build passes where ever possible.
 *  This is enabled using the "Q" (quick) flag.  The second enhansement is the
 *  elimination of the "c.com" file produced by "cc1".  Instead the compiler
 *  commands are sent to stdout, which may be piped to shell.  This mode is
 * enabled using the "B" (bypass) flag.
 *
*/
#define direct
#include <stdio.h>
#include <ctype.h>

#define TRUE    1
#define FALSE   0

#define NUM_SRC 16
#define NUM_LIB 16
#define NUM_DEF 16

#define TO_END(x)   while( *x ) x++;

/*    Compiler Option Flags & Variables     */

/*      count source files, definitions, and libraries  on command line   */

direct char SRC_cnt,
            DEF_cnt,
            LIB_cnt = 0;

/*      option flags note the occurences of the command line options   */

direct char A_flag,
            B_flag,
            C_flag,
            E_flag,
            F_flag,
            M_flag,
            O_flag,
            P_flag,
            Q_flag,
            R_flag,
            S_flag = 0;

/*      memory size and edition number storage  */

direct int  M_size,
            E_num;

direct char *FILE_name,		/* output file name */
           *LIB_name[NUM_LIB],	/* library file names    */
           *SRC_name[NUM_SRC],	/* source file names  */
            SRC_type[NUM_SRC],	/* source file type  */
           *D_str[NUM_DEF];	/* pointers to definitions */

/*     storage for resultant command file     */

char    cmd_buffer[512];
direct FILE   *fp;

char   *build_prep_line (), *build_p1_line (), *build_p2_line ();
char   *build_opt_line (), *build_asm_line (), *build_link_line ();
char   *build_p_common (), *strrcpy ();

main (argc, argv)
int     argc;
char   *argv[];
{
    int     lp;
    register char  *tmp_ptr;
    char   *tmp_ptr2;
    if (!--argc)		/* if no parameter exists */
	usage ();		/*  NEVER RETURNS!! */
    else
    {
	argv++;			/* point past name to first parameter */
	parse_parms (argc, argv);/* collect parameters and file names */
	if (!SRC_cnt)		/* if no source files were specified */
	    usage ();		/*  NEVER RETURNS!! */
	if (B_flag)		/* bypass building c.com    */
	{
	    fp = stdout;	/* use stdout as a file */
	    fputs ("-p\n", fp);
	}
	else			/* build c.com file     */
	{
	    fp = fopen ("c.com", "w");/* open output file */
	}

	for (lp = 0; lp < SRC_cnt; lp++)/* process all src files  */
	{
	/*  print "echo 'filename' to c.com */
	    fputs ("echo \'", fp);
	    fputs (SRC_name[lp], fp);
	    fputs ("\'\n", fp);

	    if (SRC_type[lp] == 'c')
	    {
		fputs ("-x\n", fp);
				/* disable shell from stopping on error */

		tmp_ptr = build_prep_line (cmd_buffer, SRC_name[lp]);

	    /* change source extension for later use    */
		tmp_ptr2 = SRC_name[lp];
		TO_END (tmp_ptr2);
		tmp_ptr2--;
		if (A_flag || O_flag)
		    *tmp_ptr2 = 'a';
		else
		    *tmp_ptr2 = 'o';

		if (Q_flag)	/* build commands using pipes */
		{
		    *tmp_ptr++ = '!';
		    *tmp_ptr++ = ' ';
		    tmp_ptr = build_p1_line (tmp_ptr, "\0");
		    *tmp_ptr++ = ' ';
		    *tmp_ptr++ = '!';
		    *tmp_ptr++ = ' ';
		    tmp_ptr = build_p2_line (tmp_ptr, "\0");

		    if (!O_flag)/* use optimizer    */
		    {
			*tmp_ptr++ = ' ';
			*tmp_ptr++ = '!';
			*tmp_ptr++ = ' ';
			tmp_ptr = build_opt_line (tmp_ptr, "\0");
			fputs ("echo \"c.prep: ! c.pass1: ! c.pass2: ! c.opt:\"\n", fp);

			if (SRC_cnt > 1 || A_flag)
			{
			    tmp_ptr = strrcpy (tmp_ptr, " > ");
			    tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
			    *tmp_ptr++ = '\n';
			    *tmp_ptr = '\0';
			}
			else
			    strcpy (tmp_ptr, " > ctmp.3.o\n");

		    }
		    else	/* don't use optimizer pass */
		    {
			fputs ("echo \"c.prep: ! c.pass1: ! c.pass2:\"\n", fp);

			if (SRC_cnt > 1 || A_flag)
			{
			    tmp_ptr = strrcpy (tmp_ptr, " > ");
			    tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
			    *tmp_ptr++ = '\n';
			    *tmp_ptr = '\0';
			}
			else
			    strcpy (tmp_ptr, " > ctmp.3.a\n");
		    }

		    fputs (cmd_buffer, fp);
				/* write command line to file   */

		    fputs ("x\n", fp);/* enable shell to stop on error */
		}
		else		/* no q flag - don't use pipes     */
		{
		    fputs ("echo c.prep:\n", fp);
		    strcpy (tmp_ptr, " > ctmp.3.m\n");
		    fputs (cmd_buffer, fp);
		    fputs ("x\n", fp);/* enable shell to stop on error */

		    fputs ("echo c.pass1:\n", fp);
		    tmp_ptr = build_p1_line (cmd_buffer, "ctmp.3.m");
		    strcpy (tmp_ptr, "-o=ctmp.3.i\n");
		    fputs (cmd_buffer, fp);
		    fputs ("del ctmp.3.m\n", fp);

		    fputs ("echo c.pass2:\n", fp);
		    tmp_ptr = build_p2_line (cmd_buffer, "ctmp.3.i");
		    tmp_ptr = strrcpy (tmp_ptr, "-o=");

		    if (A_flag || O_flag)/* quit at assembler source */
		    {
			tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
			*tmp_ptr++ = '\n';
			*tmp_ptr = '\0';
			fputs (cmd_buffer, fp);
			fputs ("del ctmp.3.i\n", fp);
		    }
		    else	/* do optimizer step  */
		    {
		    /* finish building pass2 line   */
			strcpy (tmp_ptr, "ctmp.3.a\n");
			fputs (cmd_buffer, fp);
			fputs ("del ctmp.3.i\n", fp);

			fputs ("echo c.opt:\n", fp);
			tmp_ptr = build_opt_line (cmd_buffer, "ctmp.3.a");
			*tmp_ptr++ = '>';
			*tmp_ptr++ = ' ';
			if (SRC_cnt > 1)
			{
			    tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
			}
			else
			{
			    tmp_ptr = strrcpy (tmp_ptr, "ctmp.3.o");
			}
			*tmp_ptr++ = '\n';
			*tmp_ptr = '\0';
			fputs (cmd_buffer, fp);
			fputs ("del ctmp.3.a\n", fp);
		    }
		}

		if (!A_flag)	/* dont stop at assembler source    */
		{

		    fputs ("echo c.asm:\n", fp);
		    tmp_ptr = build_asm_line (cmd_buffer);
		    if (SRC_cnt > 1)
		    {
			tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
			tmp_ptr = strrcpy (tmp_ptr, " -o=");
			tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
			tmp_ptr--;
			*tmp_ptr++ = 'r';
			*tmp_ptr++ = '\n';
			*tmp_ptr = '\0';
			fputs (cmd_buffer, fp);

			fputs ("del ", fp);
			fputs (SRC_name[lp], fp);
			fputs ("\n", fp);

		    /* change source extension for later use    */
			tmp_ptr = SRC_name[lp];
			TO_END (tmp_ptr);
			tmp_ptr--;
			*tmp_ptr = 'r';

		    }
		    else
		    {		/* specify input file name  */
			if (O_flag)
			    tmp_ptr = strrcpy (tmp_ptr, "ctmp.3.a");
			else
			    tmp_ptr = strrcpy (tmp_ptr, "ctmp.3.o");

			if (R_flag)
			{
			    tmp_ptr = strrcpy (tmp_ptr, " -o=");
			    tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
			    tmp_ptr--;
			    *tmp_ptr++ = 'r';
			    *tmp_ptr++ = '\n';
			    *tmp_ptr++ = '\0';
			}
			else
			{
			    strcpy (tmp_ptr, " -o=ctmp.3.r\n");
			}

			fputs (cmd_buffer, fp);
			if (O_flag)
			    fputs ("del ctmp.3.a\n", fp);
			else
			    fputs ("del ctmp.3.o\n", fp);

		    }
		}
	    }

	    else
		if (SRC_type[lp] == 'a')
		{
		/*  print "echo 'filename' to c.com */

		    if (!O_flag)
		    {
			fputs ("echo c.opt:\n", fp);
			tmp_ptr = build_opt_line (cmd_buffer, SRC_name[lp]);
			strcpy (tmp_ptr, " > ctmp.3.o\n");
			fputs (cmd_buffer, fp);

		    }
		    fputs ("echo c.asm:\n", fp);
		    tmp_ptr = build_asm_line (cmd_buffer);

		    if (O_flag)
			tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
		    else
			tmp_ptr = strrcpy (tmp_ptr, "ctmp.3.o");

		    tmp_ptr = strrcpy (tmp_ptr, " -o=");

/* change the extension to .r  */
		    tmp_ptr2 = SRC_name[lp];
		    TO_END (tmp_ptr2);
		    tmp_ptr2--;
		    *tmp_ptr2++ = 'r';

		    tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
		    *tmp_ptr++ = '\n';
		    *tmp_ptr = '\0';
		    fputs (cmd_buffer, fp);

/* delete the intermediate optimized source */
		    tmp_ptr = cmd_buffer;
		    tmp_ptr = strrcpy (tmp_ptr, "del ");
		    tmp_ptr = strrcpy (tmp_ptr, SRC_name[lp]);
		    tmp_ptr--;
		    *tmp_ptr++ = 'o';
		    *tmp_ptr++ = '\n';
		    *tmp_ptr = '\0';
		    fputs (cmd_buffer, fp);
		}
	}			/* end of SRC loop  */

	if (!R_flag)
	{
	    fputs ("echo c.link:\n", fp);
	    tmp_ptr = build_link_line (cmd_buffer, SRC_name[lp]);
	    *tmp_ptr++ = '\n';
	    *tmp_ptr = '\0';
	    fputs (cmd_buffer, fp);

	    if (SRC_cnt == 1)
		fputs ("del ctmp.3.r\n", fp);
	}
	if (!B_flag)
	{
	    fclose (fp);
	    system ("c.com\n");
	}
	else
	    fputs ("p\n", fp);

    }
}

/********************************************/
/*     Parse the command line parameters     */
/********************************************/

parse_parms (argc, argv)
int     argc;
char  **argv;
{
    register char  *parm;
    char   *tmp_ptr;
    char    lp;

 /*  Clear all pointers  */

    for (lp = 0; lp < NUM_SRC; lp++)

    {
	SRC_name[lp] = (char *) 0;
    }

    for (lp = 0; lp < NUM_LIB; lp++)
    {
	LIB_name[lp] = (char *) 0;
    }

    for (lp = 0; lp < NUM_DEF; lp++)
    {
	D_str[lp] = (char *) 0;
    }

 /* Clear local counters */

    do
    {				/*      PROCESS ALL PARAMETERS      */
	parm = *argv++;		/* point at next parameter  */
#ifdef DEBUG
	printf ("Parameter %d is %s\n", argc, parm);
#endif
	if (*parm == '-')	/* if first character is a '-' its an
				   option    */
	{

	    while (*++parm)	/*  PROCESS ALL CHARACTERS IN OPTION
				   STRING */
	    {			/* point to option char */
		*parm = toupper (*parm);
		switch (*parm)
		{
		    case 'A': 	/*      suppress assembly   */
			A_flag = TRUE;
#ifdef DEBUG
			printf ("Assembler option -A\n");
#endif
			break;

		    case 'B': 	/*      bypass building c.com   */
			B_flag = TRUE;
#ifdef DEBUG
			printf ("Bypass c.com flag -B\n");
#endif
			break;

		    case 'C': 	/*      comment assembler output with C
				   source code      */
			C_flag = TRUE;
#ifdef DEBUG
			printf ("C-code in Assembler option -C\n");
#endif
			break;

		    case 'D': 	/*      command line definition */
#ifdef DEBUG
			printf ("Command line definition = %s\n", parm);
#endif
			if (DEF_cnt < NUM_DEF)
				/*   only fixed amount allowed   */
			{
			    *parm = tolower (*parm);
			    D_str[DEF_cnt++] = parm;
			}
			else
			{
			    printf ("Too many definitions\n");
			    exit (FALSE);
			}
			while (parm[1])
			    parm++;
			break;

		    case 'E': 	/*      Specify edition number  */
			E_flag = TRUE;
#ifdef DEBUG
			printf ("Command line edition  = %s\n", parm);
#endif
			if (!((*++parm == '=') &&
				    sscanf (++parm, "%d", &E_num)))
			{
			    printf ("Invalid edition %s\n", parm);
			    exit (FALSE);
			}
			while (parm[1])
			    parm++;
			break;

		    case 'O': 	/*      Bypass optimizer pass   */
			O_flag = TRUE;
#ifdef DEBUG
			printf ("Optimizer option -O\n");
#endif
			break;

		    case 'P': 	/*      generate profiler code  */
#ifdef DEBUG
			printf ("Profiler option -P\n");
#endif
			P_flag = TRUE;
			break;

		    case 'Q': 	/*      use pipes where possible    */
#ifdef DEBUG
			printf ("Quick option -Q\n");
#endif
			Q_flag = TRUE;
			break;

		    case 'M': 	/*      specify memory size     */
			M_flag = TRUE;
#ifdef DEBUG
			printf ("Command line memory  = %s\n", parm);
#endif
			if (!((*++parm == '=') &&
				    sscanf (++parm, "%d", &M_size)))
			{
			    --parm;
			    --parm;
			    printf ("Invalid Memory %s\n", parm);
			    exit (FALSE);
			}
			while (parm[1])
			    parm++;
			break;

		    case 'L': 	/*  use specified library   */
#ifdef DEBUG
			printf ("Library option = %s\n", parm);
#endif
			if (LIB_cnt < NUM_LIB && parm[1] == '=')
			/*      only fixed amount allowed   */
			{
			    *parm = tolower (*parm);
			    LIB_name[LIB_cnt++] = parm;
			}
			else
			{
			    printf ("Too many libraries\n");
			    exit (FALSE);
			}

			while (parm[1])
			    parm++;
			break;

		    case 'F': 	/*  specify output file name    */
			F_flag = TRUE;
#ifdef DEBUG
			printf ("Filename option = %s\n", parm);
#endif
			if (parm[1] != '=')
			{
			    printf ("Invalid Filename %s\n", parm);
			    exit (FALSE);
			}
			FILE_name = &parm[2];
			while (parm[1])
			    parm++;
			break;

		    case 'S': 	/*  inhibit stack shecking code */
			S_flag = TRUE;
#ifdef DEBUG
			printf ("Stack checking option -S\n");
#endif
			break;


		    default: 
			{
			    printf ("Unknown option %s\n", parm);
			    exit (FALSE);
			}
			break;
		}		/* end of switch statement  */
	    }			/* end of while loop - charecters in
				   parameter string  */
	}
	else			/* parameter must be a file name */
	{
	    tmp_ptr = parm;
	    TO_END (tmp_ptr);
	    tmp_ptr -= 2;
	    if (*tmp_ptr++ == '.')/* has 1 character extension */
	    {
		if (*tmp_ptr == 'c' || *tmp_ptr == 'a' || *tmp_ptr == 'r')
		{
#ifdef DEBUG
		    printf ("source = %s\n", parm);
#endif
		    if (SRC_cnt < NUM_SRC)/* room left in source array */
		    {
			SRC_type[SRC_cnt] = *tmp_ptr;
			SRC_name[SRC_cnt++] = parm;
			if (!F_flag)
			    FILE_name = parm;
		    }
		    else
		    {
			printf ("Too many sources %s\n", parm);
			exit (FALSE);
		    }
		}
		else
		{
		    printf ("Unknown source type %s\n", parm);
		    exit (FALSE);
		}
	    }
	    else
	    {
		printf ("Unknown source type %s\n", parm);
		exit (FALSE);
	    }
	}
    } while (--argc);		/* end of do loop - command line
				   parameters */
}

/*
  **
*/

char   *build_prep_line (buf_ptr, src_name)
char   *buf_ptr,
       *src_name;
{
    int     lp;
    buf_ptr = strrcpy (buf_ptr, "C.PREP ");

    buf_ptr = strrcpy (buf_ptr, src_name);
    *buf_ptr++ = ' ';

    if (C_flag)			/* include C src in assembler outout    */
    {
	buf_ptr = strrcpy (buf_ptr, "-l ");
    }

    if (E_flag)			/* command line edition needs to be used  
				        */
    {
	sprintf (buf_ptr, "-E=%d ", E_num);
	TO_END (buf_ptr);
    }

/* process command line defines    */
    for (lp = 0; lp < DEF_cnt; lp++)
    {
	*buf_ptr++ = '-';
	buf_ptr = strrcpy (buf_ptr, D_str[lp]);
	*buf_ptr++ = ' ';
	*buf_ptr = '\0';
    }

    return (buf_ptr);		/* return pointer to end of string  */
}

/*
  **
*/

char   *build_p1_line (buf_ptr, src_name)
char   *buf_ptr,
       *src_name;
{
    int     lp;
    buf_ptr = strrcpy (buf_ptr, "C.PASS1 ");

    buf_ptr = build_p_common (buf_ptr, src_name);

    return (buf_ptr);		/* return pointer to end of string */
}

/*
  **
*/

char   *build_p2_line (buf_ptr, src_name)
char   *buf_ptr,
       *src_name;
{
    int     lp;
    buf_ptr = strrcpy (buf_ptr, "C.PASS2 ");

    buf_ptr = build_p_common (buf_ptr, src_name);

    return (buf_ptr);		/* return pointer to end of string  */
}

/*
  **
*/

char   *build_p_common (buf_ptr, src_name)
char   *buf_ptr,
       *src_name;
{
    if (*src_name)
    {
	buf_ptr = strrcpy (buf_ptr, src_name);
	*buf_ptr++ = ' ';
    }

    if (S_flag)			/* command line says to inhibit stack
				   checking */
    {
	buf_ptr = strrcpy (buf_ptr, "-s ");
    }

    if (P_flag)			/* command line says to invoke profiler
				   option  */
    {
	buf_ptr = strrcpy (buf_ptr, "-p ");
    }

    return (buf_ptr);		/* return pointer to end of string  */
}

/*
  **
*/

char   *build_opt_line (buf_ptr, src_name)
char   *buf_ptr,
       *src_name;
{
    int     lp;
    buf_ptr = strrcpy (buf_ptr, "C.OPT ");

    if (*src_name)
    {
	buf_ptr = strrcpy (buf_ptr, src_name);
	*buf_ptr++ = ' ';
    }

    return (buf_ptr);		/* return pointer to end of line */
}
/*
  **
*/

char   *build_asm_line (buf_ptr)
char   *buf_ptr;
{
    int     lp;
    buf_ptr = strrcpy (buf_ptr, "C.ASM ");
    return (buf_ptr);		/* return pointer to end of line */
}

/*
  **
*/

char   *build_link_line (buf_ptr)
char   *buf_ptr;
{
    int     lp;
    buf_ptr = strrcpy (buf_ptr, "C.LINK /d1/lib/cstart.r ");

    if (SRC_cnt > 1)
    {
	for (lp = 0; lp < SRC_cnt; lp++)
	{
	    buf_ptr = strrcpy (buf_ptr, SRC_name[lp]);
	    *buf_ptr++ = ' ';
	}
	if (F_flag)
	{
	    buf_ptr = strrcpy (buf_ptr, "-o=");
	    buf_ptr = strrcpy (buf_ptr, FILE_name);
	}
    }
    else
    {
	buf_ptr = strrcpy (buf_ptr, "ctmp.3.r -o=");
	buf_ptr = strrcpy (buf_ptr, FILE_name);
	if (!F_flag)
	{
	    buf_ptr -= 2;	/* point to . in suffix */
	    *buf_ptr = '\0';
	}
    }

    *buf_ptr++ = ' ';

/* process command line libraries    */
    for (lp = 0; lp < LIB_cnt; lp++)
    {
	*buf_ptr++ = '-';
	buf_ptr = strrcpy (buf_ptr, LIB_name[lp]);
	*buf_ptr++ = ' ';
	*buf_ptr = '\0';
    }

    buf_ptr = strrcpy (buf_ptr, "-l=/d1/lib/clib.l ");

    if (E_flag)			/* command line edition needs to be used  
				        */
    {
	sprintf (buf_ptr, "-E=%d ", E_num);
	TO_END (buf_ptr);
    }

    if (M_flag)			/* command line edition needs to be used  
				        */
    {
	sprintf (buf_ptr, "-M=%d ", M_size);
	TO_END (buf_ptr);
    }

    return (buf_ptr);		/* return pointer to end of line */
}

/*
  **
*/

usage ()
{
    printf (
	    "Usage pcc [-BQPSACO] [filename.c] [filename.a] [filename.r]\n");
    exit (FALSE);

}


/*
  **
*/

char   *strrcpy (dst, src)
char   *dst,
       *src;
{
    while (*dst++ = *src++);	/* copy the string stoping after null */
    return (--dst);		/* return pointer to null terminator  */
}