/* Copyright (c) 1988 by Sozobon, Limited. Author: Johann Ruegg * * Permission is granted to anyone to use this software for any purpose * on any computer system, and to redistribute it freely, with the * following restrictions: * 1) No charge may be made other than reasonable charges for reproduction. * 2) Modified versions must be clearly marked as such. * 3) The authors are not responsible for any harmful consequences * of using this software, even if they result from defects in it. * * decl.c * * Do all declarations * * Currently, * struct tags are local * struct members are tied to the struct * enum tags are ignored * enum members are local */ #include #include "param.h" #include "tok.h" #include "nodes.h" extern NODE *cur; extern level; NODEP symtab[NHASH], tagtab; extern NODE *blktab; NODEP alltags(), allsyms(), llook(), hlook(); extern int oflags[]; #define debug oflags['v'-'a'] /* look for global data decls return when see something weird return last ID declared */ NODEP glb_decls() { register NODEP head, xp; NODEP d_type(), def_type(), d_declr(); int sclass; for(;;) { sclass = d_scl(HERE_SC); head = d_type(); if (head == NULL) head = def_type(); if (ok_gsh(sclass, head) == 0) continue; more: xp = d_declr(head,0); if (ok_gx(xp,head)) { xp->e_sc = sclass; opt_ginit(xp); new_sym(symtab,xp); if (xp->n_tptr->t_token == '(') { /* func */ if (cur->e_token == ',' || cur->e_token == ';') fix_fun(xp); else return xp; } } if (cur->e_token == ',') { fadvnode(); goto more; } if (cur->e_token == ';') { fadvnode(); } else return NULL; } } /* do local or arg decls return 1 if see something */ loc_decls() { register NODEP head, xp; NODEP d_type(), def_type(), d_declr(); int sclass; int regs; long size; int rv = 0; size = level > 2 ? blktab->n_next->b_size : 0; regs = level > 1 ? blktab->n_next->b_regs : 0; while (is_ty_start()) { rv++; sclass = d_scl(K_AUTO); head = d_type(); if (head == NULL) head = def_type(); if (ok_lsh(sclass, head) == 0) continue; more: xp = d_declr(head,0); if (ok_lx(xp,head)) { xp->e_sc = sclass; if (level > 1) /* not args */ lc_size(&size, ®s, xp); new_sym(&blktab->b_syms,xp); fix_fun(xp); opt_linit(xp,sclass); } if (cur->e_token == ',') { fadvnode(); goto more; } if (cur->e_token == ';') { fadvnode(); } else { error("expect ;"); return 1; } } while (STACKALN & size) size++; blktab->b_size = size; blktab->b_regs = regs; return rv; } /* Decls inside Struct/Union */ su_decls(listpp, isunion, sizep, alnp) NODEP *listpp; long *sizep; char *alnp; { register NODEP head, xp; NODEP d_type(), d_declr(); long size; char aln; int fldw, fldoff; aln = 0; size = 0; fldoff = 0; for(;;) { head = d_type(); if (head == NULL) goto out; if (ok_suh(head) == 0) continue; more: xp = d_declr(head,0); opt_field(xp,&fldw,isunion); if (ok_sux(xp,head)) { if (fldw > 0) { /* handle field */ su_fld(&size,&aln,xp,fldw,&fldoff); xp->e_offs = size; } else { /* handle non-field */ afterfld(&size,&fldoff); xp->e_offs = isunion ? 0 : size; su_size(&size,&aln,xp,isunion); } new_sym(listpp,xp); listpp = &xp->n_next; } else if (fldw == 0) { afterfld(&size, &fldoff); } if (cur->e_token == ',') { fadvnode(); goto more; } if (cur->e_token == ';') { fadvnode(); } else goto out; } out: afterfld(&size,&fldoff); while (aln & size) size++; *sizep = size; *alnp = aln; return; } /* Decls inside Enum */ en_decls() { register NODEP head, xp; NODEP bas_type(), d_declr(); int curval = 0; for(;;) { head = bas_type(K_INT); more: xp = d_declr(head,0); if (ok_enx(xp,head)) { opt_enval(&curval); xp->e_ival = curval++; xp->e_sc = ENUM_SC; new_sym(level ? blktab->b_syms : (NODE *)symtab, xp); } if (cur->e_token == ',') { fadvnode(); goto more; } return; } } /* * called from expr.c, make a cast * only called if is_ty_start(); */ NODE * makecast() { NODEP head, xp; register NODEP np; NODEP d_type(), d_declr(), def_type(); head = d_type(); /* we know this is not NULL */ xp = d_declr(head, 1); if (ok_cast(xp,head) == 0) { xp = def_type(); /* return cast to INT */ } np = allocnode(); np->e_token = TCONV; np->n_tptr = xp; if (xp == head) np->n_flags |= N_COPYT; if (debug) { printf("Make cast"); printnode(np); } return np; } is_ty_start() { NODEP rv; if (is_tykw(cur->e_token)) return 1; if (cur->e_token == ID) { rv = allsyms(cur); if (rv && rv->e_sc == K_TYPEDEF) return 1; } return 0; } /* assemble decl and put in listpp */ new_sym(listpp, xp) NODEP *listpp; NODEP xp; { NODEP old; if (xp == NULL) return 0; /* put in table */ if (debug) { printf("New sym sc %c", "EARTSCH"[xp->e_sc-K_EXTERN]); printnode(xp); } /* later look for previous definition */ if (listpp == (NODE **)symtab) { old = hlook(listpp, xp); if (old == NULL || def2nd(old, xp)) puthlist(listpp, xp); } else { old = llook(*listpp, xp); if (old == NULL || def2nd(old, xp)) putlist(listpp, xp); } return 1; } /* look for storage class */ d_scl(defau) { int rv; if (is_sclass(cur->e_token)) { rv = cur->e_token; fadvnode(); return rv; } /* no storage class specified */ return defau; } NODEP d_declr(head, forcast) NODEP head; { NODEP e1; NODEP declarator(), rev_decl(); NODEP xp, tailp; e1 = declarator(); xp = rev_decl(e1, &tailp, forcast); if (xp) { tailp->n_tptr = head; tailp->n_flags |= N_COPYT; return xp; } else if (forcast) return head; else return NULL; } NODEP rev_decl(np,tailpp,forcast) NODEP np, *tailpp; { NODEP rv, scan, nxt; rv = NULL; for (scan = np; scan != NULL; scan = nxt) { nxt = scan->n_next; scan->n_next = NULL; if (rv == NULL) { *tailpp = scan; scan->n_tptr = NULL; rv = scan; } else { scan->n_tptr = rv; rv = scan; } e_to_t(rv); switch (rv->t_token) { case UNARY '*': sprintf(rv->n_name, "Ptr to"); break; case '(': sprintf(rv->n_name, "Fun ret"); break; case '[': sprintf(rv->n_name, "Ary of"); break; case ID: break; default: error("bad type xpr"); return NULL; } } /* if normal decl and see something, must see id first */ if (!ok_revx(rv,forcast)) rv = NULL; return rv; } /* * Looking for type part of a decl */ NODEP d_type() { int btype, adj; NODEP rv; NODEP bas_type(), decl_su(), decl_enum(); /* look for 'struct', 'union', 'enum' or typedef ID */ switch (cur->e_token) { case ID: rv = allsyms(cur); if (rv && rv->e_sc == K_TYPEDEF) { fadvnode(); rv = rv->n_tptr; return rv; } return NULL; case K_STRUCT: return decl_su(0); case K_UNION: return decl_su(1); case K_ENUM: return decl_enum(); } /* look for modifiers 'long', 'short', 'unsigned' */ adj = 0; while (is_tadj(cur->e_token)) { switch (cur->e_token) { case K_SHORT: adj |= SAW_SHORT; break; case K_LONG: adj |= SAW_LONG; break; case K_UNSIGNED: adj |= SAW_UNS; break; } fadvnode(); } /* look for base type 'char', 'int', 'float', 'double', 'void'*/ if (is_btype(cur->e_token)) { btype = cur->e_token; fadvnode(); } else if (adj == 0) /* saw nothing */ return NULL; else btype = K_INT; if (adj) btype = adj_type(btype, adj); rv = bas_type(btype); return rv; } NODEP decl_enum() { NODEP bas_type(); fadvnode(); /* skip 'enum' */ if (cur->e_token == ID) { /* ignore tag */ fadvnode(); } if (cur->e_token == '{') { /* new declaration */ fadvnode(); /* skip '{' */ en_decls(); /* global scope */ if (cur->e_token != '}') error("expect }"); else fadvnode(); /* skip '}' */ } return bas_type(K_INT); } extern lineno; NODEP decl_su(isunion) { register NODEP rv, tagp; NODEP *attab; fadvnode(); /* skip 'struct' or 'union' */ attab = level ? &blktab->b_tags : &tagtab; tagp = NULL; if (cur->e_token == ID) { /* hold on to ID node */ tagp = cur; e_to_t(tagp); advnode(); nnmadd(tagp, isunion ? ".U" : ".S"); } if (cur->e_token == '{') { /* new declaration */ if (tagp == NULL) { /* make fake name */ tagp = allocnode(); sprintf(tagp->n_name, isunion ? "%dU" : "%dS", lineno); } fadvnode(); /* skip '{' */ if (rv = llook(*attab, tagp)) { freenode(tagp); if (rv->n_right) { errors("struct redefined", rv->n_name); freenode(rv->n_right); rv->n_right = NULL; } } else { /* new defn */ rv = tagp; rv->t_token = isunion ? K_UNION : K_STRUCT; rv->n_flags |= N_BRKPR; /* break print loops */ putlist(attab, rv); } su_decls(&rv->n_right, isunion, &rv->t_size, &rv->t_aln); if (cur->e_token != '}') error("expect }"); else fadvnode(); /* skip '}' */ } else { /* reference to old */ if (tagp == NULL) { error("nonsense struct"); goto out; } /* ANSI special decl struct ; for hiding old tag within block */ if (cur->e_token == ';' && level) rv = llook(*attab, tagp); else rv = alltags(tagp); if (rv == NULL) { /* delayed tag */ rv = tagp; rv->t_token = isunion ? K_UNION : K_STRUCT; rv->n_flags |= N_BRKPR; /* break print loops */ putlist(attab, rv); goto out; } else freenode(tagp); } out: return rv; } NODE * alltags(np) NODE *np; { register NODE *bp; NODE *rv; for (bp=blktab; bp != NULL; bp = bp->n_next) if ((rv = llook(bp->b_tags, np)) != NULL) return rv; return llook(tagtab, np); } NODE * allsyms(np) NODE *np; { register NODE *bp; NODE *rv; for (bp=blktab; bp != NULL; bp = bp->n_next) if ((rv = llook(bp->b_syms, np)) != NULL) return rv; return hlook(symtab, np); } sim_type(a,b) register NODE *a, *b; { more: if (a == b) return 1; if (a == NULL || b == NULL) return 0; if (a->t_token != b->t_token) return 0; if (a->t_size != b->t_size && a->t_size && b->t_size) return 0; a = a->n_tptr; b = b->n_tptr; goto more; } /* 2nd def of same name at same level */ /* OK if one extern and types the same */ def2nd(old,new) NODEP old, new; { int osc, nsc; if (sim_type(old->n_tptr, new->n_tptr) == 0) goto bad; osc = old->e_sc; nsc = new->e_sc; if (nsc == K_EXTERN) { /* works only if no further use allowed */ freenode(new); return 0; } if (osc == K_EXTERN) { /* replace old def with new one */ /* for now, just put new one on list too */ return 1; } bad: errorn("bad 2nd decl of ", new); /* use 2nd def so other stuff works */ return 1; } /* saw fun but no body */ fix_fun(np) NODE *np; { if (np == NULL) return; if (np->n_tptr->t_token == '(') { /* fix to extern */ if (np->e_sc != K_TYPEDEF) np->e_sc = K_EXTERN; } } e_to_t(np) NODE *np; { int token; token = np->e_token; np->t_token = token; np->t_size = 0; np->t_aln = 0; }