git @ Cat's Eye Technologies Bhuna / master src / lib / symbol.c
master

Tree @master (Download .tar.gz)

symbol.c @masterraw · history · blame

/*
 * symbol.c
 * Symbol and symbol table housekeeping and manipulation for Bhuna.
 * $Id: symbol.c 54 2004-04-23 22:51:09Z catseye $
 */

#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

#include "mem.h"
#include "symbol.h"
#include "type.h"
#include "value.h"
#include "utf8.h"

/*** GLOBALS ***/

static int anon_counter = 0;

/*** STATICS ***/

static struct symbol *
symbol_new(wchar_t *token, int kind)
{
	struct symbol *sym;

	sym = bhuna_malloc(sizeof(struct symbol));

	if (token == NULL) {
		sym->token = bhuna_malloc(sizeof(wchar_t) * 4);
		sym->token[0] = L'%';
		sym->token[1] = (wchar_t)++anon_counter;
		sym->token[2] = L'\0';
	} else {
		sym->token = bhuna_wcsdup(token);
	}

	sym->kind = kind;
	sym->in = NULL;
	sym->index = -1;
	sym->is_pure = 0;
	sym->is_const = 0;
	sym->type = NULL;
	/*sym->value = NULL;*/
	sym->builtin = NULL;

	return(sym);
}

static void
symbol_free(struct symbol *sym)
{
	/* attached types and values take care of themselves now... */
	bhuna_free(sym->token);
	bhuna_free(sym);
}

/*** CONSTRUCTOR/DESTRUCTOR ***/

/*
 * Offset is how many levels deeper this symbol table should be from
 * its parent.  Generally, closures use 1, anonymous blocks (like if
 * and while) use 0 (same level.)
 */
struct symbol_table *
symbol_table_new(struct symbol_table *parent, int offset)
{
	struct symbol_table *stab;

	stab = bhuna_malloc(sizeof(struct symbol_table));

	stab->head = NULL;
	stab->next_index = 0;

	stab->parent = parent;
	if (parent != NULL)
		stab->level = stab->parent->level + offset;
	else
		stab->level = 0;

	return(stab);
}

void
symbol_table_free(struct symbol_table *stab)
{
	struct symbol *s, *t;

	s = stab->head;
	while (s != NULL) {
		t = s->next;
		symbol_free(s);
		s = t;
	}

	bhuna_free(stab);
}

struct symbol_table *
symbol_table_root(struct symbol_table *stab)
{
	if (stab->parent == NULL)
		return(stab);
	else
		return(symbol_table_root(stab->parent));
}

int
symbol_table_size(struct symbol_table *stab)
{
	return(stab->next_index);
}

/*** OPERATIONS ***/

/*
 * Define a new symbol.
 * Assumption: a preceding call to symbol_lookup failed.
 * If token == NULL, a new anonymous symbol is created.
 */
struct symbol *
symbol_define(struct symbol_table *stab, wchar_t *token, int kind, struct value *v)
{
	struct symbol *new_sym;

	new_sym = symbol_new(token, kind);

	new_sym->in = stab;
	if (v != NULL) {
		new_sym->is_const = 1;
		new_sym->value = *v;
	} else {
		struct symbol_table *defining_table;

		new_sym->is_const = 0;
		/*
		 * Find allocation offset for the symbol's value.
		 */
		defining_table = stab;
		while (defining_table->parent != NULL &&
		    defining_table->parent->level == defining_table->level)
			defining_table = defining_table->parent;
		new_sym->index = defining_table->next_index++;
		/*printf("%s->index = %d\n", new_sym->token, new_sym->index);*/
	}
	new_sym->next = stab->head;
	stab->head = new_sym;

	return(new_sym);
}

struct symbol *
symbol_lookup(struct symbol_table *stab, wchar_t *s, int global)
{
	struct symbol *sym;

	for (sym = stab->head; sym != NULL; sym = sym->next)
		if (wcscmp(s, sym->token) == 0)
			return(sym);
	if (global && stab->parent != NULL)
		return(symbol_lookup(stab->parent, s, global));
	return(NULL);
}

int
symbol_is_global(struct symbol *sym)
{
	return(sym->in->parent == NULL);
}

void
symbol_set_type(struct symbol *sym, struct type *t)
{
	assert(sym->type == NULL);
	sym->type = t;
}

void
symbol_set_value(struct symbol *sym, struct value v)
{
	assert(sym->is_const);
	sym->value = v;
}

#ifdef DEBUG
static int stab_indent = 0;
#endif

void
symbol_table_dump(struct symbol_table *stab, int show_ast)
{
#ifdef DEBUG
	struct symbol *s;
	int i;

	printf("STAB<\n");
	stab_indent += 4;
	for (s = stab->head; s != NULL; s = s->next) {
		symbol_dump(s, show_ast);
		/* if (s->next != NULL) */
		printf("\n");
	}
	stab_indent -= 4;
	for (i = 0; i < stab_indent; i++)
		printf(" ");
	printf(">");
#endif
}

void
symbol_dump(struct symbol *sym, int show_ast)
{
#ifdef DEBUG
	int i;

	for (i = 0; i < stab_indent; i++)
		printf(" ");
	
	printf("`");
	fputsu8(stdout, sym->token);
	printf("'(%08lx)", (unsigned long)sym);
	type_print(stdout, sym->type);
	if (sym->is_const) {
		printf("=");
		value_print(sym->value);
	}
#endif
}

void
symbol_print(FILE *f, struct symbol *sym)
{
#ifdef DEBUG
	fprintf(f, "symbol `");
	fputsu8(f, sym->token);
	fprintf(f, "' (type = ");
	type_print(f, sym->type);
	fprintf(f, ")");
#endif
}