/* * tsym.c -- functions for symbol table management. */ #include "..\h\config.h" #include "general.h" #include "tproto.h" #include "globals.h" #include "trans.h" #include "token.h" #include "tsym.h" #ifndef VarTran #include "lfile.h" #endif /* VarTran */ /* * Prototypes. */ hidden struct tgentry *alcglob Params((struct tgentry *blink, char *name,int flag,int nargs)); hidden struct tientry *alcid Params((char *nam,int len)); hidden struct tcentry *alclit Params((struct tcentry *blink, char *name, int len,int flag)); hidden struct tlentry *alcloc Params((struct tlentry *blink, char *name,int flag)); hidden struct tcentry *clookup Params((char *id,int flag)); hidden struct tgentry *glookup Params((char *id)); hidden struct tlentry *llookup Params((char *id)); hidden novalue putglob Params((char *id,int id_type, int n_args)); hidden int streq Params((int len,char *s1,char *s2)); #ifdef DeBugTrans novalue cdump Params((noargs)); novalue gdump Params((noargs)); novalue ldump Params((noargs)); #endif /* DeBugTrans */ /* * putid - install the identifier named by the string starting at strf * and extending for len bytes. The installation entails making an * entry in the identifier hash table and then making an identifier * table entry for it with alcid. A side effect of installation * is the incrementing of strf by the length of the string, thus * "saving" it. * * Nothing is changed if the identifier has already been installed. */ char *putid(len) int len; { register int hash; register char *s; register struct tientry *ip; int l; /* * Compute hash value by adding bytes and masking result with imask. * (Recall that imask is ihsize-1.) */ s = strf; hash = 0; l = len; while (l--) hash += *s++ & 0377; s = strf; l = len; hash &= imask; /* * If the identifier hasn't been installed, install it. */ if ((ip = ihash[hash]) != NULL) { /* collision */ for (;;) { /* work down i_blink chain until id is found or the end of the chain is reached */ if (l == ip->i_length && streq(l, s, ip->i_name)) return (ip->i_name); /* id is already installed */ if (ip->i_blink == NULL) { /* end of chain */ ip->i_blink = alcid(s,l); strf += l; return s; } ip = ip->i_blink; } } /* * Hashed to an empty slot. */ ihash[hash] = alcid(s,l); strf += l; return s; } /* * streq - compare s1 with s2 for len bytes, and return 1 for equal, * 0 for not equal. */ static int streq(len, s1, s2) register int len; register char *s1, *s2; { while (len--) if (*s1++ != *s2++) return 0; return 1; } /* * alcid - get the next free identifier table entry, and fill it in with * the specified values. */ static struct tientry *alcid(nam, len) char *nam; int len; { register struct tientry *ip; if (ifree >= &itable[isize]) tsyserr("out of identifier table space"); ip = ifree++; ip->i_blink = NULL; ip->i_name = nam; ip->i_length = len; return ip; } #ifndef VarTran /* * loc_init - clear the local symbol table. */ novalue loc_init() { register struct tlentry **lp; register struct tcentry **cp; static int maxlfree = 0; static int maxcfree = 0; /* clear local table */ maxlfree = (maxlfree > lfree-ltable) ? maxlfree : lfree-ltable; for (lp = lhash; lp < &lhash[lhsize]; lp++) *lp = NULL; lfree = ltable; /* clear constant table */ maxcfree = (maxcfree > ctfree-ctable) ? maxcfree : ctfree-ctable; for (cp = chash; cp < &chash[chsize]; cp++) *cp = NULL; ctfree = ctable; } /* * install - put an identifier into the global or local symbol table. * The basic idea here is to look in the right table and install * the identifier if it isn't already there. Some semantic checks * are performed. */ novalue install(name, flag, argcnt) char *name; int flag, argcnt; { union { struct tgentry *gp; struct tlentry *lp; } p; switch (flag) { case F_Global: /* a variable in a global declaration */ if ((p.gp = glookup(name)) == NULL) putglob(name, flag, argcnt); else p.gp->g_flag |= flag; break; case F_Proc|F_Global: /* procedure declaration */ case F_Record|F_Global: /* record declaration */ case F_Builtin|F_Global: /* external declaration */ if ((p.gp = glookup(name)) == NULL) putglob(name, flag, argcnt); else if ((p.gp->g_flag & (~F_Global)) == 0) { /* superfluous global declaration for record or proc */ p.gp->g_flag |= flag; p.gp->g_nargs = argcnt; } else /* the user can't make up his mind */ tfatal("inconsistent redeclaration", name); break; case F_Static: /* static declaration */ case F_Dynamic: /* local declaration (possibly implicit?) */ case F_Argument: /* formal parameter */ if ((p.lp = llookup(name)) == NULL) putloc(name,flag); else if (p.lp->l_flag == flag) /* previously declared as same type */ tfatal("redeclared identifier", name); else /* previously declared as different type */ tfatal("inconsistent redeclaration", name); break; default: tsyserr("install: unrecognized symbol table flag."); } } /* * putloc - make a local symbol table entry and return the index * of the entry in lhash. alcloc does the work if there is a collision. */ int putloc(id,id_type) char *id; int id_type; { register struct tlentry *ptr; if ((ptr = llookup(id)) == NULL) { /* add to head of hash chain */ ptr = lhash[lhasher(id)]; lhash[lhasher(id)] = alcloc(ptr, id, id_type); return (lhash[lhasher(id)] - ltable); } return (ptr - ltable); } /* * putglob makes a global symbol table entry. alcglob does the work if there * is a collision. */ static novalue putglob(id, id_type, n_args) char *id; int id_type, n_args; { register struct tgentry *ptr; if ((ptr = glookup(id)) == NULL) { /* add to head of hash chain */ ptr = ghash[ghasher(id)]; ghash[ghasher(id)] = alcglob(ptr, id, id_type, n_args); } } /* * putlit makes a constant symbol table entry and returns the index * of the entry in chash. alclit does the work if there is a collision. */ int putlit(id, idtype, len) char *id; int len, idtype; { register struct tcentry *ptr; if ((ptr = clookup(id,idtype)) == NULL) { /* add to head of hash chain */ ptr = chash[chasher(id)]; chash[chasher(id)] = alclit(ptr, id, len, idtype); return (chash[chasher(id)] - ctable); } return (ptr - ctable); } /* * llookup looks up id in local symbol table and returns pointer to * to it if found or NULL if not present. */ static struct tlentry *llookup(id) char *id; { register struct tlentry *ptr; ptr = lhash[lhasher(id)]; while (ptr != NULL && ptr->l_name != id) ptr = ptr->l_blink; return ptr; } /* * glookup looks up id in global symbol table and returns pointer to * to it if found or NULL if not present. */ static struct tgentry *glookup(id) char *id; { register struct tgentry *ptr; ptr = ghash[ghasher(id)]; while (ptr != NULL && ptr->g_name != id) { ptr = ptr->g_blink; } return ptr; } /* * clookup looks up id in constant symbol table and returns pointer to * to it if found or NULL if not present. */ static struct tcentry *clookup(id,flag) char *id; int flag; { register struct tcentry *ptr; ptr = chash[chasher(id)]; while (ptr != NULL && (ptr->c_name != id || ptr->c_flag != flag)) ptr = ptr->c_blink; return ptr; } /* * klookup looks up keyword named by id in keyword table and returns * its number (keyid). */ int klookup(id) register char *id; { register struct keyent *kp; for (kp = keytab; kp->keyid >= 0; kp++) if (strcmp(kp->keyname,id) == 0) return (kp->keyid); return 0; } #ifdef DeBugTrans /* * ldump displays local symbol table to stdout. */ novalue ldump() { register int i; register struct tlentry *lptr; fprintf(stderr,"Dump of local symbol table (%d entries)\n",lfree-ltable); fprintf(stderr," loc blink id (name) flags\n"); for (i = 0; i < lhsize; i++) for (lptr = lhash[i]; lptr != NULL; lptr = lptr->l_blink) fprintf(stderr,"%5d %5d %5d %20s %7o\n", lptr-ltable, lptr->l_blink, lptr->l_name, lptr->l_name, lptr->l_flag); fflush(stderr); } /* * gdump displays global symbol table to stdout. */ novalue gdump() { register int i; register struct tgentry *gptr; fprintf(stderr,"Dump of global symbol table (%d entries)\n", (int)(gfree-gtable)); fprintf(stderr," loc blink id (name) flags nargs\n"); for (i = 0; i < ghsize; i++) for (gptr = ghash[i]; gptr != NULL; gptr = gptr->g_blink) fprintf(stderr,"%5d %5d %5d %20s %7o %8d\n", gptr-gtable, gptr->g_blink, gptr->g_name, gptr->g_name, gptr->g_flag, gptr->g_nargs); fflush(stderr); } /* * cdump displays constant symbol table to stdout. */ novalue cdump() { register int i; register struct tcentry *cptr; fprintf(stderr,"Dump of constant symbol table (%d entries)\n",ctfree-ctable); fprintf(stderr," loc blink id (name) flags\n"); for (i = 0; i < chsize; i++) for (cptr = chash[i]; cptr != NULL; cptr = cptr->c_blink) fprintf(stderr,"%5d %5d %5d %20s %7o\n", cptr-ctable, cptr->c_blink, cptr->c_name, cptr->c_name, cptr->c_flag); fflush(stderr); } #endif /* DeBugTrans */ /* * alcloc allocates a local symbol table entry, fills in fields with * specified values and returns offset of new entry. */ static struct tlentry *alcloc(blink, name, flag) struct tlentry *blink; char *name; int flag; { register struct tlentry *lp; if (lfree >= <able[lsize]) tsyserr("out of local symbol table space"); lp = lfree++; lp->l_blink = blink; lp->l_name = name; lp->l_flag = flag; return lp; } /* * alcglob allocates a global symbol table entry, fills in fields with * specified values and returns offset of new entry. */ static struct tgentry *alcglob(blink, name, flag, nargs) struct tgentry *blink; char *name; int flag, nargs; { register struct tgentry *gp; if (gfree >= >able[gsize]) tsyserr("out of global symbol table space"); gp = gfree++; gp->g_blink = blink; gp->g_name = name; gp->g_flag = flag; gp->g_nargs = nargs; return gp; } /* * alclit allocates a constant symbol table entry, fills in fields with * specified values and returns offset of new entry. */ static struct tcentry *alclit(blink, name, len, flag) struct tcentry *blink; char *name; int len, flag; { register struct tcentry *cp; if (ctfree >= &ctable[csize]) tsyserr("out of constant table space"); cp = ctfree++; cp->c_blink = blink; cp->c_name = name; cp->c_length = len; cp->c_flag = flag; return cp; } /* * lout dumps local symbol table to fd, which is a .u1 file. */ novalue lout(fd) FILE *fd; { register int i; register struct tlentry *lp; i = 0; for (lp = ltable; lp < lfree; lp++) writecheck(fprintf(fd, "\tlocal\t%d,%06o,%s\n", i++, lp->l_flag, lp->l_name)); } /* * cout dumps constant symbol table to fd, which is a .u1 file. */ novalue cout(fd) FILE *fd; { register int l; register char *c; register struct tcentry *cp; int i; i = 0; for (cp = ctable; cp < ctfree; cp++) { writecheck(fprintf(fd, "\tcon\t%d,%06o", i++, cp->c_flag)); if (cp->c_flag & F_IntLit) writecheck(fprintf(fd, ",%d,%s\n", strlen(cp->c_name), cp->c_name)); else if (cp->c_flag & F_RealLit) writecheck(fprintf(fd, ",%s\n", cp->c_name)); else { c = cp->c_name; l = cp->c_length - 1; writecheck(fprintf(fd, ",%d", l)); while (l--) writecheck(fprintf(fd, ",%03o", *c++ & 0377)); writecheck(putc('\n', fd)); } } } /* * rout dumps a record declaration for name to file fd, which is a .u2 file. */ novalue rout(fd,name) FILE *fd; char *name; { register int i; register struct tlentry *lp; writecheck(fprintf(fd, "record\t%s,%d\n", name, (int)(lfree-ltable))); i = 0; for (lp = ltable; lp < lfree; lp++) writecheck(fprintf(fd, "\t%d,%s\n", i++, lp->l_name)); } /* * gout writes various items to fd, which is a .u2 file. These items * include: implicit status, tracing activation, link directives, * and the global table. */ novalue gout(fd) FILE *fd; { register int i; register char *name; register struct tgentry *gp; struct lfile *lfl; if (uwarn) name = "error"; else name = "local"; writecheck(fprintf(fd, "impl\t%s\n", name)); if (trace) writecheck(fprintf(fd, "trace\n")); lfl = lfiles; while (lfl) { #if MVS writecheck(fprintf(fd,"link\t%s\n",lfl->lf_name)); #else /* MVS */ writecheck(fprintf(fd,"link\t%s.u1\n",lfl->lf_name)); #endif /* MVS */ lfl = lfl->lf_link; } lfiles = 0; writecheck(fprintf(fd, "global\t%d\n", (int)(gfree-gtable))); i = 0; for (gp = gtable; gp < gfree; gp++) writecheck(fprintf(fd, "\t%d,%06o,%s,%d\n", i++, gp->g_flag, gp->g_name, gp->g_nargs)); } #endif /* VarTran */