/*
    mmorph, MULTEXT morphology tool
    Version 2.3, October 1995
    Copyright (c) 1994,1995 ISSCO/SUISSETRA, Geneva, Switzerland
    Dominique Petitpierre, <petitp@divsun.unige.ch>
*/
/*

procedures to handle symbol tables

there are Types with associated Attributes

there are Attributes with associated Values

there are rules with associated rule description


*/
#include <search.h>
#include "user.h"


/*
  declarations to shutup "gcc -traditional -Wall", and lint
  on SunOS 4.1.3
 */
#ifdef UNDEF
#ifndef STDC_HEADERS
extern char *tsearch();
extern char *tfind();
extern void twalk();

#endif
#endif

s_symbol_set symbol_set[SYM_TABLES_NUMBER];	/* independant symbols */

/* symbol kind names (should follow the order of e_symbol_kind enumeration) */
t_str       symbol_kind_str[_last_symbol_kind + 1] = {
    "attribute",
    "pair",
    "rule",
    "spelling",
    "type",
    "value",
    "variable",
    "surface symbol",
    "lexical symbol",
    "lexical or surface symbol",
    "surface symbol class",
    "lexical symbol class",
    "lexical or surface symbol class",
    "lexical entry",
    "alphabet",
    ""
};

/* rule kind names (should follow the order of e_rule_kind enumeration) */
static t_str rule_kind_str[_last_rule_kind + 1] = {
    "goal",
    "lexical",
    "unary",
    "binary",
    "prefix",
    "suffix",
/*
    "compound",
    "composite_prefix",
    "composite_suffix",
*/
    ""
};


void
init_symbol_set(symbol_set, symbol_kind)
s_symbol_set *symbol_set;
e_symbol_kind symbol_kind;

{
    symbol_set->kind = symbol_kind;
    symbol_set->card = 0;
    symbol_set->table = NULL;
    symbol_set->ref = NULL;
}

void
init_symbol()
{
    e_symbol_kind kind;

    for (kind = FIRST_SYM_KIND; kind < SYM_TABLES_NUMBER; kind++) {
	init_symbol_set(&symbol_set[kind], kind);
    }
}

static int
#if defined(__STDC__)
sym_compare(const T_PTR sym1, const T_PTR sym2)
#else
sym_compare(sym1, sym2)
T_PTR       sym1;
T_PTR       sym2;

#endif
{
    return (strcmp(((s_symbol *) sym1)->name, ((s_symbol *) sym2)->name));
}

#ifdef COMMENTED_OUT
/* TODO recurse through all pointers */
void
free_symbol(sym)
s_symbol   *sym;

{
    if (sym != NULL) {
	if (sym->data != NULL)
	    MY_FREE(sym->data);
	if (sym->name != NULL)
	    MY_FREE(sym->name);
	MY_FREE(sym);
    }
}

#endif	/* COMMENTED_OUT */

int
reference_position(reference, item)
t_ptr      *reference;
t_ptr       item;

{
    t_ptr      *ref;

    /* example: search for this attribute in the list associated to type */
    /* TODO: sort attributes first */
    ref = reference;
    while ((*ref != NULL) && (*ref != item))
	ref++;
    if (*ref == NULL)
	return (-1);	/* not found */
    else
	return (ref - reference);	/* return position */
}

t_ptr      *current_ref = NULL;	/* argument passed to action() */

/* one kind of action */
void
ref_is_item(item)
t_ptr       item;

{
    *current_ref = item;
    current_ref++;
}

t_ptr      *
new_ref(card, fill_reference, source, action)
int         card;
void        (*fill_reference) ();
t_ptr       source;
void        (*action) ();

{
    t_ptr      *ref;

    MY_CALLOC(ref, card + 1, t_ptr);
    ref[card] = (t_ptr) NULL;	/* sentinel */
    if (card > 0) {
	current_ref = ref;
	fill_reference(source, action);
    }
    return (ref);
}


/* extra argument passed to assign_reference */
static s_symbol_set *current_set;

/* Assign the reference pointer */
/*ARGSUSED2*/
static void
#if defined(__STDC__)
assign_reference(const T_PTR sym, VISIT order, int level)
#else
assign_reference(sym, order, level)
T_PTR       sym;
VISIT       order;
int         level;

