mirror of
https://github.com/PDP-10/PCC20.git
synced 2026-01-13 23:26:39 +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 "<c>c20"
|
|
# define old_prefix "<c>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);
|
|
}
|