/* Symbol table handling */

#include "com.h"
#include "symtab.h"

/* Global symbol/type table */
Var *global;

/* Table for dealing with structures */
Var *structures;

Var *lookup(Var *table, const char *sym)
{
	for(; table != NULL; table = table->next)
		if (strcmp(sym, table->name) == 0)
			return table;
		
	return NULL;
}

Var *mkvar(Type *type, char *name)
{
	Var *var = (Var *)malloc(sizeof(*var));

	var->name = name;
	var->next = NULL;
	var->prev = NULL;
	var->type = type;

	return var;
}

Var *add(Var *table, Var *var)
{
	assert(var != NULL);
	
	var->next = var->prev = NULL;
	
	if (table != NULL)
	{
		Var *tp = table;
		
		while(tp->next != NULL)
			tp = tp->next;

		tp->next = var;
		var->prev = tp;
	}
	else
		table = var;

	return table;
}

Var *addl(Var *table, Var *l)
{
	Var *n;

	assert(l != NULL);
	
	for(; l != NULL; l = n)
	{
		n = l->next;
		table = add(table, l);
	}

	return table;
}

Var *preadd(Var *table, Var *var)
{
	var->next = table;
	if (table)
		table->prev = var;
	
	return var;
}

Type *mktype(void)
{
	Type *tp = (Type *)malloc(sizeof(Type));

	tp->tclass = NoType;
	tp->anon = 1;
	tp->nocode = 0;
	tp->nohdr = 0;
	tp->demand = 0;
	tp->norep = 0;
	tp->coded = 0;
	tp->name = NULL;
	
	return tp;
}

Var *mktypedef(Type *type, char *name)
{
	Type *td = mktype();
	Var *tv = mkvar(td, name);

	td->tclass = Typedef;
	td->i.typedef_i.t = type;
	td->i.typedef_i.n = name;
	type->anon = 0;

	if (type->name == NULL)
		type->name = td;
	
	td->anon = 0;
	td->norep = type->norep;
	
	return tv;
}

Type *mkstruct(Var *vars)
{
	Type *st = mktype();

	st->tclass = Struct;
	st->i.struct_i = vars;

	return st;
}

Type *mkpointer(Type *type)
{
	Type *pt = mktype();

	pt->tclass = Pointer;
	pt->i.pointer_i = type;

	return pt;
}

Type *mkvoid(void)
{
	Type *v = mktype();

	v->tclass = Void;
	return v;
}

Type *mkarray(Type *type)
{
	Type *at = mktype();

	at->tclass = Array;
	at->i.array_i = type;

	return at;
}

Type *mkcarray(Type *type, unsigned int size)
{
	Type *at = mktype();

	at->tclass = CArray;
	at->i.carray_i.type = type;
	at->i.carray_i.size = size;
	
	return at;
}

Type *mkscalar(enum sc_size sz, int sgn)
{
	Type *st = mktype();

	st->tclass = Scalar;
	st->i.scalar_i.size = sz;
	st->i.scalar_i.Unsigned = sgn;

	return st;
}

Type *realtype(Type *t)
{
	while(t && t->tclass == Typedef)
		t = t->i.typedef_i.t;

	return t;
}

Type *Ulonglong_type;
Type *Ulong_type;
Type *Ushort_type;
Type *Uchar_type;
Type *longlong_type;
Type *long_type;
Type *short_type;
Type *char_type;
Type *void_type;
Type *float_type;
Type *double_type;

/*
 * Carefully set up symbol table types.  Most of the fiddling here
 * is to cover the slight differences between our type system and
 * C's
 */
