/* Symbol table support
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
James Bowman
This file is part of gputils.
gputils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
gputils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with gputils; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "stdhdr.h"
#include "libgputils.h"
/* Base the hash func on the 1st, 2nd, 3rd and last characters of the
string, and its length. */
static int hashfunc(struct symbol_table *t, char *s)
{
union {
char b[4];
unsigned long ul;
} change;
int len;
change.ul = 0;
len = strlen(s);
change.b[0] = s[0];
if (len > 1) {
change.b[1] = s[1];
change.b[3] = s[len - 1];
if (len > 2)
change.b[2] = s[2];
}
if (t->case_insensitive) {
change.ul &= 0x1f1f1f1f;
}
change.ul += (len << 3);
return (change.ul % HASH_SIZE);
}
struct symbol_table *push_symbol_table(struct symbol_table * table,
gp_boolean case_insensitive)
{
struct symbol_table *new = calloc(sizeof(*new), 1);
new->case_insensitive = case_insensitive;
if (case_insensitive)
new->compare = strcasecmp;
else
new->compare = strcmp;
new->prev = table;
return new;
}
struct symbol_table *pop_symbol_table(struct symbol_table *table)
{
struct symbol_table *prev;
prev = table->prev;
return prev;
}
struct symbol *add_symbol(struct symbol_table *table, char *name)
{
struct symbol *r;
int index;
assert(name != NULL);
assert(table != NULL);
index = hashfunc(table, name);
r = table->hash_table[index];
while (r && ((*table->compare)(name, r->name) != 0))
r = r->next;
if (!r) { /* No match */
r = malloc(sizeof(*r));
r->name = strdup(name);
r->next = table->hash_table[index];
r->annotation = NULL;
table->hash_table[index] = r;
table->count++;
}
return r;
}
/* FIXME: remove_symbol does not search all of the symbol tables in the stack.
Maybe this is ok, but it seems wrong. */
int remove_symbol(struct symbol_table *table, char *name)
{
struct symbol *r = NULL;
struct symbol *last = NULL;
int index;
int found_symbol = 0;
assert(name != NULL);
assert(table != NULL);
index = hashfunc(table, name);
/* Search for the symbol */
if (table != NULL) {
r = table->hash_table[index];
while (r && ((*table->compare)(name, r->name) != 0)) {
last = r;
r = r->next;
}
}
if (r != NULL) {
/* remove the symbol */
if (last) {
last->next = r->next;
} else {
/* r was first in the list */
table->hash_table[index] = r->next;
}
table->count--;
found_symbol = 1;
free(r);
}
return found_symbol;
}
struct symbol *get_symbol(struct symbol_table *table, char *name)
{
struct symbol *r = NULL;
assert(name != NULL);
if (table != NULL) {
int index = hashfunc(table, name);
r = table->hash_table[index];
while (r && ((*table->compare)(name, r->name) != 0))
r = r->next;
/* If r is still NULL, we didn't match. Try the prev table on the stack */
if (r == NULL)
r = get_symbol(table->prev, name);
}
return r;
}
void annotate_symbol(struct symbol *s, void *a)
{
s->annotation = a;
}
char *get_symbol_name(struct symbol *s)
{
return s->name;
}
void *get_symbol_annotation(struct symbol *s)
{
return s->annotation;
}
int symbol_compare(const void *p0, const void *p1)
{
struct symbol
*s0 = *(struct symbol **)p0,
*s1 = *(struct symbol **)p1;
return strcmp(s0->name, s1->name);
}
syntax highlighted by Code2HTML, v. 0.9.1