1
0
mirror of https://github.com/PDP-10/its.git synced 2026-01-24 03:18:05 +00:00
Lars Brinkhoff 120ae989fa Revert change to CC for LP phase.
Because the new CC now passes the wrong number of arguments to _LP BIN,
we keep the old around as OCC and use it until the new _LP BIN is built.
2018-10-30 08:36:56 +01:00

773 lines
16 KiB
Groff

# include "c.defs"
# define MERGE_LP 1
# define CALL_ERROR 1
/*
C Compiler Command Routine
Host machine: PDP-10 ITS
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"
# define fner "0.er"
# define fnhm "0.hm"
# define fnma "0.ma"
# define fnno "0.no"
# define fnst "0.st"
# define fnsy "0.sy"
# define fnto "0.to"
# define fnty "0.ty"
/* program file names */
# define normal_prefix "/dsk/c/_"
# define old_prefix "/dsk/c/_"
# define test_prefix "/dsk/c/_"
# define normal_suffix ".bin"
# define old_suffix ".obin"
# define test_suffix ".tbin"
# 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 30
/* 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[] {
"MIDAS",
"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?
reasonably machine-independent:
stcpy - copy string
stcmp - compare strings
lower - convert char to lower case
execv - execute program passing vector of args
delete - delete file
now - get current date and time
prcal - print date and time
pr60th - print time given in 1/60 second units
grossly ITS dependent:
fopen - open file
fillen - determine file length
close - close file
fparse - parse file name
prfile - convert file specification to string
runame - return user name
etime - return an elapsed time
c6tos - convert sixbit to ASCII string
csto6 - convert ASCII to sixbit string
execs - execute program passing string command line
*/
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. For the ITS version,
output file names are formed by changing the FNAME2 and
setting the DEVICE to DSK.
**********************************************************************/
construct_output_file_names (source, obj_name, rel_name, sym_name)
char *source, *obj_name, *rel_name;
{filespec f;
fparse (source, &f);
f.dev = csto6 ("DSK");
f.fn2 = csto6 (target_obj[target]);
prfile (&f, obj_name);
if (target==new10) f.fn2 = csto6 ("NSTK");
else f.fn2 = csto6 ("STK");
prfile (&f, rel_name);
f.fn2 = csto6 ("SYMTAB");
prfile (&f, sym_name);
}
/**********************************************************************
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[10];
filespec fs;
fparse (source, &fs);
if (fs.dir == 0) fs.dir = rsname ();
flag = TRUE;
f = copen ("/dsk/c/c.stat", 'a');
if (f == OPENLOSS) f = copen ("/dsk/common/c.stat", 'a');
if (f == OPENLOSS) return;
cputc ('\n', f);
c6tos (runame (), temp);
cprint (f, "%s - ", temp);
prcal (st, f);
c6tos (fs.dir, temp);
slower (temp);
cprint (f, " - %s", temp);
c6tos (fs.fn1, 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 ("/dsk/c/ts.midas", 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);
}