1
0
mirror of https://github.com/PDP-10/PCC20.git synced 2026-01-13 23:26:39 +00:00
2018-10-25 11:25:56 +02:00

463 lines
9.8 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 "cc.h"
# include "c3.h"
/*
C COMPILER
Phase C: Code Generator
Section 1: Control, Storage Allocation, and Statements
Copyright (c) 1977 by Alan Snyder
*/
type ftype; /* type of current function */
enode acore[acoresz], /* core for enode tree and switch table*/
*acorp {acore};
int lc_node 1, /* node file location counter */
flc_node, /* lc_node at beginning of current function,
used to relocate tree to start of core */
*core, /* points to array which holds the tree
for each function */
*corep, /* pointer to next free location in core */
cbn 0, /* current block number */
nfunc 0, /* current number of functions */
lineno 1, /* line number of current statement */
exprlev 0, /* expression interpretation level */
ttxlev 0, /* expression code generation level */
cur_op, /* current node op, for error messages */
temploc 0, /* temporary location counter */
autoloc 0, /* automatic variables location counter */
framesize 0, /* current maximum stack frame size */
int_size, /* size of integer */
argops, /* 1 => .arg ops are defined */
objmode -1, /* object mode (pure, impure, data, pdata) */
f_error -1,
f_mac -1,
f_node -1,
fidn -1,
ntw[] /* indicates which words of a node
are pointers, according to type_node */
{000,002,006,016,003,001,007,004},
eof_node 0, /* indicates end-of-file of node file */
aflag 0, /* flag indicates tracing */
aquote 0, /* exprlev at which don't cvt array to ptr */
ciln 5000; /* current input label number */
char *fn_error,
*fn_mac,
*fn_node,
*fn_typtab,
*options,
type_node[] /* used to index ntw according to node-op */
{0,0,0,0,0,0,4,4,5,5,
5,5,5,5,5,5,5,4,4,4,
4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,5,4,4,5,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
3,1,0,1,4,3,5,5,1,7,
1,4,0,0},
nodelen[] /* length in words of node given op */
{
# include "cnlen.h"
},
opbop[] {
0, 0, e_idn, e_int, e_float,
e_string, e_call, e_qmark, 0, 0,
0, 0, 0, 0, 0,
e_bnot, e_not, e_band, e_bor, e_xor,
e_mod, e_divi, e_muli, e_subi, e_addi,
0, 0, 0, 0, 0,
0, 0, e_ls, e_rs, e_rs,
e_ls, e_addi, e_subi, e_muli, e_divi,
e_mod, e_band, e_xor, e_bor, e_and,
e_or, 0, e_colon, e_comma, 0
};
int allreg[2] {l_reg,-1}; /* dummy loc indicating all registers ok */
int allmem[2] {l_mem,-1}; /* dummy loc indicating all memory ok */
int anywhere[2] {l_any,0}; /* dummy loc indicating anywhere ok */
int swloc[2] {l_reg,0}; /* dummy loc for switch arg */
/**********************************************************************
MAIN ROUTINE
**********************************************************************/
# define MAXN 6
main (argc,argv) int argc; char *argv[];
{int c, i, core_size;
char *cp;
if (argc < MAXN)
{cprint ("Phase C called with too few arguments.\n");
cexit (100);
}
int_size = tsize[TTINT];
argops = !undfop (e_argi);
/* initialize swloc */
i = rtopp[e_sw];
if (i >= 0)
{i = rtopl[i];
if (i >= 0)
{swloc[0]=xoploc[i].xloc[0].flag;
swloc[1]=xoploc[i].xloc[0].word;
}
}
cp = argv[1];
while (c = *cp++) switch (c) {
case 'a': aflag=TRUE; break;
}
options=argv[1];
fn_error=argv[2];
fn_node=argv[3];
fn_typtab=argv[4];
fn_mac=argv[5];
core_size = coresz;
if (argc>MAXN) if ((i=atoi(argv[MAXN]))>1000) core_size=i;
core = getvec (core_size);
reg_init ();
rtyptab ();
typcinit ();
f_mac = xopen (fn_mac, MAPPEND, TEXT);
pure;
s_alloc ();
f_node = xopen (fn_node, MREAD, BINARY);
while (!eof_node)
{flc_node = lc_node;
corep = core;
cbn++;
while (read_node() != n_prog)
{if (eof_node) break;
if (corep >= core + (core_size - 6))
errx (4013);
}
if (!eof_node)
{fhead (corep[-5], corep[-4], corep[-1]);
framesize = autoloc = corep[-2];
stmt (corep[-3]);
framesize = align (framesize, nac-1);
mepilog ();
ftail ();
}
}
endcard ();
cclose (f_mac);
cleanup (0);
}
/**********************************************************************
CLEANUP - Code Generator Cleanup Routine
**********************************************************************/
cleanup (rcode)
{extern int maxerr;
cexit (rcode?rcode:maxerr>=2000);
}
/**********************************************************************
ERRX - Report error (lineno accessed via external variable)
**********************************************************************/
errx (errno, a1, a2, a3, a4)
{error (errno, lineno, a1, a2, a3, a4);}
/**********************************************************************
CODE GENERATOR: STORAGE ALLOCATION ROUTINES
fhead
ftail
gettemp
ttemp
s_alloc
sdef
*/
/**********************************************************************
FHEAD - function head
Define function name (FIDN) and type (FTYPE) and emit prolog.
**********************************************************************/
fhead (name, o, narg) int name, o, narg;
{++nfunc;
ftype = to2p (o);
fidn = name;
pure;
mprolog (nfunc, fidn, narg);
}
/**********************************************************************
FTAIL - Termination Processing for Function.
**********************************************************************/
ftail()
{;}
/**********************************************************************
GETTEMP - Allocate a temporary location on the stack
for an expression. Return its offset from the
beginning of the stack frame.
**********************************************************************/
int gettemp (ep) enode *ep;
{return (ttemp (ep->etype, 1));}
/**********************************************************************
TTEMP - allocate a temporary for N objects of type T
**********************************************************************/
int ttemp (t, n)
type t;
{int lc;
lc = temploc = align (temploc, t->align);
temploc =+ n*t->size;
if (temploc > framesize) framesize = temploc;
return (lc);
}
/**********************************************************************
S_ALLOC - Allocate storage for string constants
**********************************************************************/
s_alloc ()
{pdata;
string ();
}
/**********************************************************************
CODE GENERATOR: HIGHER LEVEL CODE GENERATION ROUTINES
stmt
astmt
cgswitch
expr
*/
/**********************************************************************
STMT - PROCESS A STATEMENT
This routine looks for statement lists and calls ASTMT when it
finds a "real" statement. This method saves stack space while
descending the syntax tree.
**********************************************************************/
stmt (p) int *p;
{if (p[0]==n_stmtl) {stmt(p[1]); stmt(p[2]);}
else astmt(p);
}
/**********************************************************************
ASTMT - Process statement
**********************************************************************/
astmt (p) int *p;
{int el, fl, op, l1, *p1;
enode *ep;
econst *ecp;
while (TRUE)
{if (!p) return;
cur_op = op = p[0];
switch (op) {
case n_switch: ln (p);
l1 = ciln++;
cgswitch (p[2], p[4], l1);
stmt (p[3]);
ilabel (l1);
return;
case n_if: ln (p);
if (!(ep = opt (texpr (p[2])))) return;
if (ep->op == e_int)
if ((ecp=ep)->eval) stmt (p[3]);
else stmt (p[4]);
else
{p1 = p[3]; /* then stmt */
if (p1[0]==n_branch)
{jumpn (ep, p1[1]);
if (p[4]) stmt (p[4]);
}
else
{jumpz (ep, fl=el=ciln++);
stmt (p[3]);
if (p[4])
{jump (fl=ciln++);
ilabel (el);
stmt (p[4]);
}
ilabel (fl);
}
}
return;
case n_goto: ln (p);
if (!(ep = texpr (p[2]))) return;
if (ep->etype==TINT) jumpe (ep);
else errx (2009);
return;
case n_branch: jump (p[1]);
return;
case n_label: ilabel (p[1]);
p = p[2];
continue;
case n_stmtl: stmt (p[1]);
stmt (p[2]);
return;
case n_return: ln (p);
if (p[2]) ep = convert (texpr(p[2]), ftype->val);
else ep = NULL;
creturn (ep);
return;
case n_exprs: ln (p);
expr (texpr (p[2]), anywhere);
return;
}
}
}
/**********************************************************************
CGSWITCH - Generate SWITCH operation for expression
NP, case list LP, and label L1 following body
of SWITCH statement.
**********************************************************************/
cgswitch (np, lp, l1) int *np, *lp, l1;
{enode *ep;
int l, n, lo, hi, range, *p, *swtab, *et, *q, i, *csp, b, o;
ep = texpr (np);
cur_op = n_switch;
ep = expr (conv (ep, 03), swloc);
if (!ep) return;
b = ep->edref.drbase;
o = ep->edref.droffset;
l = -1; /* default internal label */
n = 0;
csp = swtab = acore;
et = acore + acoresz;
p = lp;
while (p)
{switch (p[0]) {
case n_case: i = p[2];
for (q=swtab;q<csp;q=+2)
if (q[0]==i) {errx (2020); break;}
if (q==csp)
{if (csp>=et) errx (4010);
*csp++ = i;
*csp++ = p[3];
if (n++ == 0) {lo = i; hi = i;}
else if (i < lo) lo = i;
else if (i > hi) hi = i;
}
break;
case n_def: if (l>=0) errx (2021);
else l = p[2];
break;
default: errx (6003, p[0]);
}
p = p[1];
}
if (l<0) l = l1;
if (n==0) {jump (l); return;}
range = hi - lo + 1;
if (range <= 3*n && swtab+range < et)
{csp = swtab+range;
for (q=swtab;q<csp;++q) *q=l;
p = lp;
while (p)
{if (p[0]==n_case) swtab[p[2]-lo] = p[3];
p = p[1];
}
mtswitch (b, o, lo, hi, l);
for (q=swtab;q<csp;++q) mlabcon (*q);
metswitch (b, o, lo, hi, l);
}
else
{mlswitch (b, o, n, l);
for (q=csp-2;q>=swtab;q =- 2) mint (q[0]);
for (q=csp-2;q>=swtab;q =- 2) mlabcon (q[1]);
melswitch (b, o, n, l);
}
}
/**********************************************************************
EXPR - Optimize and Generate Code For Expression
**********************************************************************/
expr (ep, xp) enode *ep;
{return (ttexpr (opt (ep), xp));}