413 lines
6.9 KiB
C
413 lines
6.9 KiB
C
#
|
|
/*
|
|
* C compiler, phase 1
|
|
*
|
|
*
|
|
* Handles processing of declarations,
|
|
* except for top-level processing of
|
|
* externals.
|
|
*/
|
|
|
|
#include "c0h.c"
|
|
|
|
/*
|
|
* Process a sequence of declaration statements
|
|
*/
|
|
declist(sclass)
|
|
{
|
|
register sc, elsize, offset;
|
|
int type;
|
|
|
|
offset = 0;
|
|
sc = sclass;
|
|
while ((elsize = getkeywords(&sclass, &type)) != -1) {
|
|
offset = declare(sclass, type, offset, elsize);
|
|
sclass = sc;
|
|
}
|
|
return(offset+align(INT, offset, 0));
|
|
}
|
|
|
|
/*
|
|
* Read the keywords introducing a declaration statement
|
|
*/
|
|
getkeywords(scptr, tptr)
|
|
int *scptr, *tptr;
|
|
{
|
|
register skw, tkw, longf;
|
|
int o, elsize, isadecl, ismos;
|
|
|
|
isadecl = 0;
|
|
longf = 0;
|
|
tkw = -1;
|
|
skw = *scptr;
|
|
elsize = 0;
|
|
ismos = skw==MOS;
|
|
for (;;) {
|
|
mosflg = ismos;
|
|
switch ((o=symbol())==KEYW? cval: -1) {
|
|
|
|
case AUTO:
|
|
case STATIC:
|
|
case EXTERN:
|
|
case REG:
|
|
if (skw && skw!=cval)
|
|
error("Conflict in storage class");
|
|
skw = cval;
|
|
break;
|
|
|
|
case LONG:
|
|
longf++;
|
|
break;
|
|
|
|
case STRUCT:
|
|
o = STRUCT;
|
|
elsize = strdec(&o, ismos);
|
|
cval = o;
|
|
case INT:
|
|
case CHAR:
|
|
case FLOAT:
|
|
case DOUBLE:
|
|
if (tkw>=0)
|
|
error("Type clash");
|
|
tkw = cval;
|
|
break;
|
|
|
|
default:
|
|
peeksym = o;
|
|
if (isadecl==0)
|
|
return(-1);
|
|
if (tkw<0)
|
|
tkw = INT;
|
|
if (skw==0)
|
|
skw = AUTO;
|
|
if (longf) {
|
|
if (tkw==FLOAT)
|
|
tkw = DOUBLE;
|
|
else if (tkw==INT)
|
|
tkw = LONG;
|
|
else
|
|
error("Misplaced 'long'");
|
|
}
|
|
*scptr = skw;
|
|
*tptr = tkw;
|
|
return(elsize);
|
|
}
|
|
isadecl++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Process a structure declaration; a subroutine
|
|
* of getkeywords.
|
|
*/
|
|
strdec(tkwp, mosf)
|
|
int *tkwp;
|
|
{
|
|
register elsize, o;
|
|
register struct hshtab *ssym;
|
|
int savebits;
|
|
struct hshtab *ds;
|
|
|
|
mosflg = 1;
|
|
ssym = 0;
|
|
if ((o=symbol())==NAME) {
|
|
ssym = csym;
|
|
if (ssym->hclass==0) {
|
|
ssym->hclass = STRTAG;
|
|
ssym->lenp = dimp;
|
|
chkdim();
|
|
dimtab[dimp++] = 0;
|
|
}
|
|
if (ssym->hclass != STRTAG)
|
|
redec();
|
|
mosflg = mosf;
|
|
o = symbol();
|
|
}
|
|
mosflg = 0;
|
|
if (o != LBRACE) {
|
|
if (ssym==0) {
|
|
syntax:
|
|
decsyn(o);
|
|
return(0);
|
|
}
|
|
if (ssym->hclass!=STRTAG)
|
|
error("Bad structure name");
|
|
if ((elsize = dimtab[ssym->lenp&0377])==0) {
|
|
*tkwp = RSTRUCT;
|
|
elsize = ssym;
|
|
}
|
|
peeksym = o;
|
|
} else {
|
|
ds = defsym;
|
|
mosflg = 0;
|
|
savebits = bitoffs;
|
|
bitoffs = 0;
|
|
elsize = declist(MOS);
|
|
bitoffs = savebits;
|
|
defsym = ds;
|
|
if ((o = symbol()) != RBRACE)
|
|
goto syntax;
|
|
if (ssym) {
|
|
if (dimtab[ssym->lenp&0377])
|
|
error("%.8s redeclared", ssym->name);
|
|
dimtab[ssym->lenp&0377] = elsize;
|
|
}
|
|
}
|
|
return(elsize);
|
|
}
|
|
|
|
/*
|
|
* Check that the dimension table has not overflowed
|
|
*/
|
|
chkdim()
|
|
{
|
|
if (dimp >= dimsiz) {
|
|
error("Dimension/struct table overflow");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Process a comma-separated list of declarators
|
|
*/
|
|
declare(askw, tkw, offset, elsize)
|
|
{
|
|
register int o;
|
|
register int skw;
|
|
|
|
skw = askw;
|
|
do {
|
|
offset =+ decl1(skw, tkw, offset, elsize);
|
|
} while ((o=symbol()) == COMMA);
|
|
if (o==SEMI || o==RPARN && skw==ARG1)
|
|
return(offset);
|
|
decsyn(o);
|
|
}
|
|
|
|
/*
|
|
* Process a single declarator
|
|
*/
|
|
decl1(askw, tkw, offset, elsize)
|
|
{
|
|
int t1, chkoff, a;
|
|
register int type, skw;
|
|
register struct hshtab *dsym;
|
|
|
|
skw = askw;
|
|
chkoff = 0;
|
|
mosflg = skw==MOS;
|
|
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()) < 0)
|
|
goto syntax;
|
|
type = 0;
|
|
do
|
|
type = type<<TYLEN | (t1 & XTYPE);
|
|
while (((t1=>>TYLEN) & XTYPE)!=0);
|
|
type =| tkw;
|
|
dsym = defsym;
|
|
if (!(dsym->hclass==0
|
|
|| (skw==ARG && 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;
|
|
}
|
|
dsym->htype = type;
|
|
if (skw)
|
|
dsym->hclass = skw;
|
|
if (skw==ARG1) {
|
|
if (paraml==0)
|
|
paraml = dsym;
|
|
else
|
|
parame->hoffset = dsym;
|
|
parame = dsym;
|
|
}
|
|
if (elsize && ((type&TYPE)==RSTRUCT || (type&TYPE)==STRUCT)) {
|
|
dsym->lenp = dimp;
|
|
chkdim();
|
|
dimtab[dimp++] = elsize;
|
|
}
|
|
elsize = 0;
|
|
if (skw==MOS) {
|
|
elsize = length(dsym);
|
|
t1 = 0;
|
|
if ((peeksym = symbol())==COLON) {
|
|
elsize = 0;
|
|
peeksym = -1;
|
|
t1 = conexp();
|
|
dsym->hflag =| FFIELD;
|
|
}
|
|
a = align(type, offset, t1);
|
|
elsize =+ a;
|
|
offset =+ a;
|
|
if (t1) {
|
|
if (chkoff && (dsym->bitoffs!=bitoffs
|
|
|| dsym->flen!=t1))
|
|
redec();
|
|
dsym->bitoffs = bitoffs;
|
|
dsym->flen = t1;
|
|
bitoffs =+ t1;
|
|
}
|
|
if (chkoff && dsym->hoffset != offset)
|
|
redec();
|
|
dsym->hoffset = offset;
|
|
}
|
|
if ((dsym->htype&XTYPE)==FUNC) {
|
|
if (dsym->hclass!=EXTERN && dsym->hclass!=AUTO)
|
|
error("Bad function");
|
|
dsym->hclass = EXTERN;
|
|
}
|
|
if (dsym->hclass==AUTO) {
|
|
autolen =+ rlength(dsym);
|
|
dsym->hoffset = -autolen;
|
|
} else if (dsym->hclass==STATIC) {
|
|
dsym->hoffset = isn;
|
|
outcode("BBNBNB", BSS, LABEL, isn++,
|
|
SSPACE, rlength(dsym), PROG);
|
|
} else if (dsym->hclass==REG) {
|
|
if ((type&TYPE)>CHAR && (type&XTYPE)==0
|
|
|| (type&XTYPE)>PTR || regvar<3)
|
|
error("Bad register %o", type);
|
|
dsym->hoffset = --regvar;
|
|
}
|
|
syntax:
|
|
return(elsize);
|
|
}
|
|
|
|
/*
|
|
* Read a declarator and get the implied type
|
|
*/
|
|
getype()
|
|
{
|
|
register int o, type;
|
|
register struct hshtab *ds;
|
|
|
|
switch(o=symbol()) {
|
|
|
|
case TIMES:
|
|
return(getype()<<TYLEN | PTR);
|
|
|
|
case LPARN:
|
|
type = getype();
|
|
if ((o=symbol()) != RPARN)
|
|
goto syntax;
|
|
goto getf;
|
|
|
|
case NAME:
|
|
defsym = ds = csym;
|
|
type = 0;
|
|
ds->ssp = dimp;
|
|
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:
|
|
chkdim();
|
|
if ((o=symbol()) != RBRACK) {
|
|
peeksym = o;
|
|
cval = conexp();
|
|
for (o=ds->ssp&0377; o<dimp; o++)
|
|
dimtab[o] =* cval;
|
|
dimtab[dimp++] = cval;
|
|
if ((o=symbol())!=RBRACK)
|
|
goto syntax;
|
|
} else
|
|
dimtab[dimp++] = 1;
|
|
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 && bitoffs) {
|
|
a =+ (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 > NCPW) {
|
|
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);
|
|
}
|