#endif
{

    if (order == postorder || order == leaf)
	if (sym != NULL)
	    if (*((s_symbol **) sym) != NULL) {
		current_set->ref[(*((s_symbol **) sym))->ordinal]
		    = *((s_symbol **) sym);
	    }
}

void
make_symbol_reference(set)
s_symbol_set *set;

{
    MY_CALLOC(set->ref, set->card + 1, s_symbol *);
    set->ref[set->card] = NULL;
    current_set = set;
    twalk((T_PTR) set->table, assign_reference);
}

void
link_attribute(value_set, attribute_symbol)
s_symbol_set *value_set;
s_symbol   *attribute_symbol;

{
    t_index     n;

    for (n = 0; n < value_set->card; n++) {
	value_set->ref[n]->data->value.attribute_link = attribute_symbol;
    }
}

s_tfs      *
new_tfs(type)
t_index     type;

{
    s_tfs      *tfs;
    t_index     type_card;

    MY_MALLOC(tfs, s_tfs);
    tfs->type = type;
    type_card = symbol_set[Type].ref[type]->data->type.card;
    MY_CALLOC(tfs->att_list, type_card + 1, t_value);
    tfs->att_list[type_card] = NO_BITS;	/* sentinel */
    tfs->var_map = NULL;
    return (tfs);
}

static void
free_var_map(var_map)
s_var_map **var_map;

{
    s_var_map **v;

    if (var_map != NULL) {
	for (v = var_map; *v != NULL; v++)
	    MY_FREE(*v);
	MY_FREE(var_map);
    }
}

void
free_tfs(tfs)
s_tfs      *tfs;

{
    if (tfs != NULL) {
	MY_FREE(tfs->att_list);
	MY_FREE(tfs);
	/* use real_free if tfs->var_map needs to be freed */
    }
}

#ifdef COMMENTED_OUT
void
real_free_tfs(tfs)
s_tfs      *tfs;

{
    if (tfs != NULL) {
	MY_FREE(tfs->att_list);
	MY_FREE(tfs);
	MY_FREE(tfs->var_map);
    }
}

#endif	/* COMMENTED_OUT */

void
fill_tfs_with_variables(tfs)
s_tfs      *tfs;

{
    s_type     *type;
    s_symbol  **attribute_ref;
    t_value    *att_list;
    t_value    *last_att;

    type = &(symbol_set[Type].ref[tfs->type]->data->type);
    attribute_ref = type->attribute_ref;
    att_list = tfs->att_list;
    last_att = att_list + type->card;
    /* fill the type feature structure with full value sets */
    while (att_list < last_att)
	*att_list++ =
	    FULL_SET((*attribute_ref++)->data->attribute.value_set.card);
}

static void
fill_var_index(variable_ref, tfs, member)
s_symbol  **variable_ref;
s_tfs      *tfs;
int         member;

{
    s_var_map **var_map;

    if (tfs != NULL)
	if (tfs->var_map != NULL)
	    for (var_map = tfs->var_map; *var_map != NULL; var_map++)
		variable_ref[(*var_map)->foreign_index]->data->variable.tfs_index[member] =
		    (*var_map)->local_index;
}

static void
direct_var_map(variable_ref, tfs, member)
s_symbol  **variable_ref;
s_tfs      *tfs;
int         member;

{
    s_var_map **var_map;

    if (tfs->var_map != NULL)
	for (var_map = tfs->var_map; *var_map != NULL; var_map++)
	    (*var_map)->foreign_index =
		variable_ref[(*var_map)->foreign_index]
		->data->variable.tfs_index[member];
}

static void
check_var_map(variable_ref, rule)
s_symbol  **variable_ref;
s_rule_instance *rule;

{
    s_symbol  **ref;
    t_index    *tfs_index;
    t_value    *att_list[3];
    t_boolean   lonely_var;
    t_boolean   fully_specified;
    int         i;
    int         j;
    int         loop_bound;
    t_value     value;

    att_list[0] = rule->lhs->att_list;
    att_list[1] = rule->first->att_list;
    if (rule->rule_kind == Binary) {
	att_list[2] = rule->second->att_list;
	loop_bound = 3;
    }
    else
	/* Prefix and Suffix rules don't have variables in second */
	loop_bound = 2;	/* 1 would not check lonely var in first */
    for (ref = variable_ref; *ref != NULL; ref++) {
	tfs_index = (*ref)->data->variable.tfs_index;
	lonely_var = TRUE;
	fully_specified = FALSE;
	/* unify circularly the values associated to variables */
	for (i = 0, j = 1; i < loop_bound; i++, j = (j + 1) % loop_bound) {
	    if (tfs_index[i] != NO_INDEX && tfs_index[j] != NO_INDEX) {
		lonely_var = FALSE;
		value = (att_list[i][tfs_index[i]]
			 &= att_list[j][tfs_index[j]]);
		if (value == NO_BITS)
		    fatal_error("variable $%s in rule \"%s\" %s",
				(*ref)->name,
				rule->rule_link->name,
				"is inconsistent with itself");
		att_list[j][tfs_index[j]] = value;	/* identify */
		/*
		   TODO: if the variable is assigned remove it from the
		   var_map. Currently dealt with by a user warning.
		*/
		if (has_unique_bit(value))
		    fully_specified = TRUE;
	    }
	}
	if (lonely_var)
	    fatal_error("variable $%s in rule \"%s\" %s",
			(*ref)->name,
			rule->rule_link->name,
			"has no correspondant");
	if (fully_specified)
	    print_warning("variable $%s in rule \"%s\" %s",
			  (*ref)->name,
			  rule->rule_link->name,
			  "is already fully specified");
    }
}

void
adjust_var_map(variable_ref, rule)
s_symbol  **variable_ref;
s_rule_instance *rule;

{

    fill_var_index(variable_ref, rule->lhs, 0);	/* TODO check necessity */
    fill_var_index(variable_ref, rule->first, 1);
    /* Prefix and Suffix rules are handled like Unary rules */
    if (rule->rule_kind == Binary)
	fill_var_index(variable_ref, rule->second, 2);
    check_var_map(variable_ref, rule);
    if (rule->rule_kind != Binary) {
	/*
	   only one var map is needed. (First->var_map...foreign by
	   convention should point to second->att_list)
	*/
	direct_var_map(variable_ref, rule->lhs, 1);
	free_var_map(rule->first->var_map);
	rule->first->var_map = NULL;
    }


    /* binary rules will be taken care of in combine_rule() */
}

void
ident_var_map(tfs)
s_tfs      *tfs;

{
    s_var_map  *v;
    int         n;
    t_index     type_card;

    type_card = symbol_set[Type].ref[tfs->type]->data->type.card;
    MY_CALLOC(v, type_card, s_var_map);
    MY_CALLOC(tfs->var_map, type_card + 1, s_var_map *);
    for (n = 0; n < type_card; n++) {
	v[n].local_index = n;
	v[n].foreign_index = n;
	tfs->var_map[n] = &v[n];
    }
    tfs->var_map[type_card] = NULL;	/* sentinel */
}

/* TODO: merge tfind and tsearch steps to avoid searching twice */
s_symbol  **
new_symbol(name, set)
t_str       name;
s_symbol_set *set;

{
    s_symbol    sym;
    s_symbol   *new_sym;
    s_symbol  **found_sym;
    t_letter   *letter_string;

    if (set->table == NULL)
	found_sym = NULL;
    else {
	sym.name = name;
	found_sym = (s_symbol **) tfind((T_PTR) & sym, (T_PTR *) & (set->table),
					sym_compare);
    }
    if (found_sym != NULL) {
	switch (set->kind) {
	    case Surface_Letter:
		/* surface and lexical alphabet share the set with pairs */
		if ((*found_sym)->kind == Lexical_Letter) {
		    (*found_sym)->kind = Pair_Letter;
		    (*found_sym)->data->pair.surface =
			(*found_sym)->data->pair.lexical;
		    break;
		}	/* else Surface_Letter or Pair_Letter: error */
		/* FALLTHROUGH */
	    case Lexical_Letter:	/* first one */
		/* FALLTHROUGH */
	    case Pair_Class:
		/* FALLTHROUGH */
	    case Attribute:
		/* FALLTHROUGH */
	    case Type:
		/* FALLTHROUGH */
	    case Rule:
		/* FALLTHROUGH */
	    case Pair:
		/* FALLTHROUGH */
	    case Spelling:
		/* FALLTHROUGH */
	    case Value:	/* declared twice */
		fatal_error("%s identifier \"%s\" is already defined",
			    symbol_kind_str[set->kind], name);
		break;
	    case Variable:	/* TODO: update map */
		break;
	    default:
		break;
	}
	/* 17/01/96 Jordi <porta@crea.rae.es>
	   It's not possible to free now and use it after. 
	   No pueden liberar y despues utilizar.
	   MY_FREE(name); 
	*/
    }
    else {
	/* TODO: put most of this into a new_symbol() */
	MY_MALLOC(new_sym, s_symbol);
	new_sym->kind = set->kind;
	new_sym->name = name;
	new_sym->ordinal = set->card++;
	found_sym = (s_symbol **) tsearch((T_PTR) new_sym,
					  (T_PTR *) & (set->table),
					  sym_compare);
	switch (set->kind) {
	    case Surface_Letter:
		/* FALLTHROUGH */
	    case Lexical_Letter:
		if (new_sym->ordinal >= (t_card) LETTER_MAX)
		    fatal_error("symbol %s: %s (maximum=%d)",
				new_sym->name,
				"too many different alphabet symbols",
				LETTER_MAX - 3);	/* NUL, ANY, 2
							   BOUNDARIES */
		MY_MALLOC(new_sym->data, s_pair);
		MY_STRALLOC(letter_string, 2);
		letter_string[0] = (t_letter) new_sym->ordinal;
		letter_string[1] = NUL_LETTER;
		new_sym->data->pair.pair_flags = BOTH_LETTERS;
		if (set->kind == Surface_Letter) {
		    new_sym->data->pair.surface = letter_string;
		    new_sym->data->pair.lexical = NULL;
		    new_sym->data->pair.next = NULL;	/* list empty */
		}
		else {
		    new_sym->data->pair.surface = NULL;
		    new_sym->data->pair.lexical = letter_string;
		    new_sym->data->pair.next = NULL;	/* list empty */
		}
		break;
	    case Pair_Class:
		MY_MALLOC(new_sym->data, s_class);
		new_sym->data->class.pair_flags = BOTH_CLASSES;
		new_sym->data->class.surface
		    = new_bitmap((long) alphabet_size);
		new_sym->data->class.lexical = NULL;
		new_sym->data->class.next = NULL;	/* list empty */
		break;
	    case Pair:
		MY_MALLOC(new_sym->data, s_pair);
		new_sym->data->pair.surface = NULL;
		new_sym->data->pair.lexical = NULL;
		new_sym->data->pair.next = NULL;	/* list empty */
		break;
	    case Attribute:
		MY_MALLOC(new_sym->data, s_attribute);
		init_symbol_set(&(new_sym->data->attribute.value_set), Value);
		break;
	    case Rule:
		MY_MALLOC(new_sym->data, s_rule);
		init_symbol_set(&(new_sym->data->rule.variable_set),
				Variable);
		MY_MALLOC(new_sym->data->rule.instance, s_rule_instance);
		new_sym->data->rule.instance->lhs = NULL;
		new_sym->data->rule.instance->first = NULL;
		new_sym->data->rule.instance->second = NULL;
		new_sym->data->rule.instance->lex = NULL;
		new_sym->data->rule.instance->rule_link = new_sym;
		break;
	    case Spelling:
		MY_MALLOC(new_sym->data, s_spelling);
		MY_MALLOC(new_sym->data->spelling.instance, s_spell_instance);

/*
		init_symbol_set(&(new_sym->data->rule.variable_set),
				Variable);
*/
		break;
	    case Type:
		MY_MALLOC(new_sym->data, s_type);
		new_sym->data->type.card = 0;
		new_sym->data->type.project_card = 0;
		new_sym->data->type.attribute_ref = NULL;
		break;
	    case Value:
		if (new_sym->ordinal >= MAXVAL) {
		    fatal_error("%s (max=%d, at value \"%s\")",
			      "too many values declared for this attribute",
				MAXVAL, new_sym->name);
		}
		MY_MALLOC(new_sym->data, s_value);
		break;
	    case Variable:
		MY_MALLOC(new_sym->data, s_variable);
		new_sym->data->variable.attribute_link = (s_symbol *) NULL;
		new_sym->data->variable.tfs_index[0] = NO_INDEX;
		new_sym->data->variable.tfs_index[1] = NO_INDEX;
		new_sym->data->variable.tfs_index[2] = NO_INDEX;
		break;
	    default:
		break;
	}
    }
    return (found_sym);
}

s_symbol  **
find_symbol(name, set)
t_str       name;
s_symbol_set *set;

{
    s_symbol    sym;
    s_symbol  **found_sym;


    sym.name = name;
    found_sym = (s_symbol **) tfind((T_PTR) & sym,
				    (T_PTR *) & (set->table), sym_compare);
    if (found_sym == NULL)
	fatal_error("%s identifier \"%s\" is not defined",
		    symbol_kind_str[set->kind], name);
    MY_FREE(name);
    return (found_sym);
}

static      t_boolean
print_value(file, attribute, value, record_field_mode)
FILE       *file;
s_symbol   *attribute;
t_value     value;
t_boolean   record_field_mode;

{
    s_symbol_set *value_set;
    char       *format;
    int         n;
    t_boolean   first;

    value_set = &attribute->data->attribute.value_set;
    if (value_set->card > 1 && FULL_SET(value_set->card) == value)
	return (FALSE);	/* don't print variables */
    else {
	print(file, "%s=", attribute->name);
	first = TRUE;
	if (record_field_mode)
	    format = "!%s";
	else
	    format = "|%s";
	for (n = 0; n < value_set->card; n++)
	    if (TEST_BIT(value, n)) {
		if (first) {
		    print(file, "%s", value_set->ref[n]->name);
		    first = FALSE;
		}
		else
		    print(file, format, value_set->ref[n]->name);
	    }
	return (TRUE);
    }
}


void
print_tfs1(file, tfs, print_var_map, print_projection, record_field_mode)
FILE       *file;
s_tfs      *tfs;
t_boolean   print_var_map;
t_boolean   print_projection;
t_boolean   record_field_mode;

{
    int         i;
    s_symbol   *symbol;
    s_symbol  **attribute_ref;
    t_index     type_card;

    if (tfs != NULL) {
	symbol = symbol_set[Type].ref[tfs->type];
	attribute_ref = symbol->data->type.attribute_ref;
	if (print_projection)
	    type_card = symbol->data->type.project_card;
	else
	    type_card = symbol->data->type.card;
	print(file, "%s[ ", symbol->name);
	for (i = 0; i < type_card; i++) {
	    if (print_value(file, attribute_ref[i], tfs->att_list[i],
			    record_field_mode))
		print(file, " ");
	}
	if (record_field_mode)
	    print(file, "]");
	else
	    print(file, "]\n");
	if (tfs->var_map != NULL && print_var_map) {
	    for (i = 0; tfs->var_map[i] != NULL; i++)
		print(file, "map att %s = %d\n",
		      attribute_ref[tfs->var_map[i]->local_index]->name,
		      tfs->var_map[i]->foreign_index);
	}
    }
}

void
print_tfs(tfs)
s_tfs      *tfs;

{
    print_tfs1(logfile, tfs, FALSE, FALSE, FALSE);
}

void
print_tfs_proj(tfs)
s_tfs      *tfs;

{
    print_tfs1(outfile, tfs, FALSE, TRUE, FALSE);
}

void
print_tfs_proj_tbl(tfs)
s_tfs      *tfs;

{
    print_tfs1(outfile, tfs, FALSE, TRUE, TRUE);
}


static void
print_labeled_tfs(tfs, label)
s_tfs      *tfs;
t_str       label;

{
    if (tfs != NULL) {
	print_log("%s", label);
	print_tfs1(logfile, tfs, TRUE, FALSE, FALSE);
    }
}


static void
print_class(class)
s_bitmap   *class;

{
    long        letter_index;

    print_log("{");
    FOR_EACH_BIT(class, letter_index)
	print_log(" %s", symbol_set[Pair].ref[letter_index]->name);
    print_log(" }");
}

static void
print_symbol_string(letter_string)
t_letter   *letter_string;
{
    if (letter_string == letter_any)
	print_log("?");
    else if (strlen((char *) letter_string) == 1)
	print_log("%s", symbol_set[Pair].ref[*letter_string]->name);
    else {	/* TODO print angle brackets */
	print_log("\"");
	print_string(logfile, letter_string);
	print_log("\"");
    }
}

static void
print_pair(pair)
s_pair     *pair;

{

    do {
	print_log(" ");
	if (pair->pair_flags & SURFACE_IS_CLASS)
	    print_class((s_bitmap *) pair->surface);
	else
	    print_symbol_string(pair->surface);
	print_log("/");
	if (pair->pair_flags & LEXICAL_IS_CLASS)
	    print_class((s_bitmap *) pair->lexical);
	else
	    print_symbol_string(pair->lexical);
	pair = pair->next;
    } while (pair != NULL);
    print_log("\n");
}

static void
print_spell(spell)
s_spell_instance *spell;

{
    if (spell->kind == Optional)
	print_log("=>\n");
    else if (spell->kind == Coerce)
	print_log("<=\n");
    else
	print_log("<=>\n");
    /* TO DO print reverse left context */
    map_chain(spell->left_context, print_pair);
    print_log("-");
    map_chain(spell->focus, print_pair);
    print_log("-");
    map_chain(spell->right_context, print_pair);
    map_chain(spell->constraint, print_tfs);
    print_log("concatenation point: %d\n", spell->concat_pos);
}

void
print_symbols_by_ref(set)
s_symbol_set *set;

{
    t_index     n;
    s_symbol   *sym;

    if (set == NULL)
	return;
    for (n = 0; n < set->card; n++) {
	sym = set->ref[n];
	print_log("\n%s %d\t%s\n",
		  symbol_kind_str[sym->kind],
		  sym->ordinal,
		  sym->name);
	switch (sym->kind) {
	    case Attribute:
		print_symbols_by_ref(&sym->data->attribute.value_set);
		break;
	    case Rule:
		print_log("rule kind %s\n",
			rule_kind_str[sym->data->rule.instance->rule_kind]);
		if (sym->data->rule.instance->lex != NULL) {
		    print_log("lex string ");
		    print_string(logfile, sym->data->rule.instance->lex);
		    print_log("\n");
		}
		print_symbols_by_ref(&sym->data->rule.variable_set);
		print_labeled_tfs(sym->data->rule.instance->lhs, "lhs: ");
		print_labeled_tfs(sym->data->rule.instance->first, "first: ");
		print_labeled_tfs(sym->data->rule.instance->second,
				  "second: ");
		break;
	    case Spelling:
		print_spell((s_spell_instance *) sym->data->spelling.instance);
/*
		print_symbols_by_ref(&sym->data->spelling.variable_set);
*/
		break;
	    case Type:
		{
		    s_symbol  **psym;

		    for (psym = sym->data->type.attribute_ref;
			 *psym != NULL; psym++)
			print_log("with attribute\t%s\n",
				  (*psym)->name);
		}
		break;
	    case Value:
		print_log("of attribute\t%s\n",
			  sym->data->value.attribute_link->name);
		break;
	    case Pair:
		/* FALLTHROUGH */
	    case Surface_Letter:
		/* FALLTHROUGH */
	    case Lexical_Letter:
		/* FALLTHROUGH */
	    case Pair_Letter:
		/* FALLTHROUGH */
	    case Surface_Class:
		/* FALLTHROUGH */
	    case Lexical_Class:
		/* FALLTHROUGH */
	    case Pair_Class:
		/* FALLTHROUGH */
	    default:
		break;
	}
    }
}


/* Print out symbols in alphabetical order */
/*ARGSUSED2*/
static void
#if defined(__STDC__)
print_sym(const T_PTR symptr, VISIT order, int level)
#else
print_sym(symptr, order, level)
T_PTR       symptr;
VISIT       order;
int         level;

#endif
{
    s_symbol   *sym;

    if (!(order == postorder || order == leaf) || symptr == NULL)
	return;
    sym = *((s_symbol **) symptr);
    if (sym == NULL)
	return;
    switch (sym->kind) {
	case Surface_Class:
	    /* FALLTHROUGH */
	case Lexical_Class:
	    /* FALLTHROUGH */
	case Pair_Class:
	    if (defined_kind == Pair_Class) {
		print_log("\n%s %d\t%s\n",
			  symbol_kind_str[sym->kind],
			  sym->ordinal,
			  sym->name);
		if (sym->kind == Surface_Class)
		    print_class(sym->data->class.surface);
		else
		    print_class(sym->data->class.lexical);
		print_log("\n");
	    }
	    break;
	case Pair:
	    if (defined_kind == Pair) {
		print_log("\n%s %d\t%s\n",
			  symbol_kind_str[sym->kind],
			  sym->ordinal,
			  sym->name);
		print_pair((s_pair *) sym->data);
	    }
	    break;
	default:
	    break;
    }
}


/* used to print tables that don't have an associated reference array */
void
print_symbol_table(symbol_set)
s_symbol_set *symbol_set;

{

    twalk((T_PTR) symbol_set->table, print_sym);
}
