Research V6 development
[unix-history] / usr / source / c / c02.c
#
/* C compiler
*
*
*/
#include "c0h.c"
/*
* Process a single external definition
*/
extdef()
{
register o, elsize;
int type, sclass;
register struct hshtab *ds;
if(((o=symbol())==EOF) || o==SEMI)
return;
peeksym = o;
type = INT;
sclass = EXTERN;
xdflg = FNDEL;
if ((elsize = getkeywords(&sclass, &type)) == -1 && peeksym!=NAME)
goto syntax;
if (type==STRUCT)
blkhed();
do {
defsym = 0;
decl1(EXTERN, type, 0, elsize);
if ((ds=defsym)==0)
return;
funcsym = ds;
ds->hflag =| FNDEL;
outcode("BS", SYMDEF, ds->name);
xdflg = 0;
if ((ds->type&XTYPE)==FUNC) {
if ((peeksym=symbol())==LBRACE || peeksym==KEYW) {
funcblk.type = decref(ds->type);
cfunc(ds->name);
return;
}
} else
cinit(ds);
} while ((o=symbol())==COMMA);
if (o==SEMI)
return;
syntax:
if (o==RBRACE) {
error("Too many }'s");
peeksym = 0;
return;
}
error("External definition syntax");
errflush(o);
statement(0);
}
/*
* Process a function definition.
*/
cfunc(cs)
char *cs;
{
register savdimp;
savdimp = dimp;
outcode("BBS", PROG, RLABEL, cs);
declist(ARG);
regvar = 5;
retlab = isn++;
if ((peeksym = symbol()) != LBRACE)
error("Compound statement required");
statement(1);
outcode("BNB", LABEL, retlab, RETRN);
dimp = savdimp;
}
/*
* Process the initializers for an external definition.
*/
cinit(ds)
struct hshtab *ds;
{
register basetype, nel, ninit;
int o, width, realwidth;
nel = 1;
basetype = ds->type;
/*
* If it's an array, find the number of elements.
* "basetype" is the type of thing it's an array of.
*/
while ((basetype&XTYPE)==ARRAY) {
if ((nel = dimtab[ds->ssp&0377])==0)
nel = 1;
basetype = decref(basetype);
}
realwidth = width = length(ds) / nel;
/*
* Pretend a structure is kind of an array of integers.
* This is a kludge.
*/
if (basetype==STRUCT) {
nel =* realwidth/2;
width = 2;
}
if ((peeksym=symbol())==COMMA || peeksym==SEMI) {
outcode("BSN",CSPACE,ds->name,(nel*width+ALIGN)&~ALIGN);
return;
}
ninit = 0;
outcode("BBS", DATA, NLABEL, ds->name);
if ((o=symbol())==LBRACE) {
do
ninit = cinit1(ds, basetype, width, ninit, nel);
while ((o=symbol())==COMMA);
if (o!=RBRACE)
peeksym = o;
} else {
peeksym = o;
ninit = cinit1(ds, basetype, width, 0, nel);
}
/*
* Above we pretended that a structure was a bunch of integers.
* Readjust in accordance with reality.
* First round up partial initializations.
*/
if (basetype==STRUCT) {
if (o = 2*ninit % realwidth)
outcode("BN", SSPACE, realwidth-o);
ninit = (2*ninit+realwidth-2) / realwidth;
nel =/ realwidth/2;
}
/*
* If there are too few initializers, allocate
* more storage.
* If there are too many initializers, extend
* the declared size for benefit of "sizeof"
*/
if (ninit<nel)
outcode("BN", SSPACE, (nel-ninit)*realwidth);
else if (ninit>nel) {
if ((ds->type&XTYPE)==ARRAY)
dimtab[ds->ssp&0377] = ninit;
nel = ninit;
}
/*
* If it's not an array, only one initializer is allowed.
*/
if (ninit>1 && (ds->type&XTYPE)!=ARRAY)
error("Too many initializers");
if (((nel&width)&ALIGN))
outcode("B", EVEN);
}
/*
* Process a single expression in a sequence of initializers
* for an external. Mainly, it's for checking
* type compatibility.
*/
cinit1(ds, type, awidth, aninit, nel)
struct hshtab *ds;
{
float sf;
register struct tnode *s;
register width, ninit;
width = awidth;
ninit = aninit;
if ((peeksym=symbol())==STRING && type==CHAR) {
peeksym = -1;
if (ninit)
bxdec();
putstr(0);
if (nel>nchstr) {
strflg++;
outcode("BN", SSPACE, nel-nchstr);
strflg = 0;
nchstr = nel;
}
return(nchstr);
}
if (peeksym==RBRACE)
return(ninit);
initflg++;
s = tree();
initflg = 0;
switch(width) {
case 1:
if (s->op != CON)
goto bad;
outcode("B1N0", BDATA, s->value);
break;
case 2:
if (s->op==CON) {
outcode("B1N0", WDATA, s->value);
break;
}
if (s->op==FCON || s->op==SFCON) {
if (type==STRUCT) {
ninit =+ 3;
goto prflt;
}
goto bad;
}
rcexpr(block(1,INIT,0,0,s));
break;
case 4:
sf = fcval;
outcode("B1N1N0", WDATA, sf);
goto flt;
case 8:
prflt:
outcode("B1N1N1N1N0", WDATA, fcval);
flt:
if (s->op==FCON || s->op==SFCON)
break;
default:
bad:
bxdec();
}
return(++ninit);
}
bxdec()
{
error("Inconsistent external initialization");
}
/*
* Process one statement in a function.
*/
statement(d)
{
register o, o1, o2;
int o3, o4;
struct tnode *np;
stmt:
switch(o=symbol()) {
case EOF:
error("Unexpected EOF");
case SEMI:
return;
case LBRACE:
if (d) {
if (proflg)
outcode("BN", PROFIL, isn++);
outcode("BN", SAVE, blkhed());
}
while (!eof) {
if ((o=symbol())==RBRACE)
return;
peeksym = o;
statement(0);
}
error("Missing '}'");
return;
case KEYW:
switch(cval) {
case GOTO:
if (o1 = simplegoto())
branch(o1);
else
dogoto();
goto semi;
case RETURN:
doret();
goto semi;
case IF:
np = pexpr();
o2 = 0;
if ((o1=symbol())==KEYW) switch (cval) {
case GOTO:
if (o2=simplegoto())
goto simpif;
cbranch(np, o2=isn++, 0);
dogoto();
label(o2);
goto hardif;
case RETURN:
if (nextchar()==';') {
o2 = retlab;
goto simpif;
}
cbranch(np, o1=isn++, 0);
doret();
label(o1);
o2++;
goto hardif;
case BREAK:
o2 = brklab;
goto simpif;
case CONTIN:
o2 = contlab;
simpif:
chconbrk(o2);
cbranch(np, o2, 1);
hardif:
if ((o=symbol())!=SEMI)
goto syntax;
if ((o1=symbol())==KEYW && cval==ELSE)
goto stmt;
peeksym = o1;
return;
}
peeksym = o1;
cbranch(np, o1=isn++, 0);
statement(0);
if ((o=symbol())==KEYW && cval==ELSE) {
o2 = isn++;
branch(o2);
label(o1);
statement(0);
label(o2);
return;
}
peeksym = o;
label(o1);
return;
case WHILE:
o1 = contlab;
o2 = brklab;
label(contlab = isn++);
cbranch(pexpr(), brklab=isn++, 0);
statement(0);
branch(contlab);
label(brklab);
contlab = o1;
brklab = o2;
return;
case BREAK:
chconbrk(brklab);
branch(brklab);
goto semi;
case CONTIN:
chconbrk(contlab);
branch(contlab);
goto semi;
case DO:
o1 = contlab;
o2 = brklab;
contlab = isn++;
brklab = isn++;
label(o3 = isn++);
statement(0);
label(contlab);
contlab = o1;
if ((o=symbol())==KEYW && cval==WHILE) {
cbranch(tree(), o3, 1);
label(brklab);
brklab = o2;
goto semi;
}
goto syntax;
case CASE:
o1 = conexp();
if ((o=symbol())!=COLON)
goto syntax;
if (swp==0) {
error("Case not in switch");
goto stmt;
}
if(swp>=swtab+swsiz) {
error("Switch table overflow");
} else {
swp->swlab = isn;
(swp++)->swval = o1;
label(isn++);
}
goto stmt;
case SWITCH:
o1 = brklab;
brklab = isn++;
np = pexpr();
chkw(np, -1);
rcexpr(block(1,RFORCE,0,0,np));
pswitch();
brklab = o1;
return;
case DEFAULT:
if (swp==0)
error("Default not in switch");
if ((o=symbol())!=COLON)
goto syntax;
label(deflab = isn++);
goto stmt;
case FOR:
o1 = contlab;
o2 = brklab;
contlab = isn++;
brklab = isn++;
if (o=forstmt())
goto syntax;
label(brklab);
contlab = o1;
brklab = o2;
return;
}
error("Unknown keyword");
goto syntax;
case NAME:
if (nextchar()==':') {
peekc = 0;
o1 = csym;
if (o1->hclass>0) {
error("Redefinition");
goto stmt;
}
o1->hclass = STATIC;
o1->htype = ARRAY;
if (o1->hoffset==0)
o1->hoffset = isn++;
label(o1->hoffset);
goto stmt;
}
}
peeksym = o;
rcexpr(tree());
semi:
if ((o=symbol())==SEMI)
return;
syntax:
error("Statement syntax");
errflush(o);
}
/*
* Process a for statement.
*/
forstmt()
{
register int l, o, sline;
int sline1, *ss;
struct tnode *st;
if ((o=symbol()) != LPARN)
return(o);
if ((o=symbol()) != SEMI) { /* init part */
peeksym = o;
rcexpr(tree());
if ((o=symbol()) != SEMI)
return(o);
}
label(contlab);
if ((o=symbol()) != SEMI) { /* test part */
peeksym = o;
rcexpr(block(1,CBRANCH,tree(),brklab,0));
if ((o=symbol()) != SEMI)
return(o);
}
if ((peeksym=symbol()) == RPARN) { /* incr part */
peeksym = -1;
statement(0);
branch(contlab);
return(0);
}
l = contlab;
contlab = isn++;
st = tree();
sline = line;
if ((o=symbol()) != RPARN)
return(o);
ss = treespace;
treespace = space;
statement(0);
sline1 = line;
line = sline;
label(contlab);
rcexpr(st);
line = sline1;
treespace = ss;
branch(l);
return(0);
}
/*
* A parenthesized expression,
* as after "if".
*/
pexpr()
{
register o, t;
if ((o=symbol())!=LPARN)
goto syntax;
t = tree();
if ((o=symbol())!=RPARN)
goto syntax;
return(t);
syntax:
error("Statement syntax");
errflush(o);
return(0);
}
/*
* The switch stateent, which involves collecting the
* constants and labels for the cases.
*/
pswitch()
{
register struct swtab *cswp, *sswp;
int dl, swlab;
cswp = sswp = swp;
if (swp==0)
cswp = swp = swtab;
branch(swlab=isn++);
dl = deflab;
deflab = 0;
statement(0);
branch(brklab);
label(swlab);
if (deflab==0)
deflab = brklab;
outcode("BNN", SWIT, deflab, line);
for (; cswp < swp; cswp++)
outcode("NN", cswp->swlab, cswp->swval);
outcode("0");
label(brklab);
deflab = dl;
swp = sswp;
}
/*
* blkhed is called at the start of each function.
* It reads the declarations at the start;
* then assigns storage locations for the
* parameters (which have been linked into a list,
* in order of appearance).
* This list is necessary because in
* f(a, b) float b; int a; ...
* the names are seen before the types.
* Also, the routine adjusts structures involved
* in some kind of forward-referencing.
*/
blkhed()
{
register pl;
register struct hshtab *cs;
autolen = 6;
declist(0);
pl = 4;
while(paraml) {
parame->hoffset = 0;
cs = paraml;
paraml = paraml->hoffset;
if (cs->htype==FLOAT)
cs->htype = DOUBLE;
cs->hoffset = pl;
cs->hclass = AUTO;
if ((cs->htype&XTYPE) == ARRAY) {
cs->htype =- (ARRAY-PTR); /* set ptr */
cs->ssp++; /* pop dims */
}
pl =+ rlength(cs);
}
for (cs=hshtab; cs<hshtab+hshsiz; cs++) {
if (cs->name[0] == '\0')
continue;
/* check tagged structure */
if (cs->hclass>KEYWC && (cs->htype&TYPE)==RSTRUCT) {
cs->lenp = dimtab[cs->lenp&0377]->lenp;
cs->htype = cs->htype&~TYPE | STRUCT;
}
if (cs->hclass == STRTAG && dimtab[cs->lenp&0377]==0)
error("Undefined structure: %.8s", cs->name);
if (cs->hclass == ARG)
error("Not an argument: %.8s", cs->name);
if (stflg)
prste(cs);
}
space = treespace;
outcode("BN", SETREG, regvar);
return(autolen);
}
/*
* After a function definition, delete local
* symbols.
* Also complain about undefineds.
*/
blkend() {
register struct hshtab *cs;
for (cs=hshtab; cs<hshtab+hshsiz; cs++) {
if (cs->name[0]) {
if (cs->hclass==0 && (cs->hflag&FNUND)==0) {
error("%.8s undefined", cs->name);
cs->hflag =| FNUND;
}
if((cs->hflag&FNDEL)==0) {
cs->name[0] = '\0';
hshused--;
cs->hflag =& ~(FNUND|FFIELD);
}
}
}
}
/*
* write out special definitions of local symbols for
* benefit of the debugger. None of these are used
* by the assembler except to save them.
*/
prste(acs)
{
register struct hshtab *cs;
register nkind;
cs = acs;
switch (cs->hclass) {
case REG:
nkind = RNAME;
break;
case AUTO:
nkind = ANAME;
break;
case STATIC:
nkind = SNAME;
break;
default:
return;
}
outcode("BSN", nkind, cs->name, cs->hoffset);
}
/*
* In case of error, skip to the next
* statement delimiter.
*/
errflush(ao)
{
register o;
o = ao;
while(o>RBRACE) /* ; { } */
o = symbol();
peeksym = o;
}