1
0
mirror of https://github.com/PDP-10/its.git synced 2026-03-25 09:52:18 +00:00
Files
PDP-10.its/c20/pcc20.c
2018-05-15 07:06:17 +02:00

594 lines
13 KiB
C

# include <stdio.h>
# include <ctype.h>
# define FALSE 0
# define TRUE 1
/*
TOPS-20 Portable C Compiler Command Routine
Compiler Options
-c compile only, do not assemble
-g do not delete assembly language temp file
-k keep intermediate files
-f write errors to file instead of tty
-o run code optimizer
-r ring bell when done
p=xxx predefine symbol xxx (to be 1)
l=xxx look in directory xxx for include files
*/
/* renamings to allow long names */
# define construct_output_file_names cnsofn
# define execute_phase execph
# define write_statistics wrstat
# define print_phase_time prphtm
# define process_options proopt
# define process_minus_option promin
# define process_equal_option proeq
# define phase_name phsnm
# define phase_pname phspnm
# define phase_prog phspr
# define phase_argc phsac
# define phase_argv phsav
# define phase_option phsop
# define phase_et phset
# define phase_pt phspt
# define argv_P avp
# define argv_C avc
/* program file names */
/* where to look for executable image files */
# define PREFIX "C:"
/* extension of executable image files */
# define SUFFIX ".exe"
# define OBJDIR ""
# define INTSUF "i"
# define OBJSUF "obj"
# define OPTSUF "mid"
# define RELSUF "rel"
# define ERRSUF "cerr"
# define ASMFILE "sys:midas.exe"
# define PHASEPRINT 1
# define file_name_size 100
/* options */
int kflag, cflag, gflag, oflag, rflag, fflag;
/* table for pre-defined symbols */
# define maxpds 10
char *pdstab[maxpds + 1];
char **pdsptr = {pdstab};
/* tables for #include default directories */
# define maxdirs 5
char *dfdirs[maxdirs + 1];
char **dfdptr = {dfdirs};
/* default search directories for # include <> */
# define n10dirs 2
char *df10dirs[] = {"-IC:", "-ICLIB:"};
/* phase information */
# define nphase 3
# define phase_P 0
# define phase_C 1
# define phase_O 2
# define extra maxpds + maxdirs
char *argv_P[2 + extra];
char *argv_C[4 + extra];
char *argv_O[2];
char *phase_name[] = {"P","C","O"};
char *phase_pname[] = {"cpp","pcc","opt"};
char phase_prog[nphase][file_name_size];
int phase_argc[] = {2, 3, 2};
char **phase_argv[] = {argv_P, argv_C, argv_O};
int phase_et[] = {0, 0, 0};
int phase_pt[] = {0, 0, 0};
static char *pdp10_pdefs[] = {"-DPDP10=1", 0}; /* predefined symbols */
# define opsys_name "-DTOPS20=1"
char *opsys = NULL;
extern char *sconcat ();
/**********************************************************************
THE MAIN PROGRAM
**********************************************************************/
main (argc, argv)
char *argv[];
{
extern FILE *stdout;
FILE *f;
int snum, cc, i, ttyflag;
cal start_time;
char *fargv[50], buffer[2000];
char src_name[file_name_size],
int_name[file_name_size],
obj_name[file_name_size],
opt_name[file_name_size],
rel_name[file_name_size],
err_name[file_name_size];
char *fptr;
char nambuf[2][file_name_size];
char cmdbuf[100];
--argc; /* skip over program name */
++argv;
argc = process_options (argc, argv);
argc = exparg (argc, argv, fargv, buffer);
argv = fargv;
pp_setup (); /* set up preprocessor arguments */
nambuf[0][0] = '<'; /* for re-directed input */
nambuf[1][0] = '>'; /* for re-directed output */
for (snum = 0; snum < argc; ++snum) {
char name[file_name_size];
strcpy (src_name, argv[snum]);
/* check that source file exists */
if ((f = fopen (src_name, "r")) == NULL) {
char ext[file_name_size];
fngtp (src_name, ext);
if (*ext == 0) {
fnsfd (src_name, src_name, 0, 0, 0, "c", 0, 0);
f = fopen (src_name, "r");
}
if (f == NULL) {
printf ("Can't Find '%s'.\n", src_name);
continue;
}
}
fclose (f);
fngnm (src_name, name); /* get name part of file spec */
for (fptr=name;*fptr!=0;fptr++)
*fptr = upperr(*fptr);
#ifdef SHORTNAME
name[6] = 0; /* print only six chars to match macro */
#endif
now (&start_time);
/* construct output file names from source file name */
construct_output_file_names (src_name, int_name, obj_name,
opt_name, rel_name, err_name);
for (i = 0; i < nphase; ++i) phase_pt[i] = -1;
#ifdef PHASEPRINT
printf ("CPP:\t%s\n",name);
#else
printf ("CC:\t%s\n",name);
#endif
fflush (stdout);
argv_P[0] = src_name; /* name of source file */
argv_P[1] = &nambuf[1][0]; /* >intname for redirected output */
strcpy (&nambuf[1][1],int_name); /* get intname */
cc = execute_phase (phase_P); /* reu preprocessor */
if (!cc) {
#ifdef PHASEPRINT
printf ("PCC:\t%s\n",name);
fflush (stdout);
#endif
argv_C[0] = &nambuf[0][0]; /* input from int file */
strcpy (&nambuf[0][1],int_name);
argv_C[1] = &nambuf[1][0]; /* output to obj file */
strcpy (&nambuf[1][1],obj_name);
argv_C[2] = name; /* tell pcc the module name */
if (fflag) {
cmdbuf[0] = '%';
strcpy (cmdbuf + 1,err_name);
argv_C[3] = cmdbuf;
phase_argc[phase_C] = 4;
}
cc = execute_phase (phase_C);
}
if (!kflag) unlink (int_name);
if (oflag) {
argv_O[0] = &nambuf[0][0];
strcpy (&nambuf[0][1],obj_name);
argv_O[1] = &nambuf[1][0];
strcpy (&nambuf[1][1],opt_name);
#ifdef PHASEPRINT
printf ("OPT:\t%s\n",name);
fflush(stdout);
#endif
cc = execute_phase (phase_O);
if (!kflag) unlink (obj_name);
}
else strcpy (opt_name, obj_name);
stats(src_name, &start_time);
if (cc) {
if (!gflag) unlink (opt_name);
}
else if (!cflag) {
#ifdef PHASEPRINT
printf ("MIDAS:\t%s\n",name);
fflush(stdout);
#endif
cc = assemble (opt_name, rel_name);
if (!cc && !gflag) unlink (opt_name);
}
if (rflag) {
putc ('\007', stdout);
fflush (stdout);
}
}
if (rflag) {
putc ('\007', stdout);
fflush (stdout);
}
}
/**********************************************************************
PROCESS_OPTIONS - Process options in command arguments
and remove options from argument list.
**********************************************************************/
int process_options (argc, argv)
char *argv[];
{
char *s, **ss, **dd;
int n, opt;
kflag = cflag = gflag = rflag = FALSE;
dd = ss = argv;
n = 0;
while (--argc >= 0) {
s = *ss++;
if (s[0] == '-') process_minus_option (s + 1);
else if ((opt = s[0]) && s[1] == '=')
process_equal_option (opt, s + 2);
else {
*dd++ = s;
++n;
}
}
return (n);
}
/**********************************************************************
PROCESS_MINUS_OPTION
**********************************************************************/
process_minus_option (s)
char *s;
{
int c;
while (c = *s) {
*s++ = c = lower (c);
switch (c) {
case 'k': kflag = TRUE; break;
case 'c': cflag = TRUE; break;
case 'g': gflag = TRUE; break;
case 'o': oflag = TRUE; break;
case 'r': rflag = TRUE; break;
case 'f': fflag = TRUE; break;
default: printf ("Unrecognized option: -%c\n", c);
break;
}
}
}
/**********************************************************************
PROCESS_EQUAL_OPTION
**********************************************************************/
process_equal_option (opt, s)
char *s;
{
char *r;
int c;
switch (opt = lower (opt)) {
case 'p': if (pdsptr < pdstab + maxpds) {
static char pdss[maxpds][20];
r = &pdss[pdsptr - pdstab][0];
*pdsptr++ = r;
sconcat (r, 3, "-D", s + 2, "=1");
}
else printf ("Sorry, too many pre-defined symbols.\n");
return;
case 'l': if (dfdptr < dfdirs + maxdirs) {
*dfdptr++ = s;
s[0] = '-';
s[1] = 'I';
}
else printf ("Sorry, too many search directories.\n");
return;
default: printf ("Unrecognized option: %c=%s\n", opt, s);
}
}
/**********************************************************************
PP_SETUP
Add pre-defined symbols and search directories to ARGV_P
**********************************************************************/
pp_setup ()
{
char **p, *q;
/* add defined search directories to preproc args */
p = df10dirs;
while (p < df10dirs + n10dirs) add_arg (phase_P, *p++);
p = dfdirs;
while (p < dfdptr) add_arg (phase_P, *p++);
/* add predefined symbols to preprocessor args */
p = pdp10_pdefs;
add_arg (phase_P, *p); /* add system predefined symbols */
if (q = opsys) {
if (strcmp (q, "-DTOPS20=1")) add_arg (phase_P, "-UTOPS20");
add_arg (phase_P, q);
}
p = pdstab; /* add user predefined symbols */
while (p < pdsptr) add_arg (phase_P, *p++);
}
/**********************************************************************
ADD_ARG - append an argument to the list for the given phase
**********************************************************************/
add_arg (phs, arg)
char *arg;
{
phase_argv[phs][phase_argc[phs]++] = arg;
}
/**********************************************************************
CONSTRUCT_OUTPUT_FILE_NAMES
Construct assembler, relocatable, and symbol table listing
file names from source file name.
**********************************************************************/
construct_output_file_names (src_name, int_name, obj_name, opt_name, rel_name, err_name)
char *src_name, *int_name, *obj_name, *opt_name, *rel_name, *err_name;
{
char *relsuf;
fnsfd (obj_name, src_name, "", OBJDIR, 0, OBJSUF, 0, 0);
fnsfd (opt_name, obj_name, 0, 0, 0, OPTSUF, 0, 0);
fnsfd (int_name, obj_name, 0, 0, 0, INTSUF, 0, 0);
fnsfd (rel_name, obj_name, 0, 0, 0, RELSUF, 0, 0);
fnsfd (err_name, obj_name, 0, 0, 0, ERRSUF, 0, 0);
}
/**********************************************************************
EXECUTE PHASE
**********************************************************************/
execute_phase (n)
int n;
{
extern int exctime, exccode;
int t;
set_program_name (n);
t = etime ();
if (execv (phase_prog[n], phase_argc[n], phase_argv[n])) {
printf ("Unable to execute phase %s\n", phase_name[n]);
return (-1);
}
phase_et[n] = etime () - t; /* elapsed time */
phase_pt[n] = exctime; /* runtime */
return (exccode);
}
/**********************************************************************
SET_PROGRAM_NAME
Construct the file name of program for the given phase.
**********************************************************************/
set_program_name (n)
int n;
{
char *r, *s;
r = PREFIX;
s = SUFFIX;
sconcat (phase_prog[n], 4, r, phase_pname[n],".",s);
}
/**********************************************************************
STATS - write statistics to stat file
**********************************************************************/
# define STATFILE1 "C:pcc20.stat"
stats (src_name, st)
char *src_name;
cal *st;
{
FILE *f;
int flag, i;
char temp[50];
flag = TRUE;
f = fopen (STATFILE1, "a");
# ifdef statfile2
if (f == NULL) f = fopen (STATFILE2, "a");
# endif
if (f == NULL) return;
putc ('\n', f);
strcpy (temp,username ());
fprintf (f, "%s - ", temp);
prcal (st, f);
fprintf (f, " - ");
fngdr (src_name, temp);
if (temp[0]) {
slower (temp);
fprintf (f, "%s/", temp);
}
fngnm (src_name, temp);
slower (temp);
fprintf (f, "%s", temp);
# define hack if (flag) {fprint (f, " ("); flag = FALSE;} else putc (' ', f)
if (cflag || gflag || kflag) {
hack;
if (cflag) putc ('c', f);
if (gflag) putc ('g', f);
if (kflag) putc ('k', f);
}
if (!flag) putc (')', f);
fprintf (f, "\n\n");
for (i = 0; i < nphase; ++i) print_phase_time (i, f);
fclose (f);
}
/**********************************************************************
PRINT_PHASE_TIME - As Part Of Statistics
**********************************************************************/
print_phase_time (n, f)
FILE *f;
{
if (phase_pt[n] != -1) {
fprint (f, phase_name[n]);
if (!phase_name[n][1]) putc (' ', f);
fprint (f, " P=");
pr60th (phase_pt[n], f);
fprint (f, " E=");
pr60th (phase_et[n], f);
putc ('\n', f);
}
}
/**********************************************************************
ASSEMBLE - Create the relocatable file from the assembler file
return TRUE iff an error occurred
**********************************************************************/
int assemble (obj_name, rel_name)
char *obj_name, *rel_name;
{
# ifdef TENEX
/* TENEX can't run MIDAS as an inferior -- sigh */
fprint ("OUTPUT on %s\n", obj_name);
return (TRUE);
}
# else
char *s, temp[100];
FILE *f;
/* construct Assembler command line */
strcpy (temp, rel_name);
strcat (temp, " _ ");
strcat (temp, obj_name);
strcat (temp, " (w)", s);
/* execute Assembler */
if (execs (ASMFILE, temp)) {
fprint (stderr,"Unable to Assemble.\n");
return (TRUE);
}
/* construct Assembler record file name */
fnsfd (temp, obj_name, 0, 0, 0, "err", 0, 0);
/* examine Assembler record file */
f = fopen (temp, "r");
if (f != NULL) { /* look for '-' <digit>+ '\t' */
register int c;
while ((c = getc (f)) != EOF) {
if (c == '-') {
c = getc (f);
if (!isdigit (c)) continue;
while (isdigit (c)) c = getc (f);
if (c != '\t') continue;
fprint (stderr, "Assembler Errors.\n");
fclose (f);
return (TRUE);
}
}
fclose (f);
unlink(temp);
}
return (FALSE);
}
# endif