view parser.c @ 75:0083b2f7b3c7

Partially working implementation of List. Modified build scripts to allow use of other compilers. Fixed some bugs involving method implementations on different types returning different numbers of outputs. Added Fold to the 'builtins' in the comipler.
author Mike Pavone <pavone@retrodev.com>
date Tue, 06 Jul 2010 07:52:59 -0400
parents 9749109b3198
children
line wrap: on
line source

#include "structs.h"
#include "visuality.h"
#include "debugmacros.h"
#ifdef WIN32
	#include "windows.h"
#endif
#include <stdio.h>
#include "interp.h"
#include "parser.h"
#include <string.h>
#include <stdlib.h>

extern int num_workers;
extern int num_wires;

/*#ifdef SEGA
#define NUM_WORKERS_START	40
#define NUM_WIRES_START		80
#else
#define NUM_WORKERS_START	1024
#define NUM_WIRES_START		2048
#endif*/
#define NUM_WORKERS_START 	20
#define NUM_WIRES_START		40
//TODO: Figure out why setting those defines to 16 and 32 respectively causes problems

BOOL is_whitespace(char c)
{
	if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
		return TRUE;
	return FALSE;
}

company * create_company(program * prog, char * name, int num_workers, int num_rooms, BOOL buildable)
{
	company * this_comp = &(prog->companylist[prog->num_companies]);
	DEBUGPRINTF("create_company %s with %d workers and %d rooms\n", name, num_workers, num_rooms);
	this_comp->type_id = prog->num_companies++;
	strncpy(this_comp->name, name, 256);
	this_comp->name[255] = '\0';
	if(num_workers)
		this_comp->methodlist = MALLOC(sizeof(worker_def *) * num_workers, "company methodlist");
	else
		this_comp->methodlist = NULL;
	this_comp->num_methods = 0;//num_workers;
	this_comp->method_storage = num_workers;
	if(num_rooms)
	{
		this_comp->room_list = MALLOC(sizeof(company_room) * num_rooms, "company roomlist");
		DEBUGPRINTF("Allocated %d bytes at %X for room_list\n", sizeof(company_room) * num_rooms, this_comp->room_list);
	}
	else
		this_comp->room_list = NULL;
	this_comp->num_rooms = 0;//num_rooms;
	this_comp->room_storage = num_rooms;
	if(buildable)
		this_comp->build_size = 0;
	else
		this_comp->build_size = -1;
	VIS_InitializeCriticalSection(this_comp->lock);
	return this_comp;
}

int add_method(company * this_comp, worker_def * def)
{
	worker_def ** temp;
	int i;
	DEBUGPUTS("add_method: ");
	DEBUGPRINTF("%s\n", def->name);
	VIS_EnterCriticalSection(this_comp->lock);
	if(this_comp->method_storage - this_comp->num_methods <= 0)
	{
		if(this_comp->method_storage < 2)
			this_comp->method_storage = 4;
		else
			this_comp->method_storage = this_comp->method_storage + ((this_comp->method_storage) >> 1);
		temp = MALLOC(sizeof(worker_def *) * this_comp->method_storage, "company method storage");
		for(i = 0; i < this_comp->num_methods; ++i)
			temp[i] = this_comp->methodlist[i];
		VIS_FREE(this_comp->methodlist, "company methodlist");
		this_comp->methodlist = temp;
	}
	i = this_comp->num_methods;
	this_comp->methodlist[this_comp->num_methods++] = def;
	DEBUGPRINTF("%s now has %d methods\n", this_comp->name, this_comp->num_methods);
	VIS_LeaveCriticalSection(this_comp->lock);
	return i;
}
int room_build_sizes[] = {0, sizeof(char), sizeof(short), sizeof(long), sizeof(float), sizeof(double), -1, -1, -1, -1, -1, sizeof(datum *), 0};
int add_comp_room(company * this_comp, char * name, int set_func, int get_func, short set_func_type, short get_func_type)
{
	company_room * temp;
	int i;
	int min_build_size;
	VIS_EnterCriticalSection(this_comp->lock);
	DEBUGPRINTF("add_comp_room: %s", name);
	DEBUGPRINTF(", num_rooms: %d, room_storage: %d\n", this_comp->num_rooms, this_comp->room_storage);
	if(this_comp->room_storage - this_comp->num_rooms <= 0)
	{
		if(this_comp->room_storage < 2)
			this_comp->room_storage = 4;
		else
			this_comp->room_storage = this_comp->room_storage + ((this_comp->room_storage) >> 1);
		temp = MALLOC(sizeof(company_room) * this_comp->room_storage, "company room storage");
		memcpy(temp, this_comp->room_list, sizeof(company_room)*this_comp->num_rooms);
		VIS_FREE(this_comp->room_list, "company room list");
		this_comp->room_list = temp;
	}
	if(this_comp->build_size >= 0)
	{
		DEBUGPRINTF("get_func_type: %d, room_build_sizes[%d] = %d\n", get_func_type, get_func_type, room_build_sizes[get_func_type]);
		if(get_func_type && get_func_type != ROOM_WORKER && get_func == -1)
			get_func = this_comp->build_size;
		if(set_func_type && set_func_type != ROOM_WORKER && set_func == -1)
			set_func = this_comp->build_size;
		if(room_build_sizes[set_func_type])
			if(room_build_sizes[set_func_type] > room_build_sizes[get_func_type])
				min_build_size = room_build_sizes[set_func_type] + set_func;
			else
				min_build_size = room_build_sizes[get_func_type] + get_func;
		else if(room_build_sizes[get_func_type])
			min_build_size = room_build_sizes[get_func_type] + get_func;
		if(min_build_size > this_comp->build_size)
			this_comp->build_size = min_build_size;	
	}
	i = this_comp->num_rooms;
	DEBUGPUTS("Copying name\n");
	this_comp->room_list[this_comp->num_rooms++].name = MALLOC(strlen(name) + 1, "company room name");
	strcpy(this_comp->room_list[i].name, name);
	DEBUGPUTS("Setting func types\n");
	this_comp->room_list[i].set_func_type = set_func_type;
	this_comp->room_list[i].get_func_type = get_func_type;
	DEBUGPRINTF("Setting funcs: get = %d, set = %d\n", get_func, set_func);
	//TODO: Change the signature of this function so that get_func and set_func are void * so we can safely pass in pointers for future get_func types
	this_comp->room_list[i].get_func = (void *)get_func;
	this_comp->room_list[i].set_func = (void *)set_func;
	DEBUGPRINTF("Build size is now: %d\n", this_comp->build_size);
	DEBUGPUTS("before return\n");
	VIS_LeaveCriticalSection(this_comp->lock);
	return i;
}