void init_symtab(void)
{
	Var *v;
	Type *t;
	
	global = NULL;
	structures = NULL;
	
	t = char_type = mkscalar(Char, 0);
	t->nocode = t->nohdr = 1;
	t = Uchar_type = mkscalar(Char, 1);
	t->nocode = 1;

	t = short_type = mkscalar(Short, 0);
	t->nocode = t->nohdr = 1;
	t = Ushort_type = mkscalar(Short, 1);
	t->nocode = 1;

	t = long_type = mkscalar(Long, 0);
	t->nocode = t->nohdr = 1;
	t = Ulong_type = mkscalar(Long, 1);
	t->nocode = 1;

	t = longlong_type = mkscalar(LongLong, 0);
	t->nocode = t->nohdr = 1;
	t = Ulonglong_type = mkscalar(LongLong, 1);
	t->nocode = 1;

	t = float_type = mkscalar(Float, 0);
	t->nocode = t->nohdr = 1;
	t = double_type = mkscalar(Double, 1);
	t->nocode = 1;

	t = void_type = mkvoid();
	t->nohdr = t->nocode = t->norep = 1;
	
	global = add(global, v = mktypedef(char_type, "char"));
	v->type->nocode = v->type->nohdr = 1;
	global = add(global, v = mktypedef(short_type, "short"));
	v->type->nocode = v->type->nohdr = 1;
	global = add(global, v = mktypedef(long_type, "long"));
	v->type->nocode = v->type->nohdr = 1;
	global = add(global, v = mktypedef(longlong_type, "longlong"));
	v->type->nocode = v->type->nohdr = 1;

	global = add(global, v = mktypedef(float_type, "float"));
	v->type->nocode = v->type->nohdr = 1;
	global = add(global, v = mktypedef(double_type, "double"));
	v->type->nocode = v->type->nohdr = 1;

	global = add(global, v = mktypedef(void_type, "void"));
	v->type->nohdr = v->type->nocode = v->type->norep = 1;

	global = add(global, v = mktypedef(Uchar_type, "Uchar"));
	v->type->nocode = v->type->nohdr = 1;
	global = add(global, v = mktypedef(Ushort_type, "Ushort"));
	v->type->nocode = v->type->nohdr = 1;
	global = add(global, v = mktypedef(Ulong_type, "Ulong"));
	v->type->nocode = v->type->nohdr = 1;
	global = add(global, v = mktypedef(Ulonglong_type, "Ulonglong"));
	v->type->nocode = v->type->nohdr = 1;
    	global = add(global, v=mktypedef(Ulong_type, "Uint"));
	v->type->demand = v->type->nohdr = v->type->indir = 1;

	global = add(global, v=mktypedef(long_type, "int"));
	v->type->demand = v->type->nohdr = v->type->indir = 1;
}

extern char *prefix;

static Var *name_type(Type *type, Var *var)
{
	Var *vp;
	static typecnt = 1;

	if (type->tclass != Typedef && type->anon == 1)
	{
		char buf[20];
		Var *nv;
		
		sprintf(buf, "_%s_%03d", prefix, typecnt++);

		nv = mktypedef(type, strdup(buf));
		type->anon = 1;
		
		var = preadd(var, nv);
	}

	switch(type->tclass)
	{
	case Array:
		var = name_type(type->i.array_i, var);
		break;

	case CArray:
		var = name_type(type->i.carray_i.type, var);
		break;
		
	case Pointer:
		var = name_type(type->i.pointer_i, var);
		break;

	case Struct:
		for(vp = type->i.struct_i; vp != NULL; vp = vp->next)
			var = name_type(vp->type, var);
		break;

	case Typedef:
		var = name_type(type->i.typedef_i.t, var);
		break;
		
	default:
		break;
	}

	return var;
}

Var *name_types(Var *table)
{
	Var *vp, *sc;
	Var *tab;
	
	for(tab = table; tab != NULL; tab = tab->next)
	{
		if (tab->type->nocode)
			continue;
		vp = name_type(tab->type, NULL);

		if (vp == NULL)
			continue;
		
		for(sc = vp; sc->next != NULL; sc = sc->next)
			;

		vp->prev = tab->prev;
		if (tab->prev)
			tab->prev->next = vp;
		else
			table = vp;
		
		sc->next = tab;
		tab->prev = sc;
	}

	return table;
}
