Interdata_v6/usr/source/c/c02.c
#
/* C compiler
*
*
*/
#include "c0.h"
/*
* Process a single external definition
*/
extdef()
{
register o;
int sclass, scflag, *cb;
struct hshtab typer;
register struct hshtab *ds;
if(((o=symbol())==EOF) || o==SEMI)
return;
peeksym = o;
sclass = 0;
blklev = 0;
if (getkeywords(&sclass, &typer)==0) {
sclass = EXTERN;
if (peeksym!=NAME)
goto syntax;
}
scflag = 0;
if (sclass==DEFXTRN) {
scflag++;
sclass = EXTERN;
}
if (sclass!=EXTERN && sclass!=STATIC && sclass!=TYPEDEF)
error("Illegal storage class");
do {
defsym = 0;
paraml = 0;
parame = 0;
if (sclass==TYPEDEF) {
decl1(TYPEDEF, &typer, 0, NULL);
continue;
}
decl1(EXTERN, &typer, 0, NULL);
if ((ds=defsym)==0)
return;
funcsym = ds;
if ((ds->type&XTYPE)==FUNC) {
if ((peeksym=symbol())==LBRACE || peeksym==KEYW
|| (peeksym==NAME && csym->hclass==TYPEDEF)) {
funcblk.type = decref(ds->type);
setinit(ds);
#ifndef unix
strflg++;
#endif
outcode("BS", SYMDEF, sclass==EXTERN?ds->name:"");
#ifndef unix
strflg = 0;
#endif
cfunc();
return;
}
if (paraml)
error("Inappropriate parameters");
} else if ((o=symbol())==COMMA || o==SEMI) {
peeksym = o;
o = (length(ds)+ALIGN) & ~ALIGN;
if (sclass==STATIC) {
setinit(ds);
outcode("BSBBSBN", SYMDEF, "", BSS, NLABEL, ds->name, SSPACE, o);
} else if (scflag) {
/***
*** only allow one external definition
*** unless '-m' flag specified
***/
/***/ if (!mflag) {
/***/ setinit(ds);
/***/ outcode("BBSBSBN", BSS, SYMDEF,
/***/ ds->name, NLABEL, ds->name, SSPACE, o);
/***/ } else
/***/ outcode("BSN", CSPACE, ds->name, o);
}
} else {
if (o!=ASSIGN)
peeksym = o;
setinit(ds);
if (sclass==EXTERN)
outcode("BS", SYMDEF, ds->name);
outcode("BBS", DATA, NLABEL, ds->name);
cb = funcbase;
if (cinit(ds, 1, sclass) & ALIGN)
outcode("B", EVEN);
if (maxdecl > cb)
cb = maxdecl;
funcbase = cb;
}
} 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();
}
/*
* Process a function definition.
*/
cfunc()
{
register int *cb;
register sloc;
/***
sloc = isn;
isn =+ 2;
***/
outcode("BBS", PROG, RLABEL, funcsym->name);
cb = curbase;
/***/ regvar = 14;
autolen = STAUTO;
maxauto = STAUTO;
blklev = 1;
declist(ARG);
outcode("B", SAVE);
if (proflg)
outcode("BN", PROFIL, isn++);
funchead();
/***
branch(sloc);
label(sloc+1);
***/
retlab = isn++;
blklev = 0;
if ((peeksym = symbol()) != LBRACE)
error("Compound statement required");
statement();
outcode("BNB", LABEL, retlab, RETRN);
/***
label(sloc);
***/
outcode("BN", SETSTK, -maxauto);
/***
branch(sloc+1);
***/
if (cb < maxdecl)
cb = maxdecl;
curbase = funcbase = cb;
}
/*
* Process the initializers for an external definition.
*/
cinit(anp, flex, sclass)
struct hshtab *anp;
{
register struct phshtab *np;
register nel, ninit;
int width, isarray, o, brace, realtype, *cb;
struct tnode *s;
cb = funcbase;
np = gblock(sizeof(*np));
funcbase = curbase;
cpysymb(np, anp);
realtype = np->type;
isarray = 0;
if ((realtype&XTYPE) == ARRAY)
isarray++;
else
flex = 0;
width = length(np);
nel = 1;
/*
* If it's an array, find the number of elements.
* temporarily modify to look like kind of thing it's
* an array of.
*/
if (sclass==AUTO)
if (isarray || realtype==STRUCT)
error("No auto. aggregate initialization");
if (isarray) {
np->type = decref(realtype);
np->subsp++;
if (width==0 && flex==0)
error("0-length row: %.8s", anp->name);
o = length(np);
nel = (unsigned)width / o;
width = o;
}
brace = 0;
if ((peeksym=symbol())==LBRACE && (isarray || np->type!=STRUCT)) {
peeksym = -1;
brace++;
}
ninit = 0;
do {
if ((o=symbol())==RBRACE)
break;
peeksym = o;
if (o==STRING && realtype==ARRAY+CHAR) {
if (sclass==AUTO)
error("No strings in automatic");
peeksym = -1;
putstr(0, flex?10000:nel);
ninit =+ nchstr;
o = symbol();
break;
} else if (np->type==STRUCT)
strinit(np, sclass);
else if ((np->type&ARRAY)==ARRAY || peeksym==LBRACE)
cinit(np, 0, sclass);
else {
initflg++;
s = tree();
initflg = 0;
if (np->hflag&FFIELD)
error("No field initialization");
*cp++ = nblock(np);
*cp++ = s;
build(ASSIGN);
if (sclass==AUTO||sclass==REG)
rcexpr(*--cp);
else
rcexpr(block(INIT,np->type,NULL,NULL,(*--cp)->tr2));
}
ninit++;
} while ((o=symbol())==COMMA && (ninit<nel || brace || flex));
if (brace==0 || o!=RBRACE)
peeksym = o;
/*
* 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 && sclass!=AUTO)
outcode("BN", SSPACE, (nel-ninit)*width);
else if (ninit>nel) {
if (flex && nel==0) {
np->subsp[-1] = ninit;
} else
error("Too many initializers: %.8s", anp->name);
nel = ninit;
}
curbase = funcbase = cb;
return(nel*width);
}
/*
* Initialize a structure
*/
strinit(np, sclass)
struct tnode *np;
{
register struct hshtab **mlp;
static zerloc;
register int o, brace;
if ((mlp = np->strp->memlist)==NULL) {
mlp = &zerloc;
error("Undefined structure initialization");
}
brace = 0;
if ((o = symbol()) == LBRACE)
brace++;
else
peeksym = o;
do {
if ((o=symbol()) == RBRACE)
break;
peeksym = o;
if (*mlp==0) {
error("Too many structure initializers");
cinit(&funcblk, 0, sclass);
} else
cinit(*mlp++, 0, sclass);
if (*mlp == &structhole) {
outcode("B", EVEN);
mlp++;
}
} while ((o=symbol())==COMMA && (*mlp || brace));
if (sclass!=AUTO && sclass!=REG) {
if (*mlp)
outcode("BN", SSPACE, np->strp->ssize - (*mlp)->hoffset);
outcode("B", EVEN);
}
if (o!=RBRACE || brace==0)
peeksym = o;
}
/*
* Mark already initialized
*/
setinit(anp)
struct hshtab *anp;
{
register struct hshtab *np;
np = anp;
if (np->hflag&FINIT)
error("%s multiply defined", np->name);
np->hflag =| FINIT;
}
/*
* Process one statement in a function.
*/
statement()
{
register o, o1, o2;
int o3;
struct tnode *np;
int sauto, sreg;
stmt:
switch(o=symbol()) {
case EOF:
error("Unexpected EOF");
case SEMI:
return;
case LBRACE:
sauto = autolen;
sreg = regvar;
blockhead();
while (!eof) {
if ((o=symbol())==RBRACE) {
autolen = sauto;
if (sreg!=regvar)
outcode("BN", SETREG, sreg);
regvar = sreg;
blkend();
return;
}
peeksym = o;
statement();
}
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();
if ((o=symbol())==KEYW && cval==ELSE) {
o2 = isn++;
branch(o2);
label(o1);
statement();
label(o2);
return;
}
peeksym = o;
label(o1);
return;
case WHILE:
o1 = contlab;
o2 = brklab;
label(contlab = isn++);
cbranch(pexpr(), brklab=isn++, 0);
statement();
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();
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(RFORCE,0,NULL,NULL,np));
pswitch();
brklab = o1;
return;
case DEFAULT:
if (swp==0)
error("Default not in switch");
if (deflab)
error("More than 1 'default'");
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;
case ELSE:
error("Inappropriate 'else'");
statement();
return;
}
error("Unknown keyword");
goto syntax;
case NAME:
if (nextchar()==':') {
peekc = 0;
o1 = csym;
if (o1->hclass>0) {
if (o1->hblklev==0) {
pushdecl(o1);
o1->hoffset = 0;
} else {
defsym = o1;
redec();
goto stmt;
}
}
o1->hclass = STATIC;
o1->htype = ARRAY;
o1->hflag =| FLABL;
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;
cbranch(tree(), brklab, 0);
if ((o=symbol()) != SEMI)
return(o);
}
if ((peeksym=symbol()) == RPARN) { /* incr part */
peeksym = -1;
statement();
branch(contlab);
return(0);
}
l = contlab;
contlab = isn++;
st = tree();
sline = line;
if ((o=symbol()) != RPARN)
return(o);
ss = funcbase;
funcbase = curbase;
statement();
sline1 = line;
line = sline;
label(contlab);
rcexpr(st);
line = sline1;
if (ss < maxdecl)
ss = maxdecl;
curbase = funcbase = ss;
branch(l);
return(0);
}
/*
* A parenthesized expression,
* as after "if".
*/
struct tnode *
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 statement, 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();
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;
}
/*
* funchead is called at the start of each function
* to process the arguments, which have been linked in a list.
* This list is necessary because in
* f(a, b) float b; int a; ...
* the names are seen before the types.
*/
/*
* Structure resembling a block for a register variable.
*/
struct hshtab hreg { REG, 0, 0, NULL, NULL, 0 };
struct tnode areg { NAME, 0, NULL, NULL, &hreg};
funchead()
{
register pl;
register struct hshtab *cs;
struct tnode *bstack[2];
pl = STARG;
while(paraml) {
parame->hoffset = 0;
cs = paraml;
paraml = paraml->hoffset;
if (cs->htype==FLOAT)
cs->htype = DOUBLE;
/***/ if (cs->htype==CHAR || cs->htype==SHORT)
/***/ cs->htype = INT;
cs->hoffset = pl;
if ((cs->htype&XTYPE) == ARRAY) {
cs->htype =- (ARRAY-PTR); /* set ptr */
cs->subsp++; /* pop dims */
}
pl =+ rlength(cs);
if (cs->hclass==AREG && (hreg.hoffset=goodreg(cs))>=0) {
bstack[0] = &areg;
bstack[1] = nblock(cs);
cp = &bstack[2];
areg.type = cs->htype;
cs->hclass = AUTO;
build(ASSIGN);
rcexpr(bstack[0]);
cs->hoffset = hreg.hoffset;
cs->hclass = REG;
} else
cs->hclass = AUTO;
prste(cs);
}
for (cs=hshtab; cs<hshtab+HSHSIZ; cs++) {
if (cs->name[0] == '\0')
continue;
if (cs->hclass == ARG || cs->hclass==AREG)
error("Not an argument: %.8s", cs->name);
}
outcode("BN", SETREG, regvar);
}
blockhead()
{
register r;
r = regvar;
blklev++;
declist(0);
if (r != regvar)
outcode("BN", SETREG, regvar);
}
/*
* After the end of a block, delete local
* symbols; save those that are external.
* Also complain about undefined labels.
*/
blkend()
{
register struct hshtab *cs, *ncs;
struct hshtab *endcs;
register i;
blklev--;
for (cs=hshtab; cs->name[0] && cs<hshtab+HSHSIZ-1; ++cs)
;
endcs = cs;
do if (cs->name[0]) {
if (cs->hblklev <= blklev)
continue;
/*** The test below has been changed since it caused
*** EXTERN declarations in inner blocks of functions
*** not to be retained to the end of the file.
***/
if ((cs->hclass!=EXTERN /*** || blklev!=0 ***/)
&& ((cs->hflag&FLABL)==0 || blklev==0)) {
if (cs->hclass==0)
error("%.8s undefined", cs->name);
if ((ncs = cs->hpdown)==NULL) {
cs->name[0] = '\0';
hshused--;
cs->hflag =& ~(FFIELD|FLABL);
} else {
cpysymb(cs, ncs);
}
continue;
}
/*
* Retained name; must rehash.
*/
for (i=0; i<NCPS; i++)
symbuf[i] = cs->name[i];
lookup();
if ((ncs=csym) != cs) {
cs->name[0] = '\0';
hshused--;
i = ncs->hflag;
cpysymb(ncs, cs);
ncs->hflag =| i&FKEYW;
cs->hflag =& ~(FFIELD|FLABL);
}
if (ncs->hblklev>1 || (ncs->hblklev>0 && ncs->hclass==EXTERN))
ncs->hblklev--;
} while ((cs = (cs<&hshtab[HSHSIZ-1])? ++cs: hshtab) != endcs);
}
/*
* 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)
struct hshtab *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;
}