/* forw.c */

#include "symbol.h"
#include "expr.h"
#include "forw.h"

static CODE_ADDR *forwroot;
static CODE_ADDR **currentforw;

extern int yyerror();

/* initialise the forw table */

void initforw()
{
	forwroot = NULL;
	currentforw = &forwroot;
}

/* create a forw */

CODE_ADDR *createforw(int address, EXPR_NODE *value, int scope, char *filename, int lineno)
{
	CODE_ADDR *ptr;

	ptr = (CODE_ADDR *)malloc(sizeof(CODE_ADDR));

	if (ptr == NULL)
	{
		yyerror("Out of Memory");
		exit(1);
	}

	ptr->filename = strdup(filename);
	if (ptr->filename == NULL)
	{
		yyerror("Out of Memory");
		exit(1);
	}

	ptr->done	= 0;
	ptr->address	= address;
	ptr->scope	= scope;
	ptr->value	= value;
	ptr->lineno     = lineno;
	ptr->next	= NULL;

	return ptr;
}

/* delete a forw (doesn't follow tree!) */
/* returns the value of sym->next         */

CODE_ADDR *deleteforw(CODE_ADDR *sym)
{
	CODE_ADDR *ptr;

	ptr = sym->next;

	free(sym);		/* free the structure     */

	return ptr;
}

/* delete the whole thing */

void deletewholeforw()
{
	CODE_ADDR *ptr;

	ptr = forwroot;

	while(ptr != NULL)
		ptr = deleteforw(ptr);
}

/* add a forw to the forw table */

void addforw(int address, EXPR_NODE *value, int scope, char *filename, int lineno)
{
	CODE_ADDR *ptr;

	ptr = createforw(address, value, scope, filename, lineno);

	*currentforw = ptr;
	currentforw = &(ptr->next);
}

void printref(CODE_ADDR *ptr)
{
	printf("Forward Ref:  addr %d, scope %d can be expanded %d - ",
		ptr->address, ptr->scope, exprcheck(ptr->value));
	anexprlist(ptr->value);
}

void listforwardrefs()
{
	CODE_ADDR *ptr;

	ptr = forwroot;

	while(ptr != NULL)
	{
		printref(ptr);
		ptr = ptr->next;
	}
}
void resolveforwardrefs(int scope_now)
{
	CODE_ADDR *ptr;

	ptr = forwroot;

	while(ptr != NULL)
	{
		if (!ptr->done)
		{
			if (ptr->scope >= scope_now)
			{
				if (!exprcheck(ptr->value))
				{
					emit(ptr->address, evaluateexpr(ptr->value));
					ptr->done = 1; /* delete from queue in next version */
				}
			}
		}
		ptr = ptr->next;
	}
}

/* returns 0 if none left, 1 if any have been left */
/* prints error messages for these */

int anyforwardsleft()
{
	CODE_ADDR *ptr;
	int retval = 0;

	ptr = forwroot;

	while(ptr != NULL)
	{
		if (ptr->done == 0)
		{
			retval = 1;
			fprintf(stderr,"Error forward reference not defined anywhere, in file %s, line %d\n",ptr->filename, ptr->lineno);
		}

		ptr = ptr->next;
	}

	return retval;
}

/* ... The End ... */
