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