worker_def * create_worker(program * prog, char * name, int num_inputs, int num_outputs, short type)
{
	custom_worker * aworker;
	int i, j;
	int thisdef;
	worker_def * deflist;
	DEBUGPRINTF("create_worker: %s with %d inputs and %d outputs\n", name, num_inputs, num_outputs);
	if(!strcmp(name, "Main"))
	{
		thisdef = 0;
		deflist = prog->defs->deflist;
	}
	else
	{
		if(prog->current->num_defs >= prog->current->defs_storage) {
			prog->current->next = MALLOC(sizeof(defchunk) + (START_DEF_STORAGE - 1) * sizeof(worker_def), "worker def storage");
			prog->current = prog->current->next;
			prog->current->defs_storage = START_DEF_STORAGE;
			prog->current->num_defs = 0;
			prog->current->next = NULL;
		}
		if(prog->current == prog->defs && prog->current->num_defs == 0)
			prog->current->num_defs = 1;
		thisdef = prog->current->num_defs;
		deflist = prog->current->deflist;
	}
	DEBUGPRINTF("new deflist index: %d\n", thisdef);
	if(type & USER_FLAG && (type & TYPE_MASK) == WORKER_TYPE)
	{
		//puts("Creating custom worker.");
		aworker = MALLOC(sizeof(custom_worker), "custom worker implementation");
		aworker->num_workers = 0;
		aworker->num_wires = 0;
		aworker->workerlist = MALLOC(sizeof(worker)*NUM_WORKERS_START, "custom worker workerlist");
		aworker->worker_storage = NUM_WORKERS_START;
		aworker->wirelist = MALLOC(sizeof(wire)*NUM_WIRES_START, "custom worker wirelist");
		aworker->wire_storage = NUM_WIRES_START;
		aworker->workers_to_wires_up = MALLOC(sizeof(int)*(NUM_WIRES_START+1),"custom worker workers to wires up");
		aworker->workers_to_wires_down = MALLOC(sizeof(int)*(NUM_WIRES_START+1),"custom worker workers to wires down");
		aworker->dirty = TRUE;
		VIS_InitializeCriticalSection(aworker->lock);
		deflist[thisdef].implement_func = aworker;
	}
	DEBUGPUTS("Setting properties\n");
	deflist[thisdef].num_inputs = num_inputs;
	deflist[thisdef].num_outputs = num_outputs;
	deflist[thisdef].type = type;
	DEBUGPUTS("Calling malloc\n");
	deflist[thisdef].name = MALLOC(strlen(name)+1, "worker def name");
	DEBUGPRINTF("malloc return: %X, calling strcpy\n", deflist[thisdef].name);
	strcpy(deflist[thisdef].name, name);
	DEBUGPUTS("strcpy done\n");
	
	if(num_inputs)
		deflist[thisdef].input_types = MALLOC(sizeof(short) * num_inputs, "worker def input types");
	else
		deflist[thisdef].input_types = NULL;
	if(num_outputs)
		deflist[thisdef].output_types = MALLOC(sizeof(short) * num_outputs, "worker def output types");
	else
		deflist[thisdef].output_types = NULL;
	for(i = 0; i < num_inputs; ++i)
		deflist[thisdef].input_types[i] = ANY_TYPE;
	deflist[thisdef].num_stores = 0;
	deflist[thisdef].uses_stores = NULL;
	deflist[thisdef].transaction_flags = TRANSACTION_RETRY;
	if(thisdef >= prog->current->num_defs)
		prog->current->num_defs = thisdef+1;
	for(i = 0; name[i] != '\0'; ++i)
	{
		if(name[i] == '@')
		{
			DEBUGPRINTF("Name ends in %s\n", name+i);
			for(j = 0; j < prog->num_companies; ++j)
			{
				if(!strcmp(name+i+1, prog->companylist[j].name))
				{
					DEBUGPRINTF("Worker is a method of company %d, ", j);
					DEBUGPRINTF("%s\n", prog->companylist[j].name);
					add_method(prog->companylist+j, deflist+thisdef);
					break;
				}
			}
			break;
		}
	}
	deflist[thisdef].program = prog;
	return deflist + thisdef;
}

int find_worker(char * name, int * num_inputs, int * num_outputs, program * prog, worker_def ** def)
{
	int i;
	int term;
	int len;
	defchunk * current;
	worker_def * temp;
	DEBUGPRINTF("Calling strlen on name: %X\n", name);
	len = strlen(name);
	DEBUGPRINTF("find_worker: %s\n", name);
	if(len >= 2 && !strcmp(name+len-2, ">>"))
	{
		DEBUGPUTS("Get property\n");
		term = len-2;
		for(i = term-1; i > 0; --i)
		{
			if(name[i] == ' ')
				term = i;
			else
				break;
		}
		DEBUGPRINTF("term: %d\n", term);
		name[term] = '\0';
		DEBUGPRINTF("name: %s\n", name);
		if(num_inputs);
			*num_inputs = 1;
		if(num_outputs)
			*num_outputs = 1;
		return -1;
	}
	if(len >= 2 && !strcmp(name+len-2, "<<"))
	{
		DEBUGPUTS("Set property\n");
		term = len-2;
		for(i = term-1; i > 0; --i)
		{
			if(name[i] == ' ')
				term = i;
			else
				break;
		}
		DEBUGPRINTF("term: %d\n", term);
		name[term] = '\0';
		DEBUGPRINTF("name: %s\n", name);
		if(num_inputs);
			*num_inputs = 2;
		if(num_outputs)
			*num_outputs = 1;
		return -2;
	}
	current = prog->defs;
	while(current)
	{
		for(i = 0; i < current->num_defs; ++i)
		{
			if(current->deflist[i].name && !strcmp(current->deflist[i].name, name))
			{
				DEBUGPRINTF("Found worker #%d\n", i);
				if(num_inputs)
					*num_inputs = current->deflist[i].num_inputs;
				if(num_outputs)
					*num_outputs = current->deflist[i].num_outputs;
				if(def)
					*def = current->deflist + i;
				return i;
			}
		}
		current = current->next;
	}
	if(num_inputs && num_outputs)
	{
		for(i = 1; i < prog->num_companies; ++i)
		{
			temp = find_method(i, name, *num_inputs, prog);
			if(temp && temp->num_outputs >= *num_outputs)
			{
				*def = create_worker(prog, name, temp->num_inputs, temp->num_outputs, MAGIC_TYPE);
				return 1;
			}
		}
	}
	else
	{
		for(i = 1; i < prog->num_companies; ++i)
		{
			temp = find_method_noinputcheck(i, name, prog);
			if(temp)
			{
				*def = create_worker(prog, name, temp->num_inputs, temp->num_outputs, MAGIC_TYPE);
				return 1;
			}
		}
	}
	DEBUGPUTS("Could not find worker\n");
	return -3;
}

