1
0
mirror of https://github.com/PDP-10/PCC20.git synced 2026-01-14 07:29:59 +00:00
2018-10-25 11:25:56 +02:00

759 lines
15 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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);
}