# /* * 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 hshtab typer; offset = 0; sc = sclass; while (getkeywords(&sclass, &typer)) { offset = declare(sclass, &typer, offset); sclass = sc; } return(offset+align(INT, offset, 0)); } /* * Read the keywords introducing a declaration statement * Store back the storage class, and fill in the type * entry, which looks like a hash table entry. */ getkeywords(scptr, tptr) int *scptr; struct hshtab *tptr; { register skw, tkw, longf; int o, isadecl, ismos, unsignf; isadecl = 0; longf = 0; unsignf = 0; tptr->htype = INT; tptr->hstrp = NULL; tptr->hsubsp = NULL; tkw = -1; skw = *scptr; ismos = skw==MOS||skw==MOU; for (;;) { mosflg = ismos && isadecl; o = symbol(); if (o==NAME && csym->hclass==TYPEDEF && tkw<0) { tkw = csym->htype; tptr->hsubsp = csym->hsubsp; tptr->hstrp = csym->hstrp; isadecl++; continue; } switch (o==KEYW? cval: -1) { case AUTO: case STATIC: case EXTERN: case REG: case TYPEDEF: if (skw && skw!=cval) { if (skw==ARG && cval==REG) cval = AREG; else error("Conflict in storage class"); } skw = cval; break; case UNSIGN: unsignf++; break; case LONG: longf++; break; case ENUM: strdec(ismos, cval); cval = INT; goto types; case UNION: case STRUCT: tptr->hstrp = strdec(ismos, cval); cval = STRUCT; case INT: case CHAR: case FLOAT: case DOUBLE: types: 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 = blklev==0? DEFXTRN: AUTO; if (unsignf) { if (tkw==INT) tkw = UNSIGN; else error("Misplaced 'unsigned'"); } if (longf) { if (tkw==FLOAT) tkw = DOUBLE; else if (tkw==INT) tkw = LONG; else error("Misplaced 'long'"); } *scptr = skw; tptr->htype = tkw; return(1); } isadecl++; } } /* * Process a structure, union, or enum declaration; a subroutine * of getkeywords. */ struct str * strdec(mosf, kind) { register elsize, o; register struct hshtab *ssym; int savebits; struct hshtab **savememlist; int savenmems; struct str *strp; struct hshtab *ds; struct hshtab *mems[NMEMS]; struct hshtab typer; int tagkind; if (kind!=ENUM) { tagkind = STRTAG; mosflg = 1; } else tagkind = ENUMTAG; ssym = 0; if ((o=symbol())==NAME) { ssym = csym; mosflg = mosf; o = symbol(); if (o==LBRACE && ssym->hblklevhclass==0) { ssym->hclass = tagkind; ssym->strp = gblock(sizeof(*strp)); funcbase = curbase; ssym->strp->ssize = 0; ssym->strp->memlist = NULL; } if (ssym->hclass != tagkind) redec(); strp = ssym->strp; } 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!=tagkind) error("Bad structure/union/enum name"); peeksym = o; } else { ds = defsym; mosflg = 0; savebits = bitoffs; savememlist = memlist; savenmems = nmems; memlist = mems; nmems = 2; bitoffs = 0; if (kind==ENUM) { typer.htype = INT; typer.hstrp = strp; declare(ENUM, &typer, 0); } else elsize = declist(kind==UNION?MOU: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, tptr, offset) struct hshtab *tptr; { register int o; register int skw, isunion; skw = askw; isunion = 0; if (skw==MOU) { skw = MOS; isunion++; mosflg = 1; if ((peeksym=symbol()) == SEMI) { o = length(tptr); if (o>offset) offset = o; } } do { if (skw==ENUM && (peeksym=symbol())==RBRACE) { o = peeksym; peeksym = -1; break; } o = decl1(skw, tptr, isunion?0:offset, NULL); if (isunion) { o =+ align(CHAR, o, 0); if (o>offset) offset = o; } else offset =+ o; } while ((o=symbol()) == COMMA); if (o==RBRACE) { peeksym = o; o = SEMI; } if (o!=SEMI && (o!=RPARN || skw!=ARG1)) decsyn(o); return(offset); } /* * Process a single declarator */ decl1(askw, atptr, offset, absname) struct hshtab *atptr, *absname; { int t1, chkoff, a, elsize; register int skw; int type; register struct hshtab *dsym; register struct hshtab *tptr; struct tdim dim; struct field *fldp; int *dp; int isinit; skw = askw; tptr = atptr; chkoff = 0; mosflg = skw==MOS; dim.rank = 0; if (((peeksym=symbol())==SEMI || peeksym==RPARN) && absname==NULL) return(0); /* * Filler field */ if (peeksym==COLON && skw==MOS) { peeksym = -1; t1 = conexp(); elsize = align(tptr->htype, offset, t1); bitoffs =+ t1; return(elsize); } t1 = getype(&dim, absname); if (t1 == -1) return(0); if (tptr->hsubsp) { type = tptr->htype; for (a=0; type&XTYPE;) { if ((type&XTYPE)==ARRAY) dim.dimens[dim.rank++] = tptr->hsubsp[a++]; type =>> TYLEN; } } type = tptr->htype & ~TYPE; while (t1&XTYPE) { if (type&BIGTYPE) { typov(); type = t1 = 0; } type = type<> TYLEN; } type =| tptr->htype&TYPE; if (absname) defsym = absname; dsym = defsym; if (dsym->hblklev < blklev) pushdecl(dsym); if (dim.rank == 0) dsym->subsp = NULL; else { dp = gblock(dim.rank*sizeof(dim.rank)); funcbase = curbase; if (skw==EXTERN) maxdecl = curbase; for (a=0; ahtype&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 && skw!=TYPEDEF) && absname==NULL) error("Bad func. storage class"); } if (!(dsym->hclass==0 || ((skw==ARG||skw==AREG) && 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 && (type&TYPE)==STRUCT) if (dsym->hstrp != tptr->hstrp) { error("Warning: structure redeclaration"); nerror--; } dsym->htype = type; if (tptr->hstrp) dsym->hstrp = tptr->hstrp; if (skw==TYPEDEF) { dsym->hclass = TYPEDEF; return(0); } if (absname) return(0); if (skw==ARG1) { if (paraml==0) paraml = dsym; else parame->hoffset = dsym; parame = dsym; dsym->hclass = skw; return(0); } 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) if ((dsym->hoffset = goodreg(dsym)) < 0) skw = AUTO; dsym->hclass = skw; isinit = 0; if ((a=symbol())!=COMMA && a!=SEMI && a!=RBRACE) isinit++; if (a!=ASSIGN) peeksym = a; if (skw==AUTO) { /* if (STAUTO < 0) { */ autolen =- rlength(dsym); dsym->hoffset = autolen; if (autolen < maxauto) maxauto = autolen; /* } else { */ /* dsym->hoffset = autolen; */ /* autolen =+ rlength(dsym); */ /* if (autolen > maxauto) */ /* maxauto = autolen; */ /* } */ if (isinit) cinit(dsym, 0, AUTO); } else if (skw==STATIC) { dsym->hoffset = isn; if (isinit) { outcode("BBN", DATA, LABEL, isn++); if (cinit(dsym, 1, STATIC) & ALIGN) outcode("B", EVEN); } else outcode("BBNBN", BSS, LABEL, isn++, SSPACE, rlength(dsym)); outcode("B", PROG); } else if (skw==REG && isinit) cinit(dsym, 0, REG); else if (skw==ENUM) { if (type!=INT) error("Illegal enumeration %.8s", dsym->name); dsym->hclass = ENUMCON; dsym->hoffset = offset; if (isinit) cinit(dsym, 0, ENUMCON); elsize = dsym->hoffset-offset+1; } prste(dsym); syntax: return(elsize); } /* * Push down an outer-block declaration * after redeclaration in an inner block. */ pushdecl(asp) struct phshtab *asp; { register struct phshtab *sp, *nsp; sp = asp; nsp = gblock(sizeof(*nsp)); maxdecl = funcbase = curbase; cpysymb(nsp, sp); sp->hclass = 0; sp->hflag =& (FKEYW|FMOS); sp->htype = 0; sp->hoffset = 0; sp->hblklev = blklev; sp->hpdown = nsp; } /* * Copy the non-name part of a symbol */ cpysymb(s1, s2) struct phshtab *s1, *s2; { register struct phshtab *rs1, *rs2; rs1 = s1; rs2 = s2; rs1->hclass = rs2->hclass; rs1->hflag = rs2->hflag; rs1->htype = rs2->htype; rs1->hoffset = rs2->hoffset; rs1->hsubsp = rs2->hsubsp; rs1->hstrp = rs2->hstrp; rs1->hblklev = rs2->hblklev; rs1->hpdown = rs2->hpdown; } /* * Read a declarator and get the implied type */ getype(adimp, absname) struct tdim *adimp; struct hshtab *absname; { static struct hshtab argtype; int type; register int o; register struct hshtab *ds; register struct tdim *dimp; ds = defsym; dimp = adimp; type = 0; switch(o=symbol()) { case TIMES: type = getype(dimp, absname); if (type==-1) return(type); if (type&BIGTYPE) { typov(); type = 0; } return(type<rank>=5) { error("Rank too large"); dimp->rank = 4; } if ((o=symbol()) != RBRACK) { peeksym = o; cval = conexp(); defsym = ds; if ((o=symbol())!=RBRACK) goto syntax; } else { if (dimp->rank!=0) error("Null dimension"); cval = 0; } dimp->dimens[dimp->rank++] = cval; if (type&BIGTYPE) { typov(); type = 0; } type = type<offset) bitoffs = 0; } if (flen) { if (type==INT || type==UNSIGN) { 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; /* * Special dispensation for unions */ if (type==STRUCT && length(hp)<=SZINT) type = INT; if ((type!=INT && type!=CHAR && type!=UNSIGN && (type&XTYPE)==0) || (type&XTYPE)>PTR || regvar<3) return(-1); return(--regvar); }