int generic_add_to_def(worker_def * parent, char * name,int display_type, int type, int num_inputs, int num_outputs, double xpos, double ypos)
{
	int returnval;
	worker * temp;
	VIS_EnterCriticalSection(parent->implement_func->lock);
		if(parent->implement_func->num_workers >= parent->implement_func->worker_storage) {
			parent->implement_func->worker_storage = parent->implement_func->num_workers + (parent->implement_func->num_workers >> 1);
			parent->implement_func->workerlist = realloc(parent->implement_func->workerlist, parent->implement_func->worker_storage * sizeof(worker));
		}
		strcpy(parent->implement_func->workerlist[parent->implement_func->num_workers].name, name);
		parent->implement_func->workerlist[parent->implement_func->num_workers].type=type;
		parent->implement_func->workerlist[parent->implement_func->num_workers].num_inputs = num_inputs;
		parent->implement_func->workerlist[parent->implement_func->num_workers].num_outputs = num_outputs;
		parent->implement_func->workerlist[parent->implement_func->num_workers].null_input = FALSE;
		parent->implement_func->workerlist[parent->implement_func->num_workers].magic_cache_implement = NULL;
		parent->implement_func->workerlist[parent->implement_func->num_workers].magic_cache_type = 0;
		VIS_InitializeCriticalSection(parent->implement_func->workerlist[parent->implement_func->num_workers].lock);
		parent->implement_func->dirty = TRUE;
		//puts("end generic_add_to_def");
		DEBUGPRINTF("generic_add_to_def: %s with type %d and num_inputs %d and num_outputs %d returned %d\n", name, type, num_inputs, num_outputs, parent->implement_func->num_workers);
		returnval =  parent->implement_func->num_workers++;
	VIS_LeaveCriticalSection(parent->implement_func->lock);
	return returnval;
}

int add_worker_to_def(worker_def * parent, worker_def * worker, double xpos, double ypos)
{
	int list_index;
	list_index = generic_add_to_def(parent, worker->name, TRAPEZOID, WORKER, worker->num_inputs, worker->num_outputs, xpos, ypos);

	parent->implement_func->workerlist[list_index].value_index = worker;
	return list_index;
}

int add_get_comp_room(worker_def * parent, char * name, double xpos, double ypos)
{
	return generic_add_to_def(parent, name, RECTANGLE, GET_COMP, 1, 2, xpos, ypos);
}

int add_set_comp_room(worker_def * parent, char * name, double xpos, double ypos)
{
	return generic_add_to_def(parent, name, RECTANGLE, SET_COMP, 2, 1, xpos, ypos);
}

int add_global(worker_def * parent, char * name, double xpos, double ypos, int type)
{
	int i,j;
	int thisdef;
	int num_in, num_out;
	if(type == SET_GLOBAL)
	{
		num_in = 1;
		num_out = 0;
		parent->transaction_flags |= TRANSACTION_WRITE;
	}
	else
	{
		num_in = 0;
		num_out = 1;
	}
	thisdef = generic_add_to_def(parent, name, RECTANGLE, type, num_in, num_out, xpos, ypos);
	for(i = 0; name[i+1] != '\0'; ++i)
	{
		if(name[i] == ':' && name[i+1] == ':')
		{
			parent->implement_func->workerlist[thisdef].value_index = (void *)-1;
			if(i > 0)
			{
				for(j = 0; j < parent->num_stores; ++j)
				{
					if(strlen(parent->uses_stores[j]) == i && !memcmp(parent->uses_stores[j], name, i))
					{
						parent->implement_func->workerlist[thisdef].value_index = (void *)j;
						break;
					}
				}
				if(parent->implement_func->workerlist[thisdef].value_index < 0)
				{
					name[i] = '\0';
					printf("Error: Worker %s is not declared to use global store %s but references it.\n", parent->name, name);
					exit(-1);
				} 
			}
			else if(type == SET_GLOBAL)
				parent->implement_func->workerlist[thisdef].value_index = 0;
			parent->implement_func->workerlist[thisdef].io_num = i+2;
			break;
		}
	}
	return thisdef;
}

int add_global_get(worker_def * parent, char * name, double xpos, double ypos)
{
	return add_global(parent, name, xpos, ypos, GET_GLOBAL);
}

int add_global_set(worker_def * parent, char * name, double xpos, double ypos)
{
	return add_global(parent, name, xpos, ypos, SET_GLOBAL);
}

int find_object(worker_def * def, char * name, int type)
{
	int i;
	for(i = 0; i < def->implement_func->num_workers; ++i)
		if(!strcmp(def->implement_func->workerlist[i].name, name) && def->implement_func->workerlist[i].type == 1)
			break;
	if(i < def->implement_func->num_workers)
		return i;
	return -1;
}

int create_find_room(worker_def * def, char * name, double xpos, double ypos)
{
	int found = find_object(def, name, ROOM);
	if(found >= 0)
		return found;
	return generic_add_to_def(def, name, RECTANGLE, ROOM, 1, 1, xpos, ypos);
}

int add_constant(worker_def * def, char * value, double xpos, double ypos)
{
	int index = generic_add_to_def(def, value, RECTANGLE, CONSTANT, 0, 1, xpos, ypos);
	def->implement_func->workerlist[index].value_index = get_constant(value, -1, def->program);
	return index;
}

int add_input_num(worker_def * def, char * name, int input_num, double xpos, double ypos)
{
	int i;
	unsigned short * temp_types;
	int found;
	if(def->num_inputs <= input_num)
	{
		temp_types = def->input_types;
		def->input_types = MALLOC(sizeof(short)*(input_num+1), "worker def input types");
		if(temp_types) {
			memcpy(def->input_types, temp_types, sizeof(short)*def->num_inputs);
			VIS_FREE(temp_types, "temp types?");
		}
		for(i = def->num_inputs; i <= input_num; ++i)
			def->input_types[i] = ANY_TYPE;
		def->num_inputs = input_num+1;
	}
	found = generic_add_to_def(def, name, RECTANGLE, INPUT, 0, 1, xpos, ypos);
	def->implement_func->workerlist[found].io_num = input_num;
	return found;
}
int add_input(worker_def * def, char * name, double xpos, double ypos)
{
	
	int input_num;
	int i;
	for(i = 0; name[i] != 0; ++i)
		if(name[i] == '(')
		{
			input_num = atol(name+i+1);
			break;
		}
	return add_input_num(def, name, input_num, xpos, ypos);
}

int add_output_num(worker_def * def, char * name, int output_num, double xpos, double ypos)
{
	int i;
	unsigned short * temp_types;
	int found;
	if(def->num_outputs <= output_num)
	{
		temp_types = def->output_types;
		def->output_types = MALLOC(sizeof(short)*(output_num+1), "worker def output types");
		if(temp_types)
		{
			memcpy(def->output_types, temp_types, sizeof(short)*def->num_outputs);
			VIS_FREE(temp_types, "temp types?");
		}
		for(i = def->num_outputs; i <= output_num; ++i)
			def->output_types[i] = ANY_TYPE;
		def->num_outputs = output_num+1;
	}
	found = generic_add_to_def(def, name, RECTANGLE, OUTPUT, 1, 0, xpos, ypos);
	def->implement_func->workerlist[found].io_num = output_num;
	return found;
}
int add_output(worker_def * def, char * name, double xpos, double ypos)
{
	int output_num;
	int i;
	
	for(i = 0; name[i] != 0; ++i)
		if(name[i] == '(')
		{
			output_num = atol(name+i+1);
			break;
		}
	return add_output_num(def, name, output_num, xpos, ypos);
}

int create_find_output(worker_def * def, char * name, double xpos, double ypos)
{
	int output_num;
	int i;
	unsigned short * temp_types;
	int found = find_object(def, name, OUTPUT);
	if(found >= 0)
		return found;
	return add_output(def, name, xpos, ypos);
}

void add_wire(worker_def * def, int start, int output_num, int end, int input_num)
{
	VIS_EnterCriticalSection(def->implement_func->lock);
		if(def->implement_func->num_wires >= def->implement_func->wire_storage) {
			def->implement_func->wire_storage = def->implement_func->num_wires + (def->implement_func->num_wires >> 1);
			def->implement_func->wirelist = realloc(def->implement_func->wirelist, def->implement_func->wire_storage * sizeof(wire));
			def->implement_func->workers_to_wires_up = realloc(def->implement_func->workers_to_wires_up, (def->implement_func->wire_storage+1) * sizeof(int));
			def->implement_func->workers_to_wires_down = realloc(def->implement_func->workers_to_wires_down, (def->implement_func->wire_storage+1) * sizeof(int));
		}
		def->implement_func->wirelist[def->implement_func->num_wires].start_worker = start;
		def->implement_func->wirelist[def->implement_func->num_wires].end_worker = end;
		def->implement_func->wirelist[def->implement_func->num_wires].output_num = output_num;
		def->implement_func->wirelist[def->implement_func->num_wires].input_num = input_num;
		def->implement_func->dirty = TRUE;
		++def->implement_func->num_wires;
		if(input_num == -1)
		{
			def->implement_func->workerlist[end].null_input = TRUE;
		}
	VIS_LeaveCriticalSection(def->implement_func->lock);
}

int process_expression(worker_def * def, int num_outputs, char ** outvars, int num_inputs, char ** inputs, char * workername, BOOL worker_expr, int block_depth, int * block_workers, int * block_output, int last_worker)
{
	int i,j;
	int current;
	int this_worker;// = ++return_worker;
	int expected_in, expected_out;
	int input_num=-1;
	int worker_num;
	worker_def * call_def;
	BOOL block_attach=FALSE;
	BOOL room = FALSE;
	BOOL global_flag;
	if(worker_expr)
	{
		DEBUGPUTS("calling find_worker\n");
		expected_in = num_inputs;
		expected_out = num_outputs;
		worker_num = find_worker(workername, &expected_in, &expected_out, def->program, &call_def);
		DEBUGPRINTF("\nWorker %s with %d inputs and %d outputs expects %d inputs and %d outputs\n", workername, num_inputs, num_outputs, expected_in, expected_out);
		if(worker_num >= 0)
			this_worker = add_worker_to_def(def, call_def, 1.0, 1.0);
		else if(worker_num == -1)
			this_worker = add_get_comp_room(def, workername, 1.0, 1.0);
		else if(worker_num == -2)
			this_worker = add_set_comp_room(def, workername, 1.0, 1.0);
		else
		{
			ERRORPRINTF("Could not find a worker named %s or a method of the same name with %d inputs and at least %d outputs\n", workername, num_inputs, num_outputs);
			for(i = 0; i < num_inputs; ++i)
			{
				ERRORPRINTF("Input %d was %s\n", i, inputs[i]);
			}
			exit(-1);
		}
	}
	else
	{
		if(workername[0] == '{' || workername[0] == '"' || (workername[0] >= '0' && workername[0] <= '9') || strcmp(workername, "Yes") == 0 || strcmp(workername, "No") == 0)
		{
			//Constant expression
			this_worker = add_constant(def, workername, 1.0, 1.0);
		}
		/*else if(workername[0] == '"')
		{
			//printf("\nString %s\n", workername);
			workername[strlen(workername)-1] = '\0';
			this_worker = add_constant(def, workername+1, 1.0, 1.0);
		}
		else if(workername[0] >= '0' && workername[0] <= '9')
		{
			//printf("\nNumber %s\n", workername);
			this_worker = add_constant(def, workername, 1.0, 1.0);
		}
		else if(strcmp(workername, "Yes") == 0 || strcmp(workername, "No") == 0)
		{
			this_worker = add_constant(def, workername, 1.0, 1.0);
		}*/
		else
		{
			for(i = 0; workername[i] != 0; ++i)
				if(workername[i] == '(')
				{
					input_num = atol(workername + i+1);
					break;
				}
			if(input_num >= 0)
			{
				//printf("\nInput %d %s\n", input_num, workername);
				this_worker = add_input(def, workername, 1.0, 1.0);
			}
			else
			{
				room = TRUE;
				//printf("\nRoom %s\n", workername);
				for(i = 0; i < strlen(workername)-1; ++i)
				{
					if(workername[i] == ':' && workername[i+1] == ':')
					{
						room = FALSE;
						break;
					}
				}
				if(room)
					this_worker = create_find_room(def, workername, 1.0, 1.0);
				else
					this_worker = add_global_get(def, workername, 1.0, 1.0);
				
			}
		}
	}
	for(i = 0; i < num_inputs; ++i)
		if(inputs[i])
		{
			if(!strcmp(inputs[i], "~")) 
			{
				//printf("Input %d = ~ (parent block)\n", i);
				if(!block_depth)
				{
					printf("Error: Reference to parent block (~) for input %d of worker %s, but block depth is 0", i, workername);
					exit(-2);
				}
				add_wire(def, block_workers[block_depth-1], block_output[block_depth-1], this_worker, i);
				block_attach = TRUE;
			}
			else
			{
				DEBUGPRINTF("Processing input %d (%s)\n", i, inputs[i]);
				if(block_depth)
					current = parse_body(def, inputs[i], strlen(inputs[i]), block_depth, block_output, block_workers);
				else
					current = parse_body(def, inputs[i], strlen(inputs[i]), 0, NULL, NULL);
				add_wire(def, current, 0, this_worker, i);
			}
		}
		else
		{
			//printf("Input %d = last_worker(%d)\n", i, last_worker);
			add_wire(def, last_worker, 0, this_worker, i);
		}
	for(i = 0; i < num_outputs; ++i)
	{
		global_flag = FALSE;
		//printf("Output %d = %s\n", i, outvars[i]);
		for(j = 0; outvars[i][j] != '\0'; ++j)
			if(outvars[i][j] == '(')
				break;
			else if(outvars[i][j] == ':' && outvars[i][j+1] == ':')
				break;				
		if(outvars[i][j] == '\0')
			current = create_find_room(def, outvars[i], 2.0, 2.0);
		else if(outvars[i][j] == ':')
			current = add_global_set(def, outvars[i], 2.0, 2.0);
		else
			current = create_find_output(def, outvars[i], 2.0, 2.0);
		add_wire(def, this_worker, i, current, 0);
	}
	
	//printf("Current blockdepth: %d\n", block_depth);
	if(block_depth > 0)
	{
		//printf("Block Worker: %d\nBlock Output: %d\n", block_workers[block_depth-1], block_output[block_depth-1]);
		if(worker_expr && num_inputs < expected_in)
		{
			if(block_attach)
				printf("Warning: Worker %s is attached to block both explicitly and implicitly (i.e. at least one input was stated as ~, but there are still unsatisfied inputs)\n", workername);
			if(expected_in - num_inputs > 1)
				printf("Warning: More than one input of worker %s implicitly tied to block (%d inputs implicitly tied)", workername, expected_in - num_inputs);
			for(i = num_inputs; i < expected_in; ++i)
				add_wire(def, block_workers[block_depth-1], block_output[block_depth-1], this_worker, i);
				
		}
		else if(!block_attach && !room)
		{
			add_wire(def, block_workers[block_depth-1], block_output[block_depth-1], this_worker, -1);
			//def->implement_func->workerlist[this_worker].null_input = TRUE;
		}
	} 
	else  if(worker_expr && num_inputs < expected_in)
	{
		ERRORPRINTF("Error: Worker %s expects %d input(s), but was only given %d input(s)\n", workername, expected_in, num_inputs);
		exit(-1);
	}
	//printf("Returning %d\n\n", this_worker);
	return this_worker;
}
typedef enum {NULL_STATE, OUT_STATE, BETWEEN_OUT, BEFORE_WORK, PRE_IN_STATE, BETWEEN_PRE_IN, WORK_STATE, IN_STATE, BETWEEN_IN, AFTER_IN, BLOCK_FIND, LINE_COMMENT_STATE} parse_state;
char state_txt[12][20] = {"Null","Out","Between Out","Before Work","Pre Input","Between Pre-Input","Worker","Input","Between Input","After Input","Block Find"};
int parse_body(worker_def * def, char * code, int len, int prev_block_depth, int * prev_block_output, int * prev_block_workers)
{
	char * outputs[32];
	char * inputs[32];
	char * worker;
	short saw_line=0;
	int num_inputs=0, num_outputs=0;
	int left_bracket=0;
	int left_curly=0;
	int block_depth = 0;
	int block_workers[32];
	int block_output[32];
	int last_worker = 0;
	BOOL worker_expr = FALSE;
	BOOL in_string = FALSE;
	BOOL literal = FALSE;
	BOOL do_curly = FALSE;
	BOOL saw_newline = FALSE;
	int i,j;
	int start;
	int line_comment_start;
	parse_state state = NULL_STATE;
	parse_state old_state;
	DEBUGPRINTF("code: %X\n", code);
	//printf("prev_block_depth: %d\n", prev_block_depth);
	for(i=0; i < len; ++i)
	{
		//printf("i: %d, code[i]: '%c', state: %s(%d)\n", i, code[i], state_txt[state],state);
		DEBUGPRINTF("i: %d, code[i]: '%c', state: %s(%d), left_bracket: %d, num_inputs: %d\n", i, code[i], state_txt[state],state, left_bracket, num_inputs);
		if(!in_string)
		{
			if(state != LINE_COMMENT_STATE)
			{
				if(code[i] == '/' && code[i+1] == '/')
				{
					old_state = state;
					state = LINE_COMMENT_STATE;
					line_comment_start = i;
					i += 2;
				}
				else if(code[i] == '[')
					++left_bracket;
				else if(code[i] == ']')
					--left_bracket;
				else if(code[i] == '{')
					do_curly = TRUE;
				else if(code[i] == '}')
					--left_curly;
				else if(code[i] == '"')
				{
					in_string = TRUE;
					//continue;
				}
			}
			if(left_curly == 0)
			{
				switch(state)
				{
				case NULL_STATE:
					
					if(code[i] == '[')
					{
						//puts("worker_expr = TRUE");
						worker_expr = TRUE;
						state = BETWEEN_PRE_IN;
					}
					else if(code[i] == ':' && code[i+1] == '|')
					{
						++i;
						state = BLOCK_FIND;
					}
					else if(code[i] == '|' && code[i+1] == ':')
					{
						block_workers[block_depth] = last_worker;
						block_output[block_depth++] = 0;
						//puts("Found |: increasing block depth");
						++i;
					}
					else if(!is_whitespace(code[i]))
					{
						start = i;
						for(j = i; j < len-1; ++j)
							if(code[j] == '<' && code[j+1] == '-')
							{
								state = OUT_STATE;
								--i;
								break;
							}
							else if(code[j] == '[' || code[j] == '\n' || (code[j] == '|' && code[j+1] == ':') || code[j] == '#' || code[j] == '"')
							{
								state = WORK_STATE;
								break;
							}
						if(state == NULL_STATE)
							state = WORK_STATE;
					}
					break;
				case OUT_STATE:
					if(code[i] == ',' || (code[i] == '<' && code[i+1] == '-'))
					{
						outputs[num_outputs++] = code + start;
						for(j = i-1; j > start; --j)
							if(!is_whitespace(code[j]))
								break;
						if(code[i] == ',')
							state = BETWEEN_OUT;
						else
						{
							state = BEFORE_WORK;
							++i;
						}
						code[j+1] = '\0';
					}
					break;
				case BETWEEN_OUT:
					if(!is_whitespace(code[i]))
					{
						start = i;
						state = OUT_STATE;
						--i;
					}
					break;
				case BEFORE_WORK:
					if(code[i] == '[')
					{
						//puts("worker_expr = TRUE");
						worker_expr = TRUE;
						state = BETWEEN_PRE_IN;
					}
					else if(code[i] == ':' && code[i+1] == '|')
					{
						start = i;
						while(i < len && (code[i] != '\n' || saw_line < 5))
						{
							if(code[i] == '\n')
								++saw_line;
							++i;
						}
						code[i] = '\0';
						ERRORPRINTF("Error: Expected a worker name, but found a closing bracket (:|) instead at:\n%s", code + start);
						exit(-1);
					}
					else if(!is_whitespace(code[i]))
					{
						start = i;
						state = WORK_STATE;
					}
					break;
				case PRE_IN_STATE:
					if((code[i] == ',' && left_bracket == 1) || (code[i] == ']' && left_bracket == 0) )
					{
						inputs[num_inputs++] = code + start;
						for(j = i-1; j > start; --j)
							if(!is_whitespace(code[j]))
								break;
						if(code[i] == ',')
							state = BETWEEN_PRE_IN;
						else
							state = BEFORE_WORK;
						code[j+1] = '\0';
					}
					break;
				case BETWEEN_PRE_IN:
					if(code[i] == ']')
					{
						state = BEFORE_WORK;
					}
					else if(!is_whitespace(code[i]))
					{
						start = i;
						state = PRE_IN_STATE;
					}
					break;
				case WORK_STATE:
					if(code[i] == '[' || code[i] == '#' || (code[i] == '|' && code[i+1] == ':') || (code[i] == ':' && code[i+1] == '|') || code[i] == '\n')
					{
						for(j = i-1; j > start; --j)
							if(!is_whitespace(code[j]))
								break;
						
						worker = code+start;
			
						if(code[i] == '[')
						{
							code[j+1] = '\0';
						//	puts("Worker to Between Input");
						//	puts("worker_expr = TRUE;");
							worker_expr = TRUE;
							state = BETWEEN_IN;
						}
						else if(code[i] == '#' || code[i] == '\n')
						{
							code[j+1] = '\0';
						//	puts("Worker to Null State(#)");
							//printf("worker_expr: %d\n", worker_expr);
							if(block_depth)
								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
							else
								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
							num_inputs = 0;
							num_outputs = 0;
							worker_expr = FALSE;
							state = NULL_STATE;
						}
						else if(code[i] == ':')
						{
							code[j+1] = '\0';
							if(block_depth)
								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
							else
								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
							num_inputs = 0;
							num_outputs = 0;
							worker_expr = FALSE;
							state = BLOCK_FIND;
							++i;
						}
						else
						{
							//puts("Worker to Null State(else)");
							code[j+1] = '\0';
							if(block_depth)
								last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
							else
								last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
							block_output[block_depth++] = 0;
							//puts("Found |:, increasinb block depth");
							num_inputs = 0;
							num_outputs = 0;
							worker_expr = FALSE;
							state = NULL_STATE;
							++i;
						}
						
					}
					break;
				case BETWEEN_IN:
					if(code[i] == ']')
					{
						state = AFTER_IN;
					}
					else if(!is_whitespace(code[i]))
					{
						start = i;
						state = IN_STATE;
					}
					break;
				case IN_STATE:
					if((code[i] == ',' && left_bracket == 1) || (code[i] == ']' && left_bracket == 0) )
					{
						inputs[num_inputs++] = code + start;
						for(j = i-1; j > start; --j)
							if(!is_whitespace(code[j]))
								break;
						
						if(code[i] == ',')
							state = BETWEEN_IN;
						else
							state = AFTER_IN;
						code[j+1] = '\0';
					}
					break;
				case AFTER_IN:
					//puts("AFTER_IN test");
					if(code[i] == '\n')
						saw_newline = TRUE;
					if(code[i] == '|' && code[i+1] == ':')
					{
						if(block_depth)
							last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
						else
							last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
						block_output[block_depth++] = 0;
						//puts("Found |: increasing block depth");
						state = NULL_STATE;
						num_inputs = 0;
						num_outputs = 0;
						worker_expr = FALSE;
						++i;
					}
					else if(code[i] == '#')
					{
						if(block_depth)
							last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
						else
							last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
						state = NULL_STATE;
						num_inputs = 0;
						num_outputs = 0;
						worker_expr = FALSE;
					}
					else if(code[i] == '[')
					{
						if(saw_newline)
						{
							if(block_depth)
								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
							else
								last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
							saw_newline = FALSE;
							state = NULL_STATE;
							num_inputs = 0;
							num_outputs = 0;
							worker_expr = FALSE;
							--left_bracket;
							--i;
						}
						else
						{
							puts("Error: Too many input blocks at");
							code[i+1] = '\0';
							for(j = i-1; j > 0; --j)
							if(code[j] == '\n')
							{
								++j;
								break;
							}
							puts(code + j);
							exit(-1);
						}
					}
					else if(!is_whitespace(code[i]))
					{
						if(block_depth)
							last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
						else
							last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
						if(saw_newline)
						{
							saw_newline = FALSE;
							num_inputs = 0;
						}
						else
						{
							num_inputs = 1;
							inputs[0] = NULL;
						}
						state = NULL_STATE;
						
						num_outputs = 0;
						worker_expr = FALSE;
						--i;
					}
					break;
				case BLOCK_FIND:
					if(code[i] == '|' && code[i+1] == ':')
					{
						//puts("Found |: increasing output number (not block depth)");
						++block_output[block_depth-1];
						++i;
						state = NULL_STATE;
					}
					else if(!is_whitespace(code[i]))
					{
						//puts("Found :| without another |: following; decreasing block depth");
						--block_depth;
						if(code[i] == '[')
							--left_bracket;
						--i;
						num_inputs = 0;
						state = NULL_STATE;
						
					}
					break;
				case LINE_COMMENT_STATE:
					if(code[i+1] == '\n')
					{
						for(;line_comment_start <= i; ++line_comment_start)
							code[line_comment_start] = ' ';
						state = old_state;
					}
					break;
				}
			}
			if(do_curly)
			{
				++left_curly;
				do_curly = FALSE;
			}
		}
		else if(literal)
			literal = FALSE;
		else if(code[i] == '"')
			in_string = FALSE;
		else if(code[i] == '\\')
			literal = TRUE;
	}
	//printf("State at end of code chunk: %s(%d)\n", state_txt[state], state);
	if((state != BLOCK_FIND && block_depth != 0) || (state == BLOCK_FIND && block_depth > 1))
	{
		ERRORPRINTF("Syntax Error: Missing %d block close symbol(s) (:|)\n", block_depth);
		exit(-1);
	}
	else
	{
		switch(state)
		{
			case WORK_STATE:
				for(j = i-1; j > start; --j)
					if(!is_whitespace(code[j]))
						break;
					
				worker = code+start;
				code[j+1] = '\0';
			case AFTER_IN:
				if(block_depth)
					last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker);
				else
					last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker);
				break;
			case BLOCK_FIND:
			case NULL_STATE:
				break;
			default:
				printf("Syntax Error: State is %s but there are no more characters left to process.\n", state_txt[state]);
				puts(code + start);
				exit(-1);
		}
	}
	return last_worker;
}
typedef struct parse_worker
{
	char * worker_name;
	int num_inputs;
	int num_outputs;
	worker_def * def;
	char * block;
	int block_len;
	struct parse_worker * next;
} parse_worker;

void parse_company(char * name, char * code, int len, program * prog)
{
	char * type_name;
	char * field_name;
	int i;
	int part_start;
	int part_end;
	int type;
	company * comp;
	BOOL saw_newline;
	field_name = type_name = NULL;
	comp = create_company(prog, name, 0, 0, TRUE);
	i = 0;
	while(i < len)
	{
		saw_newline = FALSE;
		part_start = -1;
		for(; i < len; ++i)
		{
			DEBUGPRINTF("i: %d, code[i]: %c ", i, code[i]);
			if(part_start < 0)
			{
				if(!is_whitespace(code[i]))
					part_end = part_start = i;
			}
			else if(code[i] == ':' && code[i-1] == ':')
			{
				type_name = code + part_start;
				type_name[part_end - part_start-1] = '\0';
				part_start = -1;
				++i;
				break;
			}
			else if(!is_whitespace(code[i]))
			{
				DEBUGPUTS("Not whitespace\n");
				if(saw_newline)
				{
					code[part_end] = '\0';
					add_comp_room(comp, code + part_start, -1, -1, ROOM_VIS_REF, ROOM_VIS_REF);
					--i;
					part_start = -1;
					saw_newline = FALSE;
				}
				else
					part_end = i+1;
			}
				
			else if(code[i] == '\n')
			{
				DEBUGPUTS("saw newline\n");
				saw_newline = TRUE;
			}
		}
		if(i >= len && part_start >= 0 && part_end > part_start)
		{
			code[part_end] = '\0';
			add_comp_room(comp, code + part_start, -1, -1, ROOM_VIS_REF, ROOM_VIS_REF);
			part_start = -1;
		}
		for(; i < len; ++i)
		{
			DEBUGPRINTF("i: %d, code[i]: %c ", i, code[i]);
			if(part_start < 0)
			{
				if(!is_whitespace(code[i]))
					part_end = part_start = i;
				DEBUGPRINTF("part_start: %d\n", part_start);
			}
			else if(!is_whitespace(code[i]))
			{
				DEBUGPRINTF("part_end: %d\n", part_end);
				part_end = i+1;
			}
			else if(code[i] == '\n')
			{
				DEBUGPRINTF("saw newline, type name: %s\n", type_name);
				if(!strcmp("Byte", type_name))
					type = ROOM_BYTE;
				else if(!strcmp("Word", type_name))
					type = ROOM_SHORT;
				else if(!strcmp("Long", type_name))
					type = ROOM_LONG;
				else
					type = ROOM_VIS_REF;
				code[part_end] = '\0';
				add_comp_room(comp, code + part_start, -1, -1, type, type);
				break;
			}
		}
	}
	if(part_start >= 0 && part_end > part_start)
	{
		if(!strcmp("Byte", type_name))
			type = ROOM_BYTE;
		else if(!strcmp("Word", type_name))
			type = ROOM_SHORT;
		else if(!strcmp("Long", type_name))
			type = ROOM_LONG;
		else
			type = ROOM_VIS_REF;
		code[part_end] = '\0';
		add_comp_room(comp, code + part_start, -1, -1, type, type);
	}
}

void import(char * filename, program * prog)
{
	int size;
	char * code;
	FILE * imp;
	imp = fopen(filename, "rb");
	if(imp)
	{
		fseek(imp, 0, SEEK_END);
		size = ftell(imp);
		fseek(imp, 0, SEEK_SET);
		code = MALLOC(size, "code from imported file");
		fread(code, 1, size, imp);
		DEBUGPRINTF("Read %d bytes\n", size);
		parse(code, size, prog);
		DEBUGPUTS("Finished parsing import file\n");
		VIS_FREE(code, "code buffer");
		fclose(imp);
	}
	else
	{
		ERRORPRINTF("Warning: Could not open import file: %s\n", filename);
	}
}

typedef enum {NULL_PARSE, WORKER_STATE, BLOCK_STATE, STRING_STATE, LITERAL_STATE, LIST_STATE, LIST_STRING, LIST_LITERAL, LINE_COMMENT} super_state;
char super_state_txt[9][30] = {"Null", "Worker", "Block", "String", "String Literal", "List", "String in List", "String Literal in List", "Single Line Comment"};
void parse(char * code, int len, program * prog)
{
	parse_worker *list=NULL, *current=NULL, *temp;
	short saw_line = 0;
	int i,j,k;
	int block_count = 0;
	int start;
	int end;
	int num_inputs;
	int num_outputs;
	int company_len, import_len;
	char * worker_name;
	int left_curly=0;
	int block_done = -1;
	int comp_start, comp_end;
	char * company_name;
	char * comp_block;
	int comp_block_len;
	int num_uses;
	char * importfiles[32];
	int num_imported = 0;
	super_state old_state;
	char ** uses_names = NULL;
	BOOL lastwasspace = FALSE;
	super_state state = NULL_PARSE;
	company_len = strlen("Company");
	import_len = strlen("Import");
	for(i = 0; i < len; ++i)
	{
		DEBUGPRINTF("i: %d, code[i]: %c, state: %s(%d)\n", i, code[i], super_state_txt[state], state);
		if(code[i] == '/' && code[i+1] == '/' && state != STRING_STATE && state != LIST_STRING)
		{
			old_state = state;
			state = LINE_COMMENT;
			i += 2;
		}
		switch(state)
		{
			case NULL_PARSE:
				if(len - i >= import_len && !memcmp("Import", code + i, import_len))
				{
					start = end = -1;
					for(j = i+import_len; j < len && code[j] != '\n'; ++j)
					{
						if(start < 0)
						{
							if(!is_whitespace(code[j]))
								start = j; 
						}
						else
						{
							if(!is_whitespace(code[j]))
								end = j;
						}
					}
					if(end < 0)
					{
						puts("Error: Import statement with no file name");
						exit(-1);
					}
					++end;
					code[end] = '\0';
					i = end;
					if(num_imported < 32)
						importfiles[num_imported++] = code+start;
					else
					{
						puts("Error: You cannot have more than 32 import statements in the same file");
						exit(-1);
					}
				}
				else if(code[i] == ':' && code[i+1] == '|')
				{
					start = i;
					while((code[i] != '\n' || saw_line < 5) && i < len)
					{
						if(code[i] == '\n')
							++saw_line;
						++i;
					}
					code[i] = '\0';
					ERRORPRINTF("Error: Unexpected closing bracket (:|) found:\n%s", code + start);
					exit(-1);
				}
				else if(!is_whitespace(code[i]))
				{
					start = i;
					state = WORKER_STATE;
				}
				break;
			case WORKER_STATE:
				if(is_whitespace(code[i]))
					lastwasspace = TRUE;
				else if(code[i] == '|' && code[i+1] == ':')
				{
					if(!strncmp(code+start, "Company",company_len) && is_whitespace(code[start+company_len]))
					{
						comp_start = -1;
						comp_end = 0;
						for(j = start+company_len+1; j < len-1; ++j)
						{
							if(comp_start >= 0)
							{
								if(code[j] == '|' && code[j+1] == ':')
									break;
								else if(!is_whitespace(code[j]))
									comp_end = j+1;
							}
							else
							{
								if(!is_whitespace(code[j]))
									comp_start = j;
							}
						}
						if(comp_start >= 0 && comp_end > comp_start)
						{
							company_name = code + comp_start;
							code[comp_end] = '\0';
							comp_start = -1;
							for(j = comp_end+1; j < len-1; ++j)
							{
								if(comp_start < 0)
								{
									if(code[j] == '|' && code[j+1] == ':')
										comp_start = j+2;
								}
								else
								{
									if(code[j] == ':' && code[j+1] == '|')
									{
										comp_end = j;
										break;
									}
								}
							}
							if(comp_start > 0)
							{
								comp_block = code+comp_start;
								comp_block_len = comp_end-comp_start;
								DEBUGPRINTF("Company block start: %d, end: %d, length: %d\n", comp_start, comp_end, comp_block_len);
								code[comp_end] = '\0';
								i = comp_end+1;
								parse_company(company_name, comp_block, comp_block_len, prog);
							}
							else
							{
								printf("Error parsing Company, comp_start is %d\n", comp_start);
							}
							
						}
						else
						{
							puts("Error parsing Company\n");
						}
						state = NULL_STATE;
						
					}
					else
					{
						for(j = i-1; j > start; --j)
							if(code[j] != ' ' && code[j] != '\t' && code[j] != '\n' && code[j] != '\r')
								break;
						for(k = start; k <= j; ++k)
							if(code[k] == '(')
							{
								code[k] = '\0';
								num_inputs = atol(code + k + 1);
							}
							else if(code[k] == ',')
								num_outputs = atol(code + k + 1);
						worker_name = code + start;
						//printf("Found worker def: %s with %d outputs and %d inputs\n", worker_name, num_outputs, num_inputs);
						start = i+2;
						++i;
						num_uses = 0;
						state = BLOCK_STATE;
					}
				}
				else if(lastwasspace && !strncmp(code+i, "uses", 4))
				{
					for(j = i-1; j > start; --j)
						if(code[j] != ' ' && code[j] != '\t' && code[j] != '\n' && code[j] != '\r')
							break;
					for(k = start; k <= j; ++k)
						if(code[k] == '(')
						{
							code[k] = '\0';
							num_inputs = atol(code + k + 1);
						}
						else if(code[k] == ',')
							num_outputs = atol(code + k + 1);
					worker_name = code + start;
					num_uses = 1;
					for(j = i + strlen("uses"); code[j] != '|' && j < len; ++j)
						if(code[j] == ',')
							++num_uses;
					DEBUGPRINTF("num_uses: %d\n", num_uses);
					i += strlen("uses");
					uses_names = MALLOC(sizeof(char *) * num_uses, "uses stores names");
					end = -1;
					start = i;
					j = 0;
					while(code[i] != '|' && i < len)
					{
						if(code[i] == ',')
						{
							uses_names[j] = MALLOC(sizeof(char) * (end-start+1), "global store name for uses stores");
							memcpy(uses_names[j], code+start, end-start);
							uses_names[j][end-start] = '\0';
							DEBUGPRINTF("uses: %s\n", uses_names[j]);
							end = -1;
							++j;
						}
						else if(code[i] != ' ' && code[i] != '\t' && code[i] != '\r' && code[i] != '\n')
							end = i+1;
						else if(end < 0)
							start = i+1;
						++i;
					}
					if(end >= 0)
					{
						uses_names[j] = MALLOC(sizeof(char) * (end-start+1), "global store name for uses stores");
						memcpy(uses_names[j], code+start, end-start);
						uses_names[j][end-start] = '\0';
						DEBUGPRINTF("uses: %s\n", uses_names[j]);
						end = -1;
						++j;
					}
					start = i+2;
					++i;
					state = BLOCK_STATE;
					
				}
				break;
			case BLOCK_STATE:
				//printf("Block count: %d\n", block_count);
				if((i-block_done)>1 && code[i] == ':' && code[i-1] == '|')
				{
					++block_count;
				}
				else if(code[i] == '"') {
					state = STRING_STATE;
				}
				else if(code[i] == '{') {
					state = LIST_STATE;
				}
				else if(code[i] == '|' && code[i-1] == ':')
				{
					if(block_count == 0)
					{
						if(current)
						{
							current->next = MALLOC(sizeof(parse_worker),"parse worker");
							current = current->next;
						}
						else
						{
							list = current = MALLOC(sizeof(parse_worker),"parse worker");
						}
						current->num_inputs = num_inputs;
						current->num_outputs = num_outputs;
						current->worker_name = worker_name;
						current->block = code + start;
						current->block_len = i-start-1;
						current->next = NULL;
						current->def = create_worker(prog, current->worker_name, current->num_inputs, current->num_outputs, USER_FLAG | WORKER_TYPE);
						current->def->uses_stores = uses_names;
						current->def->num_stores = num_uses;
						uses_names = NULL;
						num_uses = 0;
						state = NULL_PARSE;
						block_done = -1;
					}
					else
					{
						block_done = i;
						--block_count;
					}
				}
				break;
			case STRING_STATE:
				if(code[i] == '\\')
					state = LITERAL_STATE;
				else if(code[i] == '"')
					state = BLOCK_STATE;
				break;
			case LITERAL_STATE:
				state = STRING_STATE;
				break;
			case LIST_STATE:
				if(code[i] == '{')
					++left_curly;
				else if(code[i] == '}')
					if(left_curly)
						--left_curly;
					else
						state = BLOCK_STATE;
				else if(code[i] == '"')
					state = LIST_STRING;
				break;
			case LIST_STRING:
				if(code[i] == '\\')
					state = LIST_LITERAL;
				else if(code[i] == '"')
					state = LIST_STATE;
				break;
			case LIST_LITERAL:
				state = LIST_STRING;
				break;
			case LINE_COMMENT:
				if(code[i+1] == '\n')
					state = old_state;
				break;
		}
	}
	if(state != NULL_PARSE)
	{
		printf("Error: Current parse state is %s(%d) in first pass but there are no more characters to parse.\n", super_state_txt[state], state);
		if(state == BLOCK_STATE)
		{
			printf("Worker %s appears to be missing a closing bracket (:|)\n", worker_name);
		}
		exit(-3);
	}
	for(i = 0; i < num_imported; ++i)
	{
		import(importfiles[i], prog);
	}
	current = list;
	while(current)
	{
		DEBUGPRINTF("Processing worker %s with %d inputs and %d outputs\n\n", current->worker_name, current->num_inputs, current->num_outputs);
		parse_body(current->def, current->block, current->block_len, 0, NULL, NULL);
		temp = current;
		current = current->next;
		free(temp);
	}
}