/* SYMBOL TABLE HANDLING */ #include /* Each character of the identifier is xored with an 8-bit mask which depends on the position of the character; the sum of these results is the hash value. The random masks are obtained from a congruence generator. */ #define IDF_HASHSIZE 256 /* size of hashtable, must be a power of 2 */ #ifndef IDF_HSIZE #define IDF_HSIZE 16 /* # of significant characters for hashing. This is NOT the number of significant characters! */ #endif #define IDF_HASH_X 0253 /* Knuth's X */ #define IDF_HASH_A 77 /* Knuth's a */ #define IDF_HASH_C 153 /* Knuth's c */ #define IDF_HASHMASK (IDF_HASHSIZE-1) /* since it is a power of 2 */ #define IDF_STARTHASH(hs) (hs = 0) #define IDF_ENHASH(hs,ch,hm) (hs += (ch ^ hm)) #define IDF_STOPHASH(hs) (hs &= IDF_HASHMASK) static char IDF_hmask[IDF_HSIZE]; static struct idf *IDF_hashtable[IDF_HASHSIZE]; /* All identifiers can in principle be reached through IDF_hashtable; IDF_hashtable[hc] is the start of a chain of idf's whose tags all hash to hc. Any identifier is entered into this list, regardless of the nature of its declaration (variable, selector, structure tag, etc.). */ static struct idf * IDF_new(tg, size, cpy) register char *tg; register int size; { static int nidf; static struct idf *pidf; #define NIDS 50 #define IBUFSIZ 2048 static unsigned int icnt; static char *ip; register char *p; if (! nidf--) { nidf += NIDS; pidf = (struct idf *) Malloc(NIDS * sizeof (struct idf)); clear((char *) pidf, NIDS * sizeof(struct idf)); } if (cpy) { if (size > icnt) { icnt = size > IBUFSIZ ? size : IBUFSIZ; p = Malloc(icnt); } else p = ip; icnt -= size; pidf->id_text = p; while (size--) { *p++ = *tg++; } ip = p; } else pidf->id_text = tg; return pidf++; } #ifdef IDF_DEBUG hash_stat() { register int i; print("Hash table tally:\n"); for (i = 0; i < IDF_HASHSIZE; i++) { register struct idf *notch = IDF_hashtable[i]; register int cnt = 0; while (notch) { cnt++; notch = notch->id_next; } print("%d %d\n", i, cnt); } print("End hash table tally\n"); } #endif IDF_DEBUG struct idf * str2idf(tg, cpy) char tg[]; { /* str2idf() returns an entry in the symbol table for the identifier tg. If necessary, an entry is created. */ register char *cp = tg; register char *phm = &IDF_hmask[0]; struct idf **hook; register struct idf *notch; register int hash; int size; IDF_STARTHASH(hash); while (*cp && phm < &IDF_hmask[IDF_HSIZE]) { IDF_ENHASH(hash, *cp++, *phm++); } IDF_STOPHASH(hash); while (*cp++) /* nothing. Find end of string */ ; size = cp - tg; /* The tag tg with length size and known hash value hash is looked up in the identifier table; if not found, it is entered if cpy >= 0. A pointer to it is returned. Notice that the chains of idf's are sorted alphabetically. */ hook = &IDF_hashtable[hash]; while ((notch = *hook)) { register char *s1 = tg; int cmp; cp = notch->id_text; while (!(cmp = (*s1 - *cp++))) { if (*s1++ == '\0') { break; } } if (cmp == 0) return notch; if (cmp < 0) break; hook = ¬ch->id_next; } /* a new struct idf must be inserted at the hook */ if (cpy < 0) return 0; notch = IDF_new(tg, size, cpy); notch->id_next = *hook; *hook = notch; /* hooked in */ return notch; } init_idf() { /* A simple congruence random number generator, as described in Knuth, vol 2. */ register int rnd = IDF_HASH_X; register char *phm; for (phm = &IDF_hmask[0]; phm < &IDF_hmask[IDF_HSIZE];) { *phm++ = rnd; rnd = (IDF_HASH_A * rnd + IDF_HASH_C) & IDF_HASHMASK; } }