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 */
}