You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
3.9 KiB
C
182 lines
3.9 KiB
C
/*
|
|
* File: symtab.c
|
|
* --------------
|
|
* This file implements the symbol table abstraction.
|
|
*/
|
|
|
|
#include "symtab.h"
|
|
#include "genlib.h"
|
|
#include "strlib.h"
|
|
#include <stdio.h>
|
|
|
|
/*
|
|
* Constants
|
|
* ---------
|
|
* NBuckets -- Number of buckets in the hash table
|
|
*/
|
|
|
|
#define NBuckets 101
|
|
|
|
/*
|
|
* Type: cellT
|
|
* -----------
|
|
* This type defines a linked list cell for the symbol table.
|
|
*/
|
|
|
|
typedef struct cellT {
|
|
string key;
|
|
void* value;
|
|
struct cellT* link;
|
|
} cellT;
|
|
|
|
/*
|
|
* Type: symtabCDT
|
|
* ---------------
|
|
* This type defines the underlying concrete representation for a
|
|
* symtabADT. These details are not relevant to and therefore
|
|
* not exported to the client. In this implementation, the
|
|
* underlying structure is a hash table organized as an array of
|
|
* "buckets," in which each bucket is a linked list of elements
|
|
* that share the same hash code.
|
|
*/
|
|
|
|
struct symtabCDT {
|
|
cellT* buckets[NBuckets];
|
|
};
|
|
|
|
/* Private function declarations */
|
|
|
|
static void FreeBucketChain(cellT* cp);
|
|
static cellT* FindCell(cellT* cp, string s);
|
|
static int Hash(string s, int nBuckets);
|
|
|
|
/* Public entries */
|
|
|
|
symtabADT NewSymbolTable(void)
|
|
{
|
|
symtabADT table;
|
|
int i;
|
|
|
|
table = New(symtabADT);
|
|
for (i = 0; i < NBuckets; i++) {
|
|
table->buckets[i] = NULL;
|
|
}
|
|
return (table);
|
|
}
|
|
|
|
void FreeSymbolTable(symtabADT table)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NBuckets; i++) {
|
|
FreeBucketChain(table->buckets[i]);
|
|
}
|
|
FreeBlock(table);
|
|
}
|
|
|
|
void Enter(symtabADT table, string key, void* value)
|
|
{
|
|
int bucket;
|
|
cellT* cp;
|
|
|
|
bucket = Hash(key, NBuckets);
|
|
cp = FindCell(table->buckets[bucket], key);
|
|
if (cp == NULL) {
|
|
cp = New(cellT*);
|
|
cp->key = CopyString(key);
|
|
cp->link = table->buckets[bucket];
|
|
table->buckets[bucket] = cp;
|
|
}
|
|
cp->value = value;
|
|
}
|
|
|
|
void* Lookup(symtabADT table, string key)
|
|
{
|
|
int bucket;
|
|
cellT* cp;
|
|
|
|
bucket = Hash(key, NBuckets);
|
|
cp = FindCell(table->buckets[bucket], key);
|
|
if (cp == NULL)
|
|
return (UNDEFINED);
|
|
return (cp->value);
|
|
}
|
|
|
|
void MapSymbolTable(symtabFnT fn, symtabADT table,
|
|
void* clientData)
|
|
{
|
|
int i;
|
|
cellT* cp;
|
|
|
|
for (i = 0; i < NBuckets; i++) {
|
|
for (cp = table->buckets[i]; cp != NULL; cp = cp->link) {
|
|
fn(cp->key, cp->value, clientData);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Private functions */
|
|
|
|
/*
|
|
* Function: FreeBucketChain
|
|
* Usage: FreeBucketChain(cp);
|
|
* ---------------------------
|
|
* This function takes a chain pointer and frees all the cells
|
|
* in that chain. Because the package makes copies of the keys,
|
|
* this function must free the string storage as well.
|
|
*/
|
|
|
|
static void FreeBucketChain(cellT* cp)
|
|
{
|
|
cellT* next;
|
|
|
|
while (cp != NULL) {
|
|
next = cp->link;
|
|
FreeBlock(cp->key);
|
|
FreeBlock(cp);
|
|
cp = next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: FindCell
|
|
* Usage: cp = FindCell(cp, key);
|
|
* ------------------------------
|
|
* This function finds a cell in the chain beginning at cp that
|
|
* matches key. If a match is found, a pointer to that cell is
|
|
* returned. If no match is found, the function returns NULL.
|
|
*/
|
|
|
|
static cellT* FindCell(cellT* cp, string key)
|
|
{
|
|
while (cp != NULL && !StringEqual(cp->key, key)) {
|
|
cp = cp->link;
|
|
}
|
|
return (cp);
|
|
}
|
|
|
|
/*
|
|
* Function: Hash
|
|
* Usage: bucket = Hash(key, nBuckets);
|
|
* ------------------------------------
|
|
* This function takes the key and uses it to derive a hash code,
|
|
* which is an integer in the range [0, nBuckets - 1]. The hash
|
|
* code is computed using a method called linear congruence. The
|
|
* choice of the value for Multiplier can have a significant effect
|
|
* on the performance of the algorithm, but not on its correctness.
|
|
*/
|
|
|
|
#define Multiplier -1664117991L
|
|
|
|
static int Hash(string s, int nBuckets)
|
|
{
|
|
int i;
|
|
unsigned long hashcode;
|
|
|
|
hashcode = 0;
|
|
for (i = 0; s[i] != '\0'; i++) {
|
|
hashcode = hashcode * Multiplier + s[i];
|
|
}
|
|
return (hashcode % nBuckets);
|
|
}
|