|
|
coherent
/*
* n0/gdecl.c
* Read in declarators and build up the DIM and INFO structures.
*/
#ifdef vax
#include "INC$LIB:cc0.h"
#else
#include "cc0.h"
#endif
/*
* Read declarator.
* The arg "tdp" is the dimensions from a typedef.
* The storage class is passed since
* it determines the lexic level of the lookup.
*/
gdecl(asp, adp, tdp, c, ls)
SYM **asp;
DIM **adp, *tdp;
int c, ls;
{
register SYM *sp;
DIM *dp;
int ll; /* Lexical level */
int aok; /* Args are OK flag */
sizeof_t bound; /* Array bound */
aok = (llex==LL_EXT && (c==C_GDEF || c==C_GREF || c==C_SEX) && nargs==0);
while (s == CONST || s == VOLATILE) {
/* Ignore these for now. They should be treated as MUL */
/* They can appear before the type-name as well */
lex();
}
if (s == MUL) {
lex();
if (gdecl(asp, adp, NULL, c, ls) == 0)
return 0;
*adp = tackdim(*adp, D_PTR, (sizeof_t)0);
while (tdp != NULL) {
*adp = tackdim(*adp, tdp->d_type, tdp->d_bound);
tdp = tdp->d_dp;
}
return 1;
}
if (s == LPAREN) {
lex();
if (gdecl(asp, adp, NULL, c, ls) == 0)
return 0;
mustbe(RPAREN);
sp = *asp;
dp = *adp;
if (nargs != 0)
aok = 0;
} else if (s == ID) {
if (c==C_ARG || c==C_PAUTO || c==C_PREG)
ll = LL_ARG;
else if (c==C_GDEF || c==C_GREF)
ll = LL_EXT;
else
ll = llex;
sp = deflookup(ls, ll);
dp = NULL;
lex();
} else {
cerror("declarator syntax");
while (s!=EOF && s!=COMMA && s!=SEMI)
skip();
return 0;
}
again:
if (s == LPAREN) {
lex();
garglist(&aok, &dp);
mustbe(RPAREN);
goto again;
}
if (s == LBRACK) {
lex();
bound = 0;
if (s != RBRACK)
bound = getbound();
mustbe(RBRACK);
dp = tackdim(dp, D_ARRAY, bound);
goto again;
}
while (tdp != NULL) {
dp = tackdim(dp, tdp->d_type, tdp->d_bound);
tdp = tdp->d_dp;
}
*asp = sp;
*adp = dp;
return 1;
}
/*
* This routine generates tags for tagless struct/union/enum
* declarations. This makes life easier for csd.
*/
SYM *newtag(ll) int ll;
{
sprintf(id, ".%d", newlab());
setid(id);
return deflookup(SL_TAG, ll);
}
/*
* This routine processes structure and union declarations.
* The type and INFO data gets passed back indirectly through the
* "call by reference" parameters.
* The storage class is passed so that local extern structure
* definitions get entered at the correct (global) lexical level.
*/
gstruct(sc, at, aip)
int sc, *at;
INFO **aip;
{
int c, dt, i, j, mc, t, tc, w, rf, ls, ll, nbpstrg;
SYM *tsp, *msp, *mp;
DIM *dp, **mdp;
INFO *ip, *nip;
TOK *oidp;
unsigned long ofs, max, bitsize;
ll = (sc == C_GREF) ? LL_EXT : llex;
ls = lsym;
if (notvariant(VSINU))
lsym += 1;
dt = T_STRUCT;
tc = C_STAG;
mc = C_MOS;
if (s == UNION) {
dt = T_UNION;
tc = C_UTAG;
mc = C_MOU;
}
tsp = NULL;
lex();
if (s == ID) {
tsp = reflookup(SL_TAG);
if (tsp == NULL)
tsp = deflookup(SL_TAG, ll);
oidp = idp; /* save idp, lex() may clobber it */
lex();
if (s != LBRACE) {
c = tsp->s_class;
if (c == C_NONE) {
*at = dt+1; /* Forward */
*aip = tsp;
return;
}
if (c==C_STAG || c==C_UTAG) {
if (c != tc)
tagmismatch(tsp);
*at = dt;
*aip = tsp->s_ip;
++tsp->s_ip->i_refc;
return;
}
cerror("\"%s\" is not a tag", tsp->s_id);
*at = T_INT;
*aip = NULL;
return;
}
idp = oidp; /* restore idp for deflookup() */
tsp = deflookup(SL_TAG, ll);
} else
tsp = newtag(ll);
mustbe(LBRACE);
nip = (INFO *) new(sizeof(INFO));
nip->i_refc = 1;
nip->i_nsp = 0;
ofs = 0;
max = 0;
while (s!=EOF && s!=RBRACE) {
gcandt(&c, &t, &dp, &ip, &rf);
if (t == T_NONE) {
if (s == ID)
cerror("\"%s\" is not a typedef name", id);
else
cerror("missing type in structure body");
while (s!=EOF && s!=RBRACE && s!=SEMI)
lex();
if (s == SEMI)
lex();
continue;
}
if (rf != 0 || c != C_NONE)
cerror("class not allowed in structure body");
if (isvariant(VSINU)) {
/*
* Handle the "struct" in "union" rule.
* A series of unnamed structures within a union are united
* into a set of named/typed offsets within the union.
* Basically, we add the unique members of the
* new structure to the members of the current union.
* Not strictly part of C, and only works if all MOS in
* same level of symbol table.
*/
if (dt==T_UNION && t==T_STRUCT && s==SEMI) {
notbook();
lex();
bitsize = (unsigned long)ip->i_size*NBPBYTE;
if (bitsize > max)
max = bitsize;
for (i=0; i<ip->i_nsp; ++i) {
mp = ip->i_sp[i];
j = nip->i_nsp;
while (--j >= 0)
if (nip->i_sp[j] == mp)
break;
if (j < 0) {
nip = newinfo(nip, mp);
if (tsp != NULL)
mp->s_flag |= S_TAG;
}
}
continue;
}
}
for (;;) {
if (s == COLON) {
lex();
newtree(sizeof(TREE));
++ininit;
w = iconexpr();
--ininit;
if (w < 0)
cerror("bad filler field width");
ofs = fieldalign(t, NULL, ip, w, ofs) + w;
} else if (gdecl(&msp, &mdp, dp, mc, ls)) {
if (sc == C_GREF)
msp->s_level = LL_EXT;
w = 0;
if (s == COLON) {
lex();
newtree(sizeof(TREE));
++ininit;
w = iconexpr();
--ininit;
if (w <= 0)
cerror("bad field width");
}
ofs = fieldalign(t, mdp, ip, w, ofs);
msp = declare(msp, mc, t, mdp, ip, rf, w, ofs);
nip = newinfo(nip, msp);
if (tsp != NULL)
msp->s_flag |= S_TAG;
if (w == 0)
ofs += (unsigned long)ssize(msp)*NBPBYTE;
else
ofs += w;
}
if (dt == T_UNION) {
if (ofs > max)
max = ofs;
ofs = 0;
}
if (s != COMMA)
break;
lex();
}
xdropinfo(t, ip);
mustbe(SEMI);
}
mustbe(RBRACE);
if (dt == T_STRUCT)
max = ofs;
nbpstrg = saligntype(nip) * NBPBYTE;
if (nbpstrg == 0)
nbpstrg = NBPBYTE;
max = (max + nbpstrg - 1) / nbpstrg;
max = max * nbpstrg / NBPBYTE;
if (max > MAXESIZE) {
cerror("size of %s too large",
(dt==T_STRUCT) ? "struct" : "union");
max = 0;
}
nip->i_size = max;
if (tsp != NULL)
tsp = declare(tsp, tc, 0, NULL, nip, 0);
*at = dt;
*aip = nip;
}
/*
* Read an enumeration.
*/
genum(sc, at, aip)
int sc, *at;
INFO **aip;
{
register SYM *sp, *tsp;
INFO *ip;
TOK *oidp;
int c, emv, emvmax, emvmin, ll;
ll = (sc == C_GREF) ? LL_EXT : llex;
tsp = NULL;
lex();
if (s == ID) {
tsp = reflookup(SL_TAG);
oidp = idp; /* save idp, lex() may clobber it */
lex();
if (s != LBRACE) {
if (tsp == NULL)
tsp = deflookup(SL_TAG, ll);
c = tsp->s_class;
if (c == C_NONE) {
*at = T_FENUM;
*aip = tsp;
return;
}
if (c == C_ETAG) {
*at = T_ENUM;
*aip = tsp->s_ip;
++tsp->s_ip->i_refc;
return;
}
cerror("\"%s\" is not an \"enum\" tag",
tsp->s_id);
*at = T_INT;
*aip = NULL;
return;
}
idp = oidp; /* restore idp for deflookup() */
tsp = deflookup(SL_TAG, ll);
} else
tsp = newtag(ll);
mustbe(LBRACE);
ip = (INFO *) new(sizeof(INFO));
ip->i_refc = 1;
ip->i_nsp = 0;
emvmax = emvmin = emv = 0;
for (;;) {
if (s==EOF || (s==RBRACE && ip->i_nsp == 0)) {
cerror("unexpected end of enumeration list");
break;
} else if (s==RBRACE) {
cwarn("trailing ',' in enumeration list");
break;
} else if (s != ID) {
cerror("error in enumeration list syntax");
skip();
continue;
}
sp = deflookup(SL_VAR, ll);
lex();
if (s == ASSIGN) {
lex();
newtree(sizeof(TREE));
++ininit;
emv = iconexpr();
--ininit;
}
if (emv > emvmax)
emvmax = emv;
if (emv < emvmin)
emvmin = emv;
ip = newinfo(ip, sp);
sp = declare(sp, C_MOE, 0, NULL, NULL, 0, emv);
++emv;
if (s == RBRACE)
break;
mustbe(COMMA);
}
if (s == RBRACE)
lex();
ip->i_type = (emvmax>MAXUCE || emvmin<0) ? T_INT : T_UCHAR;
if (tsp != NULL)
tsp = declare(tsp, C_ETAG, 0, NULL, ip, 0);
*at = T_ENUM;
*aip = ip;
}
/*
* Read an old-style K&R function argument list.
* '*aokp' indicates whether the storage class of the parent declarator
* and the position of the parenthesized list is appropriate for the
* formal parameter list of an actual function definition.
* '*adp' is where the function prototype DIM should be stored.
*/
garglist(aokp, adp) register int *aokp; register DIM **adp;
{
register SYM *ap;
if (*aokp==1) {
nargs = 0;
if (s != RPAREN)
for (;;) {
if (s != ID) {
cerror("argument list has incorrect syntax");
break;
}
if (nargs >= NARGS)
cfatal("too many arguments");
ap = deflookup(SL_VAR, LL_ARG);
ap = declare(ap, C_ARG, T_INT,
NULL, NULL, 0);
args[nargs++] = ap;
lex();
if (s != COMMA)
break;
lex();
}
*aokp = 0;
}
*adp = tackdim(*adp, D_FUNC, (sizeof_t)0);
}
/*
* Tack a DIM structure onto the end
* of the dimension list associated with "dp".
*/
DIM *
tackdim(dp, t, b)
DIM *dp;
int t;
sizeof_t b;
{
register DIM *dp1, *dp2;
dp1 = (struct dim *) new(sizeof(struct dim));
dp1->d_dp = NULL;
dp1->d_type = t;
dp1->d_bound = b;
if ((dp2 = dp) == NULL)
return dp1;
while (dp2->d_dp != NULL)
dp2 = dp2->d_dp;
dp2->d_dp = dp1;
return dp;
}
/*
* Release a DIM chain.
*/
dropdim(dp)
register DIM *dp;
{
if (dp != NULL) {
dropdim(dp->d_dp);
free((char *) dp);
}
}
/*
* Duplicate a DIM chain.
*/
DIM *
dupldim(dp)
register DIM *dp;
{
register DIM *np;
if (dp == NULL)
return NULL;
np = (struct dim *) new(sizeof(struct dim));
np->d_dp = dupldim(dp->d_dp);
np->d_type = dp->d_type;
np->d_bound = dp->d_bound;
return np;
}
/*
* Append a symbol to a struct/union/enum information array.
* Grow the array if necessary and possible.
*/
INFO *
newinfo(ip, sp)
register INFO *ip;
SYM *sp;
{
register INFO *tip;
register int i;
i = ip->i_nsp;
if ((i % 16) == 0) {
tip = ip;
ip = (INFO *) new(sizeof(INFO) + (i+16) * sizeof(SYM *));
ip->i_refc = tip->i_refc;
ip->i_data = tip->i_data;
ip->i_nsp = i;
while (--i >= 0)
ip->i_sp[i] = tip->i_sp[i];
free((char *) tip);
i = ip->i_nsp;
}
ip->i_sp[i] = sp;
ip->i_nsp += 1;
return ip;
}
/*
* Read an array bound.
* An array bound is a constant expression.
* It may be inside a cast, so save and restore the tree allocate pointer.
* If signed, give an error if the bound is less than 0.
* Call the machine dependent size check routine for upper bound check.
*/
sizeof_t getbound()
{
register TREE *tp;
extern TREE *expr();
register int t;
register long bound;
TREE *tmp;
tmp = talloc();
tp = expr();
treset(tmp);
if (tp->t_op == ICON)
bound = tp->t_ival;
else if (tp->t_op == LCON)
bound = tp->t_lval;
else if (tp->t_op == ZCON)
bound = tp->t_zval;
else {
cerror("array bound must be a constant");
return 0;
}
t = tltype(tp);
if ((t==T_CHAR || t==T_SHORT || t==T_INT || t==T_LONG)
&& bound < 0) {
cerror("array bound must be positive");
return 0;
}
return szcheck(bound, 1, "array bound");
}
/*
* The SYM 'sp' has storage class C_STAG or C_UTAG.
* A new declaration has been encountered which is of the wrong class.
* Print a diagnostic giving the name of the tag and its previous class.
*/
tagmismatch(sp)
register SYM *sp;
{
register char *p;
p = (sp->s_class == C_UTAG) ? "union" : "structure";
cerror("\"%s\" is a %s tag", sp->s_id, p);
}
/*
* Read a cast.
* Return a pointer to a CAST tree node,
* or NULL if not a legal cast.
*/
TREE *
cast()
{
register TREE *tp;
DIM *dp;
INFO *ip;
DIM *cast1();
int rf;
int c, t;
gcandt(&c, &t, &dp, &ip, &rf);
if (c==C_NONE && t==T_NONE && rf==0)
return NULL;
if (rf != 0 || c != C_NONE)
cerror("storage class not allowed in cast");
if (t == T_NONE) {
cerror("type required in cast");
t = T_INT;
}
dp = cast1(dp);
if (t==T_VOID && dp!=NULL && !isfunction(dp)) {
cerror("illegal use of void type in cast");
t = T_INT;
}
mustbe(RPAREN);
tp = talloc();
tp->t_op = CAST;
tp->t_type = t;
tp->t_dp = dp;
tp->t_ip = ip;
xdropinfo(t, ip);
return tp;
}
/* this is the cast version of gdecl() */
DIM *
cast1(tdp)
DIM *tdp;
{
register DIM *dp;
register sizeof_t b;
DIM *cast2();
while (s == CONST || s == VOLATILE) {
lex();
}
if (s == MUL) {
lex();
dp = cast2(cast1(NULL), D_PTR, (sizeof_t)0);
} else {
dp = NULL;
if (s == LPAREN) {
lex();
if (s != RPAREN) {
dp = cast1(NULL);
mustbe(RPAREN);
} else {
lex();
dp = cast2(dp, D_FUNC, (sizeof_t)0);
}
}
again:
if (s == LPAREN) {
DIM *tdp;
lex();
tdp = dp;
cproto(&tdp);
dp = tdp;
mustbe(RPAREN);
goto again;
}
if (s == LBRACK) {
lex();
b = 0;
if (s != RBRACK)
b = getbound();
mustbe(RBRACK);
dp = cast2(dp, D_ARRAY, b);
goto again;
}
}
while (tdp != NULL) {
dp = cast2(dp, tdp->d_type, tdp->d_bound);
tdp = tdp->d_dp;
}
return dp;
}
/* this is the cast version of tackdim() */
DIM *
cast2(dp, t, b)
DIM *dp;
int t;
sizeof_t b;
{
register DIM *dp1, *dp2;
dp1 = (struct dim *) talloc();
dp1->d_dp = NULL;
dp1->d_type = t;
dp1->d_bound = b;
if ((dp2 = dp) == NULL)
return dp1;
while (dp2->d_dp != NULL)
dp2 = dp2->d_dp;
dp2->d_dp = dp1;
return dp;
}
cproto(adp) DIM **adp;
{
*adp = cast2(*adp, D_FUNC, (sizeof_t)0);
}
/* end of n0/gdecl.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.