mirror of
https://github.com/PDP-10/PCC20.git
synced 2026-01-14 07:29:59 +00:00
759 lines
15 KiB
C
759 lines
15 KiB
C
# include "c.defs"
|
||
|
||
# define MERGE_LP 1
|
||
# define CALL_ERROR 1
|
||
|
||
/*
|
||
|
||
C Compiler Command Routine
|
||
Host machine: PDP-10 TOPS-20
|
||
|
||
|
||
Compiler Options
|
||
|
||
-c compile only
|
||
-g do not delete MIDAS file
|
||
-k do not delete intermediate files
|
||
-s produce symbol table listing
|
||
-x syntax check or symbol table listing only
|
||
-b for compiling big functions
|
||
|
||
m=xxx compile code for machine xxx
|
||
|
||
t=abc run TEST versions of phases a, b, c
|
||
o=abc run OLD versions of phases a, b, c
|
||
n=abc run NORMAL versions of phases a, b, c
|
||
d=xxx set compiler debugging argument to xxx
|
||
|
||
Meaningful debugging arguments:
|
||
|
||
a debug code generator
|
||
d debug parser
|
||
e debug parser error recovery
|
||
m debug macro expander
|
||
|
||
|
||
*/
|
||
|
||
/* renamings to allow long names */
|
||
|
||
# define construct_output_file_names cnsofn
|
||
# define execute_phase execph
|
||
# define set_program_name setpn
|
||
# define set_target settrg
|
||
# define write_statistics wrstat
|
||
# define print_phase_time prphtm
|
||
# define perform_assembly perasm
|
||
# define process_options proopt
|
||
# define process_minus_option promin
|
||
# define process_equal_option proeq
|
||
|
||
# define phase_name phsnm
|
||
# 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_L avl
|
||
# define argv_LP avlp
|
||
# define argv_P avp
|
||
# define argv_C avc
|
||
# define argv_M avm
|
||
# define argv_E ave
|
||
# define argv_S avs
|
||
|
||
# define target_name tarnam
|
||
# define target_suffix tarsfx
|
||
# define target_LP_data tarlpd
|
||
# define target_obj tarobj
|
||
|
||
/* intermediate file names */
|
||
|
||
# define fncs "0.cs;t"
|
||
# define fner "0.er;t"
|
||
# define fnhm "0.hm;t"
|
||
# define fnma "0.ma;t"
|
||
# define fnno "0.no;t"
|
||
# define fnst "0.st;t"
|
||
# define fnsy "0.sy;t"
|
||
# define fnto "0.to;t"
|
||
# define fnty "0.ty;t"
|
||
|
||
/* program file names */
|
||
|
||
# define normal_prefix "c20"
|
||
# define old_prefix "c20"
|
||
# define test_prefix "<c.cmp>c20"
|
||
|
||
# define normal_suffix ".exe"
|
||
# define old_suffix ".oexe"
|
||
# define test_suffix ".exe"
|
||
|
||
# define pdp10_suffix ""
|
||
# define pdp11_suffix "11"
|
||
# define his6000_suffix "60"
|
||
# define ibm360_suffix "360"
|
||
# define cmac_suffix "-cm"
|
||
# define unix_suffix "-ux"
|
||
# define new10_suffix "-10"
|
||
|
||
# define file_name_size 100
|
||
|
||
/* options */
|
||
|
||
char debug[40];
|
||
char idebug[40];
|
||
int kflag, cflag, gflag, xflag, bflag, sflag;
|
||
|
||
/* phase information */
|
||
|
||
# define nphase 7
|
||
|
||
# define phase_L 0
|
||
# define phase_LP 1
|
||
# define phase_P 2
|
||
# define phase_C 3
|
||
# define phase_M 4
|
||
# define phase_E 5
|
||
# define phase_S 6
|
||
|
||
# define ARGC_LP 10 /* arg counts without optional args */
|
||
# define ARGC_P 8
|
||
# define ARGC_C 6
|
||
|
||
char *argv_L[] {debug, 0, fnto, fncs, fner, fnst};
|
||
char *argv_LP[] {debug, 0, fnno, fnty, fner, fnma, fncs, fnst, fnhm, fnsy, 0};
|
||
char *argv_P[] {debug, fnto, fnno, fnty, fner, fnma, fnhm, fnsy, 0};
|
||
char *argv_C[] {debug, fner, fnno, fnty, fnma, "3000"};
|
||
char *argv_M[] {debug, 0, fncs, fner, fnma, fnst, fnhm};
|
||
char *argv_E[] {debug, fner, fncs};
|
||
char *argv_S[] {fncs, fnty, fnsy, 0};
|
||
|
||
char *phase_name[] {"L", "LP", "P", "C", "M", "E", "S"};
|
||
char phase_prog[nphase][file_name_size];
|
||
char *phase_argc[] {6, ARGC_LP, ARGC_P, ARGC_C, 7, 3, 4};
|
||
char **phase_argv[] {argv_L, argv_LP, argv_P, argv_C, argv_M,
|
||
argv_E, argv_S};
|
||
int phase_option[] {'n', 'n', 'n', 'n', 'n', 'n', 'n'};
|
||
int phase_et[] {0, 0, 0, 0, 0, 0, 0};
|
||
int phase_pt[] {0, 0, 0, 0, 0, 0, 0};
|
||
|
||
/* target machine information */
|
||
|
||
# define n_target 7
|
||
|
||
# define pdp10 0
|
||
# define pdp11 1
|
||
# define his6000 2
|
||
# define ibm360 3
|
||
# define cmac 4
|
||
# define unix 5
|
||
# define new10 6
|
||
|
||
int target pdp10;
|
||
|
||
char *target_name[] {
|
||
"pdp10",
|
||
"pdp11",
|
||
"his6000",
|
||
"ibm360",
|
||
"cmac",
|
||
"unix",
|
||
"new10"
|
||
};
|
||
|
||
char *target_suffix[] {
|
||
pdp10_suffix,
|
||
pdp11_suffix,
|
||
his6000_suffix,
|
||
ibm360_suffix,
|
||
cmac_suffix,
|
||
unix_suffix,
|
||
new10_suffix
|
||
};
|
||
|
||
char *target_LP_data[] {
|
||
"",
|
||
"",
|
||
"",
|
||
"",
|
||
"",
|
||
"",
|
||
""
|
||
};
|
||
|
||
char *target_obj[] {
|
||
"mid",
|
||
"PALX",
|
||
"GMAP",
|
||
"BAL",
|
||
"CMAC",
|
||
"UNIX",
|
||
"NMIDAS"
|
||
};
|
||
|
||
/**********************************************************************
|
||
|
||
DESCRIPTION OF EXTERNALLY DEFINED ROUTINES
|
||
|
||
part of C compiler:
|
||
|
||
perror - error message processor
|
||
|
||
standard C library:
|
||
|
||
copen - open file for input/output
|
||
cprint - formatted output
|
||
cputc - output character
|
||
cclose - close file
|
||
istty - is file a terminal?
|
||
|
||
file name routines:
|
||
|
||
file name = <device,directory,name,type,version,other>
|
||
|
||
fnsfd - set parts of file name
|
||
fngdr - get directory part of file name
|
||
fngnm - get "name" part of file name
|
||
|
||
reasonably machine-independent:
|
||
|
||
stcpy - copy string
|
||
stcmp - compare strings
|
||
lower - convert char to lower case
|
||
execv - execute program passing vector of args
|
||
execs - execute program passing string command line
|
||
delete - delete file
|
||
now - get current date and time
|
||
prcal - print date and time
|
||
pr60th - print time given in 1/60 second units
|
||
etime - return an elapsed time in 1/60 sec units
|
||
|
||
*/
|
||
|
||
char *sconcat();
|
||
|
||
/**********************************************************************
|
||
|
||
THE MAIN PROGRAM
|
||
|
||
**********************************************************************/
|
||
|
||
main (argc, argv) int argc; char *argv[];
|
||
|
||
{extern int cout;
|
||
int snum, cc, f, i, ttyflag;
|
||
cal start_time;
|
||
char *s, *source, *fargv[50], buffer[2000];
|
||
char obj_name[file_name_size],
|
||
rel_name[file_name_size],
|
||
sym_name[file_name_size];
|
||
|
||
--argc;
|
||
++argv;
|
||
argc = process_options (argc, argv);
|
||
argc = exparg (argc, argv, fargv, buffer);
|
||
argv = fargv;
|
||
|
||
# ifdef MERGE_LP
|
||
|
||
s = target_LP_data[target];
|
||
if (*s)
|
||
{phase_argc[phase_LP] = ARGC_LP+1;
|
||
argv_LP[ARGC_LP] = s;
|
||
}
|
||
else phase_argc[phase_LP] = ARGC_LP;
|
||
|
||
# endif
|
||
|
||
# ifndef MERGE_LP
|
||
|
||
s = target_LP_data[target];
|
||
if (*s)
|
||
{phase_argc[phase_P] = ARGC_P+1;
|
||
argv_P[ARGC_P] = s;
|
||
}
|
||
else phase_argc[phase_P] = ARGC_P;
|
||
|
||
# endif
|
||
ttyflag = istty (cout);
|
||
|
||
for (snum = 0; snum < argc; ++snum)
|
||
{source = argv[snum];
|
||
|
||
/* check that source file exists */
|
||
|
||
if ((f = copen (source, 'r')) == OPENLOSS)
|
||
{cprint ("Can't Find '%s'.\n", source);
|
||
continue;
|
||
}
|
||
cclose (f);
|
||
|
||
if (!ttyflag || argc>1) cprint ("%s:\n", source);
|
||
now (&start_time);
|
||
|
||
/* fix debug arg */
|
||
|
||
if (sflag) sconcat (debug, 2, idebug, "s");
|
||
else if (xflag) sconcat (debug, 2, idebug, "x");
|
||
else stcpy (idebug, debug);
|
||
|
||
/* construct output file names from source file name */
|
||
|
||
construct_output_file_names (source, obj_name,
|
||
rel_name, sym_name);
|
||
|
||
cclose (copen (fner, 'w', "b"));
|
||
|
||
for (i=0;i<nphase;++i) phase_pt[i] = -1;
|
||
argv_M[1] = obj_name;
|
||
argv_S[3] = sym_name;
|
||
|
||
# ifdef MERGE_LP
|
||
|
||
argv_LP[1] = source;
|
||
cc = execute_phase (phase_LP);
|
||
|
||
# endif
|
||
|
||
# ifndef MERGE_LP
|
||
|
||
argv_L[1] = source;
|
||
cc = execute_phase (phase_L);
|
||
if (!cc) cc = execute_phase (phase_P);
|
||
|
||
# endif
|
||
|
||
if (!cc && !xflag) cc = execute_phase (phase_C);
|
||
if (!cc && !xflag) cc = execute_phase (phase_M);
|
||
|
||
# ifdef CALL_ERROR
|
||
|
||
perror (fner, fncs);
|
||
|
||
# endif
|
||
|
||
# ifndef CALL_ERROR
|
||
|
||
execute_phase (phase_E);
|
||
|
||
# endif
|
||
|
||
if (!kflag)
|
||
{delete (fnto);
|
||
delete (fner);
|
||
delete (fnno);
|
||
delete (fnma);
|
||
delete (fnhm);
|
||
delete (fnst);
|
||
}
|
||
|
||
if (sflag) execute_phase (phase_S);
|
||
|
||
if (!kflag)
|
||
{delete (fncs);
|
||
delete (fnsy);
|
||
delete (fnty);
|
||
}
|
||
|
||
write_statistics (source, &start_time);
|
||
|
||
if (!cc && !xflag && !cflag &&
|
||
(target==pdp10 || target==new10))
|
||
{cc = perform_assembly (obj_name, rel_name);
|
||
if (!gflag && !cc) delete (obj_name);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
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 = xflag = bflag = sflag = 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 's': sflag = TRUE; break;
|
||
case 'x': xflag = TRUE; break;
|
||
case 'b': bflag = TRUE;
|
||
argv_C[5] = "10000";
|
||
break;
|
||
default: cprint ("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 'd': r = idebug;
|
||
while (c = *s++) *r++ = lower (c);
|
||
*r = 0;
|
||
return;
|
||
case 'n':
|
||
case 'o':
|
||
case 't': while (c = *s++) set_phase_option (c, opt);
|
||
return;
|
||
|
||
case 'm': set_target (s);
|
||
return;
|
||
|
||
default: cprint ("Unrecognized option: %c=%s\n", opt, s);
|
||
}
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
CONSTRUCT_OUTPUT_FILE_NAMES
|
||
|
||
Construct assembler, relocatable, and symbol table listing
|
||
file names from source file name.
|
||
|
||
**********************************************************************/
|
||
|
||
construct_output_file_names (source, obj_name, rel_name, sym_name)
|
||
char *source, *obj_name, *rel_name;
|
||
|
||
{fnsfd (obj_name, source, "", 0, 0, target_obj[target], 0, 0);
|
||
fnsfd (rel_name, obj_name, 0, 0, 0, "stk", 0, 0);
|
||
fnsfd (sym_name, obj_name, 0, 0, 0, "symtab", 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]))
|
||
{cprint ("Unable to execute phase %s\n", phase_name[n]);
|
||
return (-1);
|
||
}
|
||
phase_et[n] = etime () - t;
|
||
phase_pt[n] = exctime;
|
||
return (exccode);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
SET_PHASE_OPTION
|
||
|
||
Set phase option for phase PC to be OC.
|
||
|
||
**********************************************************************/
|
||
|
||
set_phase_option (pc, oc)
|
||
|
||
{int n;
|
||
|
||
pc = lower (pc);
|
||
switch (pc) {
|
||
|
||
# ifdef MERGE_LP
|
||
|
||
case 'l':
|
||
case 'p': n = phase_LP; break;
|
||
|
||
# endif
|
||
|
||
# ifndef MERGE_LP
|
||
|
||
case 'l': n = phase_L; break;
|
||
case 'p': n = phase_P; break;
|
||
|
||
# endif
|
||
|
||
case 'c': n = phase_C; break;
|
||
case 'm': n = phase_M; break;
|
||
case 'e': n = phase_E; break;
|
||
case 's': n = phase_S; break;
|
||
default: cprint ("Unrecognized Phase Designation: %c\n", pc);
|
||
return;
|
||
}
|
||
phase_option[n] = lower (oc);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
SET_PROGRAM_NAME
|
||
|
||
Construct the file name of program for the given phase.
|
||
|
||
**********************************************************************/
|
||
|
||
set_program_name (n) int n;
|
||
|
||
{char *r, *s, *t;
|
||
|
||
switch (phase_option[n]) {
|
||
case 'o': r = old_prefix; s = old_suffix;
|
||
break;
|
||
case 't': r = test_prefix; s = test_suffix;
|
||
break;
|
||
default: cprint ("Unrecognized Phase Option: %c\n",
|
||
phase_option[n]);
|
||
case 'n': r = normal_prefix; s = normal_suffix;
|
||
break;
|
||
}
|
||
t = target_suffix[target];
|
||
if (n == phase_E || n == phase_S) t = "";
|
||
sconcat (phase_prog[n], 4, r, phase_name[n], t, s);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
SET_TARGET - Set Target Machine
|
||
|
||
**********************************************************************/
|
||
|
||
set_target (s)
|
||
char *s;
|
||
|
||
{int c, i;
|
||
char *p;
|
||
|
||
p = s;
|
||
while (c = *p) *p++ = lower (c);
|
||
for (i=0; i<n_target; ++i)
|
||
{if (stcmp (s, target_name[i]))
|
||
{target = i;
|
||
return;
|
||
}
|
||
}
|
||
cprint ("Unrecognized target machine: %s\n", s);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
WRITE_STATISTICS
|
||
|
||
**********************************************************************/
|
||
|
||
write_statistics (source, st)
|
||
char *source;
|
||
cal *st;
|
||
|
||
{int f, flag, i;
|
||
char temp[50];
|
||
|
||
flag = TRUE;
|
||
f = copen ("<c>c.stat", 'a');
|
||
if (f == OPENLOSS) f = copen ("<clu>c.stat", 'a');
|
||
if (f == OPENLOSS) return;
|
||
cputc ('\n', f);
|
||
cprint (f, "%s - ", username ());
|
||
prcal (st, f);
|
||
cprint (f, " - ");
|
||
fngdr (source, temp);
|
||
if (temp[0])
|
||
{slower (temp);
|
||
cprint (f, "%s/", temp);
|
||
}
|
||
fngnm (source, temp);
|
||
slower (temp);
|
||
cprint (f, "%s", temp);
|
||
|
||
# define hackery if (flag) {cprint (f, " ("); flag=FALSE;} else cputc (' ', f)
|
||
|
||
if (cflag || gflag || kflag || xflag || bflag || sflag)
|
||
{hackery;
|
||
if (cflag) cputc ('c', f);
|
||
if (gflag) cputc ('g', f);
|
||
if (kflag) cputc ('k', f);
|
||
if (xflag) cputc ('x', f);
|
||
if (bflag) cputc ('b', f);
|
||
if (sflag) cputc ('s', f);
|
||
}
|
||
|
||
if (*idebug)
|
||
{hackery;
|
||
cprint (f, "d=%s", idebug);
|
||
}
|
||
if (target)
|
||
{hackery;
|
||
cprint (f, "m=%s", target_name[target]);
|
||
}
|
||
if (!flag) cputc (')', f);
|
||
|
||
cprint (f, "\n\n");
|
||
for (i=0;i<nphase;++i) print_phase_time (i, f);
|
||
cclose (f);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
PRINT_PHASE_TIME - As Part Of Statistics
|
||
|
||
**********************************************************************/
|
||
|
||
print_phase_time (n, f)
|
||
|
||
{if (phase_pt[n] != -1)
|
||
{cprint (f, phase_name[n]);
|
||
if (!phase_name[n][1]) cputc (' ', f);
|
||
cprint (f, " P=");
|
||
pr60th (phase_pt[n], f);
|
||
cprint (f, " E=");
|
||
pr60th (phase_et[n], f);
|
||
cputc ('\n', f);
|
||
}
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
PERFORM_ASSEMBLY - Create the relocatable file
|
||
from the assembler file
|
||
|
||
return TRUE iff an error occurred
|
||
|
||
**********************************************************************/
|
||
|
||
int perform_assembly (obj_name, rel_name)
|
||
char *obj_name, *rel_name;
|
||
|
||
{char *s, temp[100];
|
||
int f;
|
||
|
||
/* construct Assembler command line */
|
||
|
||
s = stcpy (rel_name, temp);
|
||
s = stcpy (" _ ", s);
|
||
s = stcpy (obj_name, s);
|
||
s = stcpy (" (w)", s);
|
||
|
||
/* execute Assembler */
|
||
|
||
if (execs ("sys:midas.exe", temp))
|
||
{cprint ("Unable to Assemble.\n");
|
||
return (TRUE);
|
||
}
|
||
|
||
/* construct Assembler record file name */
|
||
|
||
s = stcpy (rel_name, temp);
|
||
s = stcpy ("ERR", s-(target==pdp10 ? 3 : 4));
|
||
|
||
/* examine Assembler record file */
|
||
|
||
f = copen (temp, 'r');
|
||
if (f != OPENLOSS) /* look for '-' <digit>+ '\t' */
|
||
{register int c;
|
||
while ((c = cgetc (f)) > 0)
|
||
{if (c == '-')
|
||
{c = cgetc (f);
|
||
if (!digit (c)) continue;
|
||
while (digit (c)) c = cgetc (f);
|
||
if (c != '\t') continue;
|
||
cprint ("Assembler Errors.\n");
|
||
cclose (f);
|
||
return (TRUE);
|
||
}
|
||
}
|
||
cclose (f);
|
||
delete (temp);
|
||
}
|
||
return (FALSE);
|
||
}
|
||
|
||
int digit (c)
|
||
{return (c>='0' && c<='9');}
|
||
|
||
/**********************************************************************
|
||
|
||
SCONCAT - String Concatenate
|
||
|
||
concatenate strings S1 ... Sn into buffer B
|
||
return B
|
||
|
||
**********************************************************************/
|
||
|
||
char *sconcat (b, n, s1, s2, s3, s4, s5, s6, s7, s8)
|
||
char *b, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8;
|
||
|
||
{char **s, *p, *q;
|
||
int c;
|
||
|
||
q = b;
|
||
s = &s1;
|
||
|
||
while (--n >= 0)
|
||
{p = *s++;
|
||
while (c = *p++) *q++ = c;
|
||
}
|
||
|
||
*q = 0;
|
||
return (b);
|
||
}
|
||
|
||
/**********************************************************************
|
||
|
||
SLOWER - Convert String To Lower Case
|
||
|
||
**********************************************************************/
|
||
|
||
slower (s) char *s;
|
||
|
||
{int c;
|
||
while (c = *s) *s++ = lower (c);
|
||
}
|
||
|