160 lines
3.5 KiB
Plaintext
160 lines
3.5 KiB
Plaintext
|
/* SYMBOL TABLE HANDLING */
|
||
|
|
||
|
#include <alloc.h>
|
||
|
|
||
|
/* 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;
|
||
|
}
|
||
|
}
|