view parser.c @ 184:c6ba9fe45910

Strip _c from filenames of current compiler
author Mike Pavone <pavone@retrodev.com>
date Wed, 27 Jul 2011 21:28:43 -0700
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);
	}
}