home *** CD-ROM | disk | FTP | other *** search
- /* stb.c - symbol table functions */
-
- /* By Eamonn McManus <em@dce.ie>. This file is not copyrighted.
- * $Id: stb.c,v 1.2 90/09/11 23:37:49 em Exp $
- *
- * Functions using a simple binary forest to implement symbol table
- * operations. Should be recompiled with DATUM defined on the command
- * line as a declaration for variable datum of suitable type. Default
- * is equivalent to -DDATUM="char *datum".
- */
-
- #ifndef DATUM
- #define DATUM char *datum
- #endif
-
- typedef DATUM;
-
- #include "stb.h"
- #ifdef __STDC__
- #include <string.h> /* For strcpy(). */
- #include <stdlib.h>
- #else
- extern char *malloc();
- extern char *strcpy();
- extern void free();
- #endif
-
- #ifndef NULL
- # define NULL 0
- #endif
-
-
- /* Return a new symbol table. NULL if can't make one. */
- stb *stb_new_table()
- {
- /* Note that calloc() to get an array of NULLs is not portable. */
- register int i;
- register stb *s = (stb *) malloc(sizeof(stb));
- for (i = 0; i < MAXCHAR; i++)
- (*s)[i] = NULL;
- return s;
- }
-
-
- /* Free tree rooted at root, using function datumfree. */
- static int free_tree(root, datumfree)
- register stb_node *root;
- register int (*datumfree)();
- {
- register stb_node *n;
- for ( ; root != NULL; root = n) {
- if (free_tree(root->link[0], datumfree) < 0)
- return -1;
- n = root->link[1];
- if ((*datumfree)(root->datum) < 0)
- return -1;
- free((char *) root->name);
- free((char *) root);
- }
- return 0;
- }
-
-
- /* Free a symbol table. Return 0 if OK, -1 if error. Datumfree is a
- * routine to free the datum in each node, returning the same error status.
- */
- int stb_free_table(table, datumfree)
- register stb *table;
- register int (*datumfree)();
- {
- register int i;
- for (i = 0; i < MAXCHAR; i++)
- if (free_tree((*table)[i], datumfree) < 0)
- return -1;
- free((char *) table);
- return 0;
- }
-
-
- /* Look up a symbol. Return pointer to its node or NULL if not found. */
- stb_node *stb_lookup(table, name)
- stb *table;
- register char *name;
- {
- register stb_node *n;
- register int order;
- if (name[0] == '\0')
- return (*table)['\0']; /* Only one null symbol. */
- if ((unsigned char) name[0] >= MAXCHAR)
- return NULL; /* Invalid. */
- for (n = (*table)[(unsigned char) *name++]; n; n = n->link[order > 0])
- if ((order = strcmp(name, n->name + 1)) == 0)
- return n;
- return NULL;
- }
-
-
- /* Insert a symbol. Returns the inserted node, or NULL if there was an
- * error or the symbol was already present.
- */
- stb_node *stb_insert(table, name, newdatum)
- stb *table;
- register char *name;
- datum *newdatum;
- {
- register stb_node *parent, *n, **link;
- register int order;
- register char *namecpy;
- if ((unsigned char) *name >= MAXCHAR)
- return NULL; /* Invalid. */
- parent = NULL;
- link = *table + (unsigned char) name[0];
- n = *link;
- if (*name++) { /* Only one null symbol, no search. */
- while (n != NULL) {
- if ((order = strcmp(name, n->name + 1)) == 0)
- break;
- link = &n->link[order > 0];
- parent = n; n = *link;
- }
- }
- if (n != NULL)
- return NULL; /* Already present. */
- if ((namecpy = malloc((unsigned) strlen(--name) + 1)) == NULL)
- return NULL; /* Out of memory. */
- (void) strcpy(namecpy, name);
- if ((n = (stb_node *) malloc(sizeof(stb_node))) == NULL)
- return NULL;
- n->link[0] = n->link[1] = NULL;
- n->parent = parent; n->name = namecpy; n->datum = *newdatum;
- *link = n;
- return n;
- }
-
-
- /* Subsequent functions are not used in the rnprejudice code. */
- #ifdef UNPREJUDICED
-
- /* Return lowest valued descendant of node. */
- static stb_node *first(node)
- register stb_node *node;
- {
- while (node->link[0] != NULL)
- node = node->link[0];
- return node;
- }
-
-
- /* Return first symbol in table, NULL if table is empty. */
- stb_node *stb_first(table)
- register stb *table;
- {
- register int i;
- for (i = 0; i < MAXCHAR; i++)
- if ((*table)[i] != NULL)
- return first((*table)[i]);
- return NULL;
- }
-
-
- /* Return the next symbol after the given node, NULL if none. */
- stb_node *stb_next(table, node)
- stb *table;
- register stb_node *node;
- {
- register int i;
- /* If there is a right pointer, return its smallest descendant.
- * If this is the left descendant of a node, return that node.
- * Otherwise, we want that node's next.
- */
- if (node->link[1] != NULL)
- return first(node->link[1]);
- for ( ; node->parent != NULL; node = node->parent)
- if (node->parent->link[0] == node)
- return node->parent;
- /* At root for this initial char. Find next tree. */
- for (i = node->name[0] + 1; i < MAXCHAR; i++)
- if ((*table)[i])
- return first((*table)[i]);
- return NULL;
- }
-
-
- /* Delete a node. Return 0 if OK, else -1. Datumfree is a function to
- * free the datum part of the node, returning the same kind of status.
- */
- int stb_delete(table, node, datumfree)
- stb *table;
- register stb_node *node;
- int (*datumfree)();
- {
- register stb_node **link, *succ;
- /* Find the link from the parent that we want to change. */
- if (node->parent == NULL)
- link = *table + node->name[0]; /* In the array of roots. */
- else link = &node->parent->link[node->parent->link[1] == node];
- /* If either descendant is NULL, replace with the other. Otherwise
- * find the successor and replace with that.
- */
- if (node->link[0] == NULL)
- *link = node->link[1];
- else if (node->link[1] == NULL)
- *link = node->link[0];
- else {
- succ = first(node->link[1]);
- /* Replace the deleted node with its successor, succ. Succ
- * has no left child (since that would be the successor), so
- * it inherits the original node's left child.
- * If succ is the right child of the original node, that is
- * enough. Otherwise, succ's parent
- * inherits succ's right child as its left child (which was
- * succ), and succ inherits the original node's right child.
- */
- succ->link[0] = node->link[0]; node->link[0]->parent = succ;
- if (succ->parent != node) {
- succ->parent->link[0] = succ->link[1];
- if (succ->link[1] != NULL)
- succ->link[1]->parent = succ->parent;
- succ->link[1] = node->link[1];
- node->link[1]->parent = succ;
- }
- *link = succ;
- }
- if (*link != NULL)
- (*link)->parent = node->parent;
- if ((*datumfree)(node->datum) < 0)
- return -1;
- free((char *)node->name); free((char *)node);
- return 0;
- }
-
- #endif /* UNPREJUDICED */
-