/* 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 HASHSIZE 256 /* size of hashtable, must be a power of 2 */ #ifndef IDF_HSIZE #define IDF_HSIZE 64 /* # of significant characters for hashing. This is NOT the number of significant characters! */ #endif #define HASH_X 0253 /* Knuth's X */ #define HASH_A 77 /* Knuth's a */ #define HASH_C 153 /* Knuth's c */ #define HASHMASK (HASHSIZE-1) /* since it is a power of 2 */ #define STARTHASH() (0) #define ENHASH(hs,ch,hm) (hs + (ch ^ hm)) #define STOPHASH(hs) (hs & HASHMASK) static char hmask[IDF_HSIZE]; static struct idf *id_hashtable[HASHSIZE]; /* All identifiers can in principle be reached through id_hashtable; id_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 * new_idf(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 DEBUG hash_stat() { register int i; print("Hash table tally:\n"); for (i = 0; i < HASHSIZE; i++) { register struct idf *notch = id_hashtable[i]; register int cnt = 0; while (notch) { cnt++; notch = notch->next; } print("%d %d\n", i, cnt); } print("End hash table tally\n"); } #endif 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 = &hmask[0]; struct idf **hook; register struct idf *notch; register int hash; int size; hash = STARTHASH(); while (*cp && phm < &hmask[IDF_HSIZE]) { hash = ENHASH(hash, *cp++, *phm++); } hash = 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 = &id_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->next; } /* a new struct idf must be inserted at the hook */ if (cpy < 0) return 0; notch = new_idf(tg, size, cpy); notch->next = *hook; *hook = notch; /* hooked in */ return notch; } init_idf() { /* A simple congruence random number generator, as described in Knuth, vol 2. */ int rnd = HASH_X; register char *phm; for (phm = &hmask[0]; phm < &hmask[IDF_HSIZE];) { *phm++ = rnd; rnd = (HASH_A * rnd + HASH_C) & HASHMASK; } }