USG_PG3/usr/source/cc/c03.c
#
/*
* C compiler, phase 1
*
*
* Handles processing of declarations,
* except for top-level processing of
* externals.
*/
#include "c0.h"
/*
* Process a sequence of declaration statements
*/
declist(sclass)
{
register sc, offset;
struct str *strp;
int type;
offset = 0;
sc = sclass;
while (getkeywords(&sclass, &type, &strp)) {
offset = declare(sclass, type, offset, strp);
sclass = sc;
}
return(offset+align(INT, offset, 0));
}
/*
* Read the keywords introducing a declaration statement
* Store back the storage class, type, and structure descriptor.
*/
getkeywords(scptr, tptr, strptr)
int *scptr, *tptr;
struct str **strptr;
{
register skw, tkw, longf;
int o, isadecl, ismos;
isadecl = 0;
longf = 0;
*strptr = NULL;
tkw = -1;
skw = *scptr;
ismos = skw==MOS;
for (;;) {
mosflg = ismos;
switch ((o=symbol())==KEYW? cval: -1) {
case AUTO:
case STATIC:
case EXTERN:
case REG:
if (skw && skw!=cval
&& (skw!=ARG || cval!=REG))
error("Conflict in storage class");
skw = cval;
break;
case LONG:
longf++;
break;
case STRUCT:
*strptr = strdec(ismos);
cval = STRUCT;
case INT:
case CHAR:
case FLOAT:
case DOUBLE:
if (tkw>=0)
error("Type clash");
tkw = cval;
break;
default:
peeksym = o;
if (isadecl==0)
return(0);
if (tkw<0)
tkw = INT;
if (skw==0)
skw = xdflg? EXTERN: AUTO;
if (longf) {
if (tkw==FLOAT)
tkw = DOUBLE;
else if (tkw==INT)
tkw = LONG;
else
error("Misplaced 'long'");
}
*scptr = skw;
*tptr = tkw;
return(1);
}
isadecl++;
}
}
/*
* Process a structure declaration; a subroutine
* of getkeywords.
*/
struct str *
strdec(mosf)
{
register elsize, o;
register struct hshtab *ssym;
int savebits;
struct hshtab **savememlist;
int savenmems;
struct str *strp;
struct hshtab *ds;
struct hshtab *mems[NMEMS];
mosflg = 1;
ssym = 0;
if ((o=symbol())==NAME) {
ssym = csym;
if (ssym->hclass==0) {
ssym->hclass = STRTAG;
ssym->strp = gblock(sizeof(*strp));
funcbase = curbase;
ssym->strp->ssize = 0;
ssym->strp->memlist = NULL;
}
if (ssym->hclass != STRTAG)
redec();
strp = ssym->strp;
mosflg = mosf;
o = symbol();
} else {
strp = gblock(sizeof(*strp));
funcbase = curbase;
strp->ssize = 0;
strp->memlist = NULL;
}
mosflg = 0;
if (o != LBRACE) {
if (ssym==0)
goto syntax;
if (ssym->hclass!=STRTAG)
error("Bad structure name");
peeksym = o;
} else {
ds = defsym;
mosflg = 0;
savebits = bitoffs;
savememlist = memlist;
savenmems = nmems;
memlist = mems;
nmems = 2;
bitoffs = 0;
elsize = declist(MOS);
bitoffs = savebits;
defsym = ds;
if (strp->ssize)
error("%.8s redeclared", ssym->name);
strp->ssize = elsize;
*memlist++ = NULL;
strp->memlist = gblock((memlist-mems)*sizeof(*memlist));
funcbase = curbase;
for (o=0; &mems[o] != memlist; o++)
strp->memlist[o] = mems[o];
memlist = savememlist;
nmems = savenmems;
if ((o = symbol()) != RBRACE)
goto syntax;
}
return(strp);
syntax:
decsyn(o);
return(0);
}
/*
* Process a comma-separated list of declarators
*/
declare(askw, tkw, offset, strp)
struct str *strp;
{
register int o;
register int skw;
skw = askw;
do {
offset =+ decl1(skw, tkw, offset, strp);
} while ((o=symbol()) == COMMA);
if (o!=SEMI && (o!=RPARN || skw!=ARG1))
decsyn(o);
return(offset);
}
/*
* Process a single declarator
*/
decl1(askw, tkw, offset, strp)
struct str *strp;
{
int t1, chkoff, a, elsize;
register int type, skw;
register struct hshtab *dsym;
struct tdim dim;
struct field *fldp;
int *dp;
skw = askw;
chkoff = 0;
mosflg = skw==MOS;
dim.rank = 0;
if ((peeksym=symbol())==SEMI || peeksym==RPARN)
return(0);
/*
* Filler field
*/
if (peeksym==COLON && skw==MOS) {
peeksym = -1;
t1 = conexp();
elsize = align(tkw, offset, t1);
bitoffs =+ t1;
return(elsize);
}
if ((t1=getype(&dim)) < 0)
goto syntax;
type = 0;
do
type = type<<TYLEN | (t1 & XTYPE);
while (((t1=>>TYLEN) & XTYPE)!=0);
type =| tkw;
dsym = defsym;
if (dim.rank == 0)
dsym->subsp = NULL;
else {
dp = gblock(dim.rank*sizeof(dim.rank));
funcbase = curbase;
for (a=0; a<dim.rank; a++) {
if ((t1 = dp[a] = dim.dimens[a])
&& (dsym->htype&XTYPE) == ARRAY
&& dsym->subsp[a] && t1!=dsym->subsp[a])
redec();
}
dsym->subsp = dp;
}
if ((type&XTYPE) == FUNC) {
if (skw==AUTO)
skw = EXTERN;
if (skw!=EXTERN)
error("Bad func. storage class");
}
if (!(dsym->hclass==0
|| ((skw==ARG||skw==REG) && dsym->hclass==ARG1)
|| (skw==EXTERN && dsym->hclass==EXTERN && dsym->htype==type)))
if (skw==MOS && dsym->hclass==MOS && dsym->htype==type)
chkoff = 1;
else {
redec();
goto syntax;
}
if (dsym->hclass && (dsym->htype&TYPE)==STRUCT && tkw==STRUCT)
if (dsym->strp != strp) {
error("Warning: structure redeclaration");
nerror--;
}
dsym->htype = type;
if (strp)
dsym->strp = strp;
if (skw==ARG1) {
if (paraml==0)
paraml = dsym;
else
parame->hoffset = dsym;
parame = dsym;
}
elsize = 0;
if (skw==MOS) {
elsize = length(dsym);
if ((peeksym = symbol())==COLON) {
elsize = 0;
peeksym = -1;
t1 = conexp();
a = align(type, offset, t1);
if (dsym->hflag&FFIELD) {
if (dsym->hstrp->bitoffs!=bitoffs
|| dsym->hstrp->flen!=t1)
redec();
} else {
dsym->hstrp = gblock(sizeof(*fldp));
funcbase = curbase;
}
dsym->hflag =| FFIELD;
dsym->hstrp->bitoffs = bitoffs;
dsym->hstrp->flen = t1;
bitoffs =+ t1;
} else
a = align(type, offset, 0);
elsize =+ a;
offset =+ a;
if (++nmems >= NMEMS) {
error("Too many structure members");
nmems =- NMEMS/2;
memlist =- NMEMS/2;
}
if (a)
*memlist++ = &structhole;
if (chkoff && dsym->hoffset != offset)
redec();
dsym->hoffset = offset;
*memlist++ = dsym;
}
if (skw==REG && dsym->hclass!=ARG1)
if ((dsym->hoffset = goodreg(dsym)) < 0)
skw = AUTO;
if (skw==AUTO) {
/* if (STAUTO < 0) { */
autolen =- rlength(dsym);
dsym->hoffset = autolen;
/* } else { */
/* dsym->hoffset = autolen; */
/* autolen =+ rlength(dsym); */
/* } */
} else if (skw==STATIC) {
dsym->hoffset = isn;
outcode("BBNBNB", BSS, LABEL, isn++,
SSPACE, rlength(dsym), PROG);
}
dsym->hclass = skw;
syntax:
return(elsize);
}
/*
* Read a declarator and get the implied type
*/
getype(adimp)
struct tdim *adimp;
{
int type;
register int o;
register struct hshtab *ds;
register struct tdim *dimp;
ds = defsym;
dimp = adimp;
switch(o=symbol()) {
case TIMES:
return(getype(dimp)<<TYLEN | PTR);
case LPARN:
type = getype(dimp);
ds = defsym;
if ((o=symbol()) != RPARN)
goto syntax;
goto getf;
case NAME:
defsym = ds = csym;
type = 0;
getf:
switch(o=symbol()) {
case LPARN:
if (xdflg) {
xdflg = 0;
ds = defsym;
declare(ARG1, 0, 0, 0);
defsym = ds;
xdflg++;
} else
if ((o=symbol()) != RPARN)
goto syntax;
type = type<<TYLEN | FUNC;
goto getf;
case LBRACK:
if (dimp->rank>=5) {
error("Rank too large");
dimp->rank = 4;
}
if ((o=symbol()) != RBRACK) {
peeksym = o;
cval = conexp();
if ((o=symbol())!=RBRACK)
goto syntax;
} else {
if (dimp->rank!=0)
error("Null dimension");
cval = 0;
}
for (o=0; o < dimp->rank; o++)
dimp->dimens[o] =* cval;
dimp->dimens[dimp->rank++] = cval;
type = type<<TYLEN | ARRAY;
goto getf;
}
peeksym = o;
return(type);
}
syntax:
decsyn(o);
return(-1);
}
/*
* Enforce alignment restrictions in structures,
* including bit-field considerations.
*/
align(type, offset, aflen)
{
register a, t, flen;
char *ftl;
flen = aflen;
a = offset;
t = type;
ftl = "Field too long";
if (flen==0) {
a =+ (NBPC+bitoffs-1) / NBPC;
bitoffs = 0;
}
while ((t&XTYPE)==ARRAY)
t = decref(t);
if (t!=CHAR) {
a = (a+ALIGN) & ~ALIGN;
if (a>offset)
bitoffs = 0;
}
if (flen) {
if (type==INT) {
if (flen > NBPW)
error(ftl);
if (flen+bitoffs > NBPW) {
bitoffs = 0;
a =+ NCPW;
}
} else if (type==CHAR) {
if (flen > NBPC)
error(ftl);
if (flen+bitoffs > NBPC) {
bitoffs = 0;
a =+ 1;
}
} else
error("Bad type for field");
}
return(a-offset);
}
/*
* Complain about syntax error in declaration
*/
decsyn(o)
{
error("Declaration syntax");
errflush(o);
}
/*
* Complain about a redeclaration
*/
redec()
{
error("%.8s redeclared", defsym->name);
}
/*
* Determine if a variable is suitable for storage in
* a register; if so return the register number
*/
goodreg(hp)
struct hshtab *hp;
{
int type;
type = hp->htype;
if ((type&TYPE)>CHAR && (type&XTYPE)==0
|| (type&XTYPE)>PTR || regvar<3)
return(-1);
return(--regvar);
}