// Base Compiler (0fh)
// 
// Copyright (c) 2000-2005, Darran Kartaschew
// All rights reserved.
// 
// Licence
// -------
// 
// Copyright (c) 2000-2005, Darran Kartaschew
// All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
// 
// *  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
// 
// *  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
// 
// *  Neither the name of "0fh" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// 
#define POSIX
#include <stdio.h>
#include <time.h>

// Extern stdlib functions:
//   printf();
//   fgetc();
//	 strcpy();
//	 strcmp();
//   strcat();
//   strrchr();
//   fprintf();
//   fopen();
//   fclose();
//   rewind();
//   _unlink();
//   clock();
//   isdigit();
//   isxdigit();
//   __iscsymf();
//   tolower();

#define TOKEN_STACK_SIZE 1024
#define HASH_TABLE_SIZE 250007
						//Size of the hash table.
#define TOKEN_MAX_SIZE 256
#define HASH_OFFSET 0x10000000
						//Offset used to store hash within token stack
#define MAX_LIB_DEPTH 32
						// Allow up to 32 deep
						
#define PATHS_MAX 256	
						// Allow up to 256 paths to held for searching for
						// includes.
#define CR 0xa
#define LF 0xd
#define TAB 0x9
#define SP 0x20

#define SOURCE_FLAT 0
#define SOURCE_0F 1
#define SOURCE_ELF 2
#define SOURCE_PE 3

#define TOKEN_OFFSET        	0x1000000
#define TOKEN_AND    			TOKEN_OFFSET + 0x0001
#define TOKEN_OR     			TOKEN_OFFSET + 0x0002
#define TOKEN_XOR	 			TOKEN_OFFSET + 0x0003
#define TOKEN_NOT	 			TOKEN_OFFSET + 0x0004
#define TOKEN_EQUATE 			TOKEN_OFFSET + 0x0005
#define TOKEN_ADD    			TOKEN_OFFSET + 0x0006
#define TOKEN_MINUS  			TOKEN_OFFSET + 0x0007
#define TOKEN_MULTIPLY 			TOKEN_OFFSET + 0x0008
#define TOKEN_DIVIDE 			TOKEN_OFFSET + 0x0009
#define TOKEN_MODULUS 			TOKEN_OFFSET + 0x000a
#define TOKEN_S_MULTIPLY 		TOKEN_OFFSET + 0x000b
#define TOKEN_S_DIVIDE 			TOKEN_OFFSET + 0x000c
#define TOKEN_S_MODULUS 		TOKEN_OFFSET + 0x000d
#define TOKEN_RROTATE 			TOKEN_OFFSET + 0x000e
#define TOKEN_LROTATE 			TOKEN_OFFSET + 0x000f
#define TOKEN_RSHIFT 			TOKEN_OFFSET + 0x0010
#define TOKEN_LSHIFT 			TOKEN_OFFSET + 0x0011

#define TOKEN_EQUALS 				TOKEN_OFFSET + 0x0020
#define TOKEN_NOTEQUALS 			TOKEN_OFFSET + 0x0021
#define TOKEN_S_LESSTHANEQUALS 		TOKEN_OFFSET + 0x0022
#define TOKEN_S_GREATERTHANEQUALS	TOKEN_OFFSET + 0x0023
#define TOKEN_S_LESSTHAN 			TOKEN_OFFSET + 0x0024
#define TOKEN_S_GREATERTHAN 		TOKEN_OFFSET + 0x0025
#define TOKEN_LESSTHANEQUALS 		TOKEN_OFFSET + 0x0026
#define TOKEN_GREATERTHANEQUALS		TOKEN_OFFSET + 0x0027
#define TOKEN_LESSTHAN 				TOKEN_OFFSET + 0x0028
#define TOKEN_GREATERTHAN 			TOKEN_OFFSET + 0x0029

#define TOKEN_COMMA			TOKEN_OFFSET + 0x0030
#define TOKEN_BLOCK_END		TOKEN_OFFSET + 0x0031

#define TOKEN_STRING 		TOKEN_OFFSET + 0x0040
#define TOKEN_END_STRING 	TOKEN_OFFSET + 0x0041
#define TOKEN_PARA_START 	TOKEN_OFFSET + 0x0042
#define TOKEN_PARA_END 		TOKEN_OFFSET + 0x0043

#define TOKEN_POINTER 		TOKEN_OFFSET + 0x0050
#define TOKEN_ARRAY_START 	TOKEN_OFFSET + 0x0051
#define TOKEN_ARRAY_END 	TOKEN_OFFSET + 0x0052

//Predefined hashes for reserved keywords.
//WARNING: If you modify the hash function, or change the hash table
// size, you will NEED TO RECALCULATE these values.

#define HASH_r0 			0x751
#define HASH_r1 			0x752
#define HASH_r2 			0x753
#define HASH_r3 			0x754
#define HASH_r4 			0x755
#define HASH_r5 			0x756
#define HASH_r6 			0x757
#define HASH_r7 			0x758
#define HASH_r8 			0x759
#define HASH_r9 			0x75a
#define HASH_r10 			0x7541
#define HASH_r11 			0x7542
#define HASH_r12 			0x7543
#define HASH_r13 			0x7544
#define HASH_r14 			0x7545
#define HASH_r15 			0x7546

#define HASH_r0b 			0x7563
#define HASH_r1b 			0x7573
#define HASH_r2b 			0x7583
#define HASH_r3b 			0x7593
#define HASH_r4b 			0x75a3
#define HASH_r5b 			0x75b3
#define HASH_r6b 			0x75c3
#define HASH_r7b 			0x75d3
#define HASH_r8b 			0x75e3
#define HASH_r9b 			0x75f3
#define HASH_r10b 			0x383cc
#define HASH_r11b 			0x383dc
#define HASH_r12b 			0x383ec
#define HASH_r13b			0x383fc
#define HASH_r14b 			0x3840c
#define HASH_r15b 			0x3841c

#define HASH_r0w 			0x7578
#define HASH_r1w 			0x7588
#define HASH_r2w 			0x7598
#define HASH_r3w 			0x75a8
#define HASH_r4w 			0x75b8
#define HASH_r5w 			0x75c8
#define HASH_r6w 			0x75d8
#define HASH_r7w 			0x75e8
#define HASH_r8w 			0x75f8
#define HASH_r9w 			0x7608
#define HASH_r10w 			0x383e1
#define HASH_r11w 			0x383f1
#define HASH_r12w 			0x38401
#define HASH_r13w 			0x38411
#define HASH_r14w 			0x38421
#define HASH_r15w 			0x38431

#define HASH_r0d 			0x7565
#define HASH_r1d 			0x7575
#define HASH_r2d 			0x7585
#define HASH_r3d 			0x7595
#define HASH_r4d 			0x75a5
#define HASH_r5d 			0x75b5
#define HASH_r6d 			0x75c5
#define HASH_r7d 			0x75d5
#define HASH_r8d 			0x75e5
#define HASH_r9d 			0x75f5
#define HASH_r10d 			0x383ce
#define HASH_r11d 			0x383de
#define HASH_r12d 			0x383ee
#define HASH_r13d 			0x383fe
#define HASH_r14d 			0x3840e
#define HASH_r15d 			0x3841e

#define HASH_fp0			0x6d31
#define HASH_fp1			0x6d32
#define HASH_fp2			0x6d33
#define HASH_fp3			0x6d34
#define HASH_fp4			0x6d35
#define HASH_fp5			0x6d36
#define HASH_fp6			0x6d37
#define HASH_fp7			0x6d38

#define HASH_zero			0x0031

#define HASH_m8 			0x709
#define HASH_m16 			0x7047
#define HASH_m32 			0x7063
#define HASH_m64 			0x7095
#define HASH_m80			0x70b1
#define HASH_m128			0x333c2
#define HASH_m256			0x334f0
#define HASH_m512			0x337ac

#define HASH_proc 			0x3a8bd
#define HASH_return 		0x27219
#define HASH_exit 			0x2fe6e
#define HASH_asm 			0x689e
#define HASH_while 			0xcaf
#define HASH_lib 			0x72f3
#define HASH_if 			0x6f7
#define HASH_else			0x2f2ff
#define HASH_push			0x3ac02
#define HASH_pop			0x7761
#define HASH_syscall		0x2a3e1
#define HASH_sysret			0x3869

#define TYPE_M8				0x0001
#define TYPE_M16			0x0002
#define TYPE_M32			0x0003
#define TYPE_M64			0x0004
#define TYPE_M80			0x0005
#define TYPE_M128			0x0006
#define TYPE_M256			0x0007
#define TYPE_M512			0x0008

#define TYPE_ARRAY			0x0010
#define TYPE_PROC			0x0020
#define TYPE_KEYWORD		0x0040

#define TYPE_REG			0x0100
#define TYPE_REG_FPU		0x0200
#define TYPE_REG_SHORT		0x0400

#define TYPE_LOCAL			0x1000
#define TYPE_GLOBAL			0x2000

typedef struct{
	unsigned long hash;
	unsigned char token[TOKEN_MAX_SIZE];
	unsigned int token_type;
	unsigned int local_offset;
} hash_table_struc;

typedef struct{
	unsigned int type;
	unsigned int offset;
	unsigned long if_while_test1;
	unsigned long if_while_test2;
	unsigned long comparison;
} if_while_struc;

typedef struct{
	FILE *handle;
	unsigned char filename[FILENAME_MAX];
	unsigned int line_count;
} file_struct;

int ch;						//current character in queue
int look_ahead_ch;				//look ahead character
file_struct file[MAX_LIB_DEPTH] = { 0 };
								//Lib / Include stack
int file_stack_ptr;				//Pointer into the file stack
FILE *code;						//pointer to code output file
FILE *data;						//pointer to data output file

unsigned int state;				//current instruction state
unsigned int line_count;		//current line in source
unsigned int token_stack[TOKEN_STACK_SIZE] = { 0 };		
								//Stack containing the current tokens to be processed.
unsigned int token;				//Pointer to current token within token stack;
unsigned int global;			//Are we at a global level?
								// If zero, we are global otherwise = hash of proc
								// we are in.
unsigned int target;			// Target Register of line (contains hash).
unsigned int block_level = 0;	//Indentation level
hash_table_struc hash_table[HASH_TABLE_SIZE];			
								//hash table
unsigned long token_hash;		//Hash of current token
unsigned char token_buffer[TOKEN_MAX_SIZE];	
								//Buffer for tokens
unsigned int toki; 				// index into above buffer.
unsigned char filename[FILENAME_MAX];
								//Filename for when opening a file.
unsigned char tmp_filename[FILENAME_MAX];
								//Temp filename used when searching includes.
char *path;
char *b0_env;
int total_paths;
char paths[PATHS_MAX][FILENAME_MAX]; // allow upto 256 paths to be searched.
								
unsigned int asm_in_string;		//Flag used to see in if string within
								// asm block.

if_while_struc if_while_stack[TOKEN_STACK_SIZE] = { 0 };
								//Stack which holds the current block type
								//Index by block_level
unsigned int block_num;			//number of occurance of block.
int local_var_offset;
int dynamic_string_count;		//Count of the dynamic string decl.
clock_t time_start, time_end;
double duration;

int DEBUG = 0;						// Whether to output debugging output.

int SOURCE_TYPE = SOURCE_FLAT;		// Default Source is flat output.

unsigned char B0_VERSION[] = {"0.0.6"};
unsigned char TOKEN_IF[TOKEN_MAX_SIZE] = { "if" };
unsigned char TOKEN_ELSE[TOKEN_MAX_SIZE] = { "else" };
unsigned char TOKEN_WHILE[TOKEN_MAX_SIZE] = { "while" };
unsigned char TOKEN_LIB[TOKEN_MAX_SIZE] = { "lib" };
unsigned char TOKEN_ASM[TOKEN_MAX_SIZE] = { "asm" };
unsigned char TOKEN_RETURN[TOKEN_MAX_SIZE] = { "return" };
unsigned char TOKEN_EXIT[TOKEN_MAX_SIZE] = { "exit" };
unsigned char TOKEN_PROC[TOKEN_MAX_SIZE] = { "proc" };
unsigned char TOKEN_PUSH[TOKEN_MAX_SIZE] = { "push" };
unsigned char TOKEN_POP[TOKEN_MAX_SIZE] = { "pop" };
unsigned char TOKEN_SYSCALL[TOKEN_MAX_SIZE] = { "syscall" };
unsigned char TOKEN_SYSRET[TOKEN_MAX_SIZE] = { "sysret" };

unsigned char TOKEN_R0[TOKEN_MAX_SIZE] = { "r0" };
unsigned char TOKEN_R1[TOKEN_MAX_SIZE] = { "r1" };
unsigned char TOKEN_R2[TOKEN_MAX_SIZE] = { "r2" };
unsigned char TOKEN_R3[TOKEN_MAX_SIZE] = { "r3" };
unsigned char TOKEN_R4[TOKEN_MAX_SIZE] = { "r4" };
unsigned char TOKEN_R5[TOKEN_MAX_SIZE] = { "r5" };
unsigned char TOKEN_R6[TOKEN_MAX_SIZE] = { "r6" };
unsigned char TOKEN_R7[TOKEN_MAX_SIZE] = { "r7" };
unsigned char TOKEN_R8[TOKEN_MAX_SIZE] = { "r8" };
unsigned char TOKEN_R9[TOKEN_MAX_SIZE] = { "r9" };
unsigned char TOKEN_R10[TOKEN_MAX_SIZE] = { "r10" };
unsigned char TOKEN_R11[TOKEN_MAX_SIZE] = { "r11" };
unsigned char TOKEN_R12[TOKEN_MAX_SIZE] = { "r12" };
unsigned char TOKEN_R13[TOKEN_MAX_SIZE] = { "r13" };
unsigned char TOKEN_R14[TOKEN_MAX_SIZE] = { "r14" };
unsigned char TOKEN_R15[TOKEN_MAX_SIZE] = { "r15" };

unsigned char TOKEN_R0B[TOKEN_MAX_SIZE] = { "r0b" };
unsigned char TOKEN_R1B[TOKEN_MAX_SIZE] = { "r1b" };
unsigned char TOKEN_R2B[TOKEN_MAX_SIZE] = { "r2b" };
unsigned char TOKEN_R3B[TOKEN_MAX_SIZE] = { "r3b" };
unsigned char TOKEN_R4B[TOKEN_MAX_SIZE] = { "r4b" };
unsigned char TOKEN_R5B[TOKEN_MAX_SIZE] = { "r5b" };
unsigned char TOKEN_R6B[TOKEN_MAX_SIZE] = { "r6b" };
unsigned char TOKEN_R7B[TOKEN_MAX_SIZE] = { "r7b" };
unsigned char TOKEN_R8B[TOKEN_MAX_SIZE] = { "r8b" };
unsigned char TOKEN_R9B[TOKEN_MAX_SIZE] = { "r9b" };
unsigned char TOKEN_R10B[TOKEN_MAX_SIZE] = { "r10b" };
unsigned char TOKEN_R11B[TOKEN_MAX_SIZE] = { "r11b" };
unsigned char TOKEN_R12B[TOKEN_MAX_SIZE] = { "r12b" };
unsigned char TOKEN_R13B[TOKEN_MAX_SIZE] = { "r13b" };
unsigned char TOKEN_R14B[TOKEN_MAX_SIZE] = { "r14b" };
unsigned char TOKEN_R15B[TOKEN_MAX_SIZE] = { "r15b" };

unsigned char TOKEN_R0W[TOKEN_MAX_SIZE] = { "r0w" };
unsigned char TOKEN_R1W[TOKEN_MAX_SIZE] = { "r1w" };
unsigned char TOKEN_R2W[TOKEN_MAX_SIZE] = { "r2w" };
unsigned char TOKEN_R3W[TOKEN_MAX_SIZE] = { "r3w" };
unsigned char TOKEN_R4W[TOKEN_MAX_SIZE] = { "r4w" };
unsigned char TOKEN_R5W[TOKEN_MAX_SIZE] = { "r5w" };
unsigned char TOKEN_R6W[TOKEN_MAX_SIZE] = { "r6w" };
unsigned char TOKEN_R7W[TOKEN_MAX_SIZE] = { "r7w" };
unsigned char TOKEN_R8W[TOKEN_MAX_SIZE] = { "r8w" };
unsigned char TOKEN_R9W[TOKEN_MAX_SIZE] = { "r9w" };
unsigned char TOKEN_R10W[TOKEN_MAX_SIZE] = { "r10w" };
unsigned char TOKEN_R11W[TOKEN_MAX_SIZE] = { "r11w" };
unsigned char TOKEN_R12W[TOKEN_MAX_SIZE] = { "r12w" };
unsigned char TOKEN_R13W[TOKEN_MAX_SIZE] = { "r13w" };
unsigned char TOKEN_R14W[TOKEN_MAX_SIZE] = { "r14w" };
unsigned char TOKEN_R15W[TOKEN_MAX_SIZE] = { "r15w" };

unsigned char TOKEN_R0D[TOKEN_MAX_SIZE] = { "r0d" };
unsigned char TOKEN_R1D[TOKEN_MAX_SIZE] = { "r1d" };
unsigned char TOKEN_R2D[TOKEN_MAX_SIZE] = { "r2d" };
unsigned char TOKEN_R3D[TOKEN_MAX_SIZE] = { "r3d" };
unsigned char TOKEN_R4D[TOKEN_MAX_SIZE] = { "r4d" };
unsigned char TOKEN_R5D[TOKEN_MAX_SIZE] = { "r5d" };
unsigned char TOKEN_R6D[TOKEN_MAX_SIZE] = { "r6d" };
unsigned char TOKEN_R7D[TOKEN_MAX_SIZE] = { "r7d" };
unsigned char TOKEN_R8D[TOKEN_MAX_SIZE] = { "r8d" };
unsigned char TOKEN_R9D[TOKEN_MAX_SIZE] = { "r9d" };
unsigned char TOKEN_R10D[TOKEN_MAX_SIZE] = { "r10d" };
unsigned char TOKEN_R11D[TOKEN_MAX_SIZE] = { "r11d" };
unsigned char TOKEN_R12D[TOKEN_MAX_SIZE] = { "r12d" };
unsigned char TOKEN_R13D[TOKEN_MAX_SIZE] = { "r13d" };
unsigned char TOKEN_R14D[TOKEN_MAX_SIZE] = { "r14d" };
unsigned char TOKEN_R15D[TOKEN_MAX_SIZE] = { "r15d" };

unsigned char TOKEN_FP0[TOKEN_MAX_SIZE] = { "fp0" };
unsigned char TOKEN_FP1[TOKEN_MAX_SIZE] = { "fp1" };
unsigned char TOKEN_FP2[TOKEN_MAX_SIZE] = { "fp2" };
unsigned char TOKEN_FP3[TOKEN_MAX_SIZE] = { "fp3" };
unsigned char TOKEN_FP4[TOKEN_MAX_SIZE] = { "fp4" };
unsigned char TOKEN_FP5[TOKEN_MAX_SIZE] = { "fp5" };
unsigned char TOKEN_FP6[TOKEN_MAX_SIZE] = { "fp6" };
unsigned char TOKEN_FP7[TOKEN_MAX_SIZE] = { "fp7" };

unsigned char TOKEN_ZERO[TOKEN_MAX_SIZE] = { "0" };

unsigned char TOKEN_M8[TOKEN_MAX_SIZE] = { "m8" };
unsigned char TOKEN_M16[TOKEN_MAX_SIZE] = { "m16" };
unsigned char TOKEN_M32[TOKEN_MAX_SIZE] = { "m32" };
unsigned char TOKEN_M64[TOKEN_MAX_SIZE] = { "m64" };
unsigned char TOKEN_M80[TOKEN_MAX_SIZE] = { "m80" };
unsigned char TOKEN_M128[TOKEN_MAX_SIZE] = { "m128" };
unsigned char TOKEN_M256[TOKEN_MAX_SIZE] = { "m256" };
unsigned char TOKEN_M512[TOKEN_MAX_SIZE] = { "m512" };

unsigned int getChar(){
	ch = look_ahead_ch;
	if (ch == CR) 
		file[file_stack_ptr].line_count++;
	look_ahead_ch = fgetc(file[file_stack_ptr].handle);
	if(DEBUG)
		printf("ch=%c 0x%x, lch=%c 0x%x\n", ch, ch, look_ahead_ch, look_ahead_ch);
	return(0);
}

unsigned int isAlpha(char s){
	if (__iscsymf(s)){
		return(1);
	} else {
		return(0);
	}
}

unsigned int abort(const char *s){
	int i;
	printf("Error: %s\n",s);
	printf("Char: %c Token: %d Filename: %s Line: %d.\n",ch,token,file[file_stack_ptr].filename, file[file_stack_ptr].line_count);
	time_end = clock();
	duration = (double)(time_end - time_start) / CLOCKS_PER_SEC;
	printf( "Processing Time: %2.3f seconds\n", duration );
	exit(1);
	return(0);
}

unsigned int isSpace(char s){
	if (s == SP | s == CR | s == 0 | s == TAB){
		return(1);
	} else {
		return(0);
	}
}

/*--- ElfHash ---------------------------------------------------
 *  The published hash algorithm used in the UNIX ELF format
 *  for object files. Accepts a pointer to a string to be hashed
 *  and returns an unsigned long.
 *-------------------------------------------------------------*/
unsigned long ElfHash ( const unsigned char *name ){
    unsigned long   h = 0, g;
    while ( *name )
    {
        h = ( h << 4 ) + *name++;
        if ( g = h & 0xF0000000 )
            h ^= g >> 24;
        h &= ~g;
    }
    return h;
}

void insert_token( const unsigned char *name, unsigned int token_type ){
	token_hash = (ElfHash(name)) % HASH_TABLE_SIZE + 1;
	if (token_hash >= (HASH_TABLE_SIZE-1)) token_hash = 1;
	hash_table[token_hash].hash = token_hash;
	strcpy(&hash_table[token_hash].token, name);
	hash_table[token_hash].token_type = token_type;	
	if(DEBUG)
		printf("TOKEN : %s = 0x%x\n", hash_table[token_hash].token, hash_table[token_hash].hash);
}

void insert_token_stack( unsigned int _token) {
	token_stack[token] = _token;
	token++;
	if (token >= TOKEN_STACK_SIZE) 
		abort("INTERNAL: Token Stack Overflow!");
}

unsigned int atStackStart(){
	if ( token != 0)
		abort("Invalid construct");
	token++;
	return(1);
}

unsigned int atStackEnd(int i){
	if (token != i) 
		abort("Unexpected expression/token");
	return(1);
}

unsigned int TokenIsLabelType(int i){
	if (token_stack[token] < HASH_OFFSET)
		abort("Expected Token/Label");
	if ((hash_table[token_stack[token]-HASH_OFFSET].token_type & i) != i) {
		switch(i) {
			case TYPE_REG: abort("64bit Register Expected"); break;
			case TYPE_REG_FPU: abort("FPU Register Expected"); break;
			case TYPE_REG_SHORT: abort("non-64bit Register Expected"); break;
			case TYPE_KEYWORD: abort("Keyword Expected"); break;
			case TYPE_PROC: abort("Procedure Expected"); break;
			case TYPE_M8:
			case TYPE_M16:
			case TYPE_M32:
			case TYPE_M64:
			case TYPE_M80:
			case TYPE_M128:
			case TYPE_M256:
			case TYPE_M512:
			case TYPE_ARRAY:
			case TYPE_LOCAL:
			case TYPE_GLOBAL: abort("Variable Expected"); break;
			case 0: abort("Unable to redefine Label/Token"); break;
			default: abort("Unknown Construct"); break;
		}
	} 
	return(1);
}

unsigned int IsLabelAllocated(){
	if (token_stack[token] < HASH_OFFSET)
		abort("Expected Token/Label");
	if (hash_table[token_stack[token]-HASH_OFFSET].token_type != 0)
		abort("Unable to redefine Label/Token");
	return(1);
}
unsigned int isHash(int i){
	if(i < HASH_OFFSET)
		abort("Expected Token/Label");
	return(1);
}

unsigned int outputString(int i){
	while ((token_stack[token] != TOKEN_END_STRING) && (token != i)) {
		if (token_stack[token] < 0xffff) {
			fprintf(data, "0%xh,", token_stack[token]); // Output string as hex value rather than plain characters.
			token++;
		} else {
			fprintf(data, "0%xh,", (((token_stack[token] >> 10) & 0x3f) + (((token_stack[token] >> 16) - 1) << 6 ) + 0xd800) ); // upper 11 bits
			fprintf(data, "0%xh,", ((token_stack[token] & 0x3ff)+ 0xfc00) ); // lower 10 bits
			token++;
		}
	}
	fprintf(data, "0\n"); // Terminate the string.
	return(1);
}

unsigned int outputNumber(int i){
	while ((token_stack[token] < TOKEN_OFFSET) && (token != i)) {
		fprintf(code, "%c", token_stack[token] );
		token++;
	}
	return(1);
}

unsigned int SetState(){
	switch( hash_table[token_stack[token]-HASH_OFFSET].token_type & 7) {
		case TYPE_M8: state = 'b'; break;
		case TYPE_M16: state = 'w'; break;
		case TYPE_M32: state = 'd'; break;
		case TYPE_M64: state = ' '; break;
	}
	return(1);
}

unsigned int TokenIs(int tok){
	if (token_stack[token] != tok){
		switch(tok){
			case TOKEN_AND: abort("&& Expected"); break;
			case TOKEN_OR: abort("| Expected"); break;
			case TOKEN_XOR: abort("^ Expected"); break;
			case TOKEN_NOT: abort("! Expected"); break;
			case TOKEN_EQUATE: abort("= Expected"); break;
			case TOKEN_ADD: abort("+ Expected"); break;
			case TOKEN_MINUS: abort("- Expected"); break;
			case TOKEN_MULTIPLY: abort("* Expected"); break;
			case TOKEN_DIVIDE: abort("/ Expected"); break;
			case TOKEN_MODULUS: abort("% Expected"); break;
			case TOKEN_S_MULTIPLY: abort("~* Expected"); break;
			case TOKEN_S_DIVIDE: abort("~/ Expected"); break;
			case TOKEN_S_MODULUS: abort("~% Expected"); break;
			case TOKEN_RSHIFT: abort(">> Expected"); break;
			case TOKEN_LSHIFT: abort("<< Expected"); break;
			case TOKEN_RROTATE: abort(">>> Expected"); break;
			case TOKEN_LROTATE: abort("<<< Expected"); break;
			case TOKEN_EQUALS: abort("== Expected"); break;
			case TOKEN_NOTEQUALS: abort("!= Expected"); break;
			case TOKEN_LESSTHAN: abort("< Expected"); break;
			case TOKEN_GREATERTHAN: abort("> Expected"); break;
			case TOKEN_LESSTHANEQUALS: abort("<= Expected"); break;
			case TOKEN_GREATERTHANEQUALS: abort(">= Expected"); break;
			case TOKEN_S_LESSTHAN: abort("~< Expected"); break;
			case TOKEN_S_GREATERTHAN: abort("~> Expected"); break;
			case TOKEN_S_LESSTHANEQUALS: abort("~<= Expected"); break;
			case TOKEN_S_GREATERTHANEQUALS: abort("~>= Expected"); break;
			case TOKEN_STRING: abort("Start of String Expected"); break;
			case TOKEN_END_STRING: abort("End of String Expected"); break;
			case TOKEN_PARA_START: abort("( Expected"); break;
			case TOKEN_PARA_END: abort(") Expected"); break;
			case TOKEN_POINTER: abort("& Expected"); break;
			case TOKEN_ARRAY_START: abort("[ Expected"); break;
			case TOKEN_ARRAY_END: abort("] Expected"); break;
			default: abort("Unknown Token"); break;
		}
	}
	return(1);
}

unsigned int callProc(unsigned int who, unsigned int return_reg, int i){
	int local_offset;
	if(DEBUG)
		printf("Processing Function call with target\n");
	local_offset = 0;
	token++;          
	TokenIs(TOKEN_PARA_START);
	token++; // Move onto the next token
	
	// First set our local variable block
	// All we do in save r0 (if required), push esi, and add the amount of space used to nearest 8 bytes
	if (return_reg != HASH_r0)
		fprintf(code, "\tpush r0\n");
	
	fprintf(code, "\tpush r6\n\tadd r6, 0%xh\n", (((hash_table[(global-HASH_OFFSET)].local_offset/8)+1)*8) );

	while (token_stack[token] != TOKEN_PARA_END){
		if ((token_stack[token] == TOKEN_STRING) || (token_stack[token] == TOKEN_POINTER)) {
			if (token_stack[token] == TOKEN_POINTER){
				token++;
			}
			TokenIs(TOKEN_STRING);
			token++;
			fprintf(data, "UTF16_STRING _B0_DynStr%d , ", dynamic_string_count);
			outputString(i);
			TokenIs(TOKEN_END_STRING);
			fprintf(code, "\tmov qword [r6+0%xh], _B0_DynStr%d\n", local_offset, dynamic_string_count);
			dynamic_string_count++; // Inc the number of dynamic strings we have
		} else {
			if ((token_stack[token] < TOKEN_OFFSET) || (token_stack[token] == TOKEN_MINUS)) {
				// We have an immediate load
				fprintf(code, "\tmov qword [r6+0%xh], ", local_offset);
				if (token_stack[token] == TOKEN_MINUS) {
					token++;
					fprintf(code, "-");
				}
				outputNumber(i);
				fprintf(code, "\n");
				token--; // Adjust for token++ below.
			} else {
				TokenIsLabelType(TYPE_REG); // Otherwise only accept 64bit registers
				fprintf(code, "\tmov [r6+0%xh], %s\n", local_offset, hash_table[token_stack[token]-HASH_OFFSET].token);
			}
		}
		token++;
		local_offset += 8; // Move the offset forward 8.
		if(token_stack[token] == TOKEN_COMMA)
			token++;
	}
	TokenIs(TOKEN_PARA_END); // Final token should be the )
	token++;
	atStackEnd(i);
	// Lets call our procedure
	fprintf(code, "\tcall %s\n", hash_table[who].token);							
	// Reset esi to point to our local variables.
	fprintf(code, "\tpop r6\n");	// Restore our frame pointer
	if (return_reg != HASH_r0){
		fprintf(code, "\tmov %s, r0\n", hash_table[return_reg].token); // Copy our result to the target reg
		fprintf(code, "\tpop r0\n"); // And restore r0, back to our default.
	}
	return(1);
}

unsigned int outputDynamicString(int i){
	token++;
	//Point to the first char.
	// dynamic_string_count = string number.
	fprintf(data, "UTF16_STRING _B0_DynStr%d , ", dynamic_string_count);
	outputString(i);
	fprintf(code, "\tmov %s, _B0_DynStr%d\n", hash_table[target].token, dynamic_string_count);
	dynamic_string_count++; // Inc the number of dynamic strings we have
	token++;
	return(1);
}

void PrintHelp(){
	printf("Base Compiler (0fh) v%s\nCopyright (c) 2005, Darran Kartaschew\nAll rights reserved.\n", B0_VERSION);
	printf("\nUsage: B0 [-v] [-?|-h] [-DEBUG] [-f<type>] [-i<include>] <filename>\n");
	printf("\nWhere:\n\t-v\t\tDisplay Version Information\n");
	printf("\t-? or -h\tDisplay Help\n");
	printf("\t-DEBUG\t\tDisplay Extremely Verbose Debugging Information\n");
	printf("\t-f<type>\tOuptut Format Type, 'flat','0f','elf' or 'pe' accepted\n");
	printf("\t-i<include>\tInclude directories for libraries\n");
	printf("\t<filename>\tFile to compile\n");
	printf("\neg: B0 -felf -i./include -DEBUG myprog.b0\n");
	exit(0);
}

int dhtoi(const unsigned char *number){
	int isHex = 0; // Flag to see if string is a hex value
	int value = 0;
	const char *start_number;
	//printf("dhtoi\n");
	start_number = number;	// Save the string pointer.
	while (*number){
		//printf("0%xh ", *number);
		if (*number > TOKEN_OFFSET)
			return(0);
		if (((*number >= 'a') && (*number <= 'f')) || (*number == 'h')) {
			isHex = 1;
			//printf("isHex\n");
		}
		*number++;
	}
	number = start_number; // Restore our pointer.
	if (isHex) {
		while (*number){
			if (*number != 'h') {
				value = value << 4;
				if (*number < 'a') {
					value += (*number - '0');
				} else {
					value += (*number - 'a' + 10);
				}
			}
			*number++;
		}
	} else {
		while (*number){
			value *= 10;
			value += (*number - '0');
			*number++;
		}
	}
	//printf("dhtoi = %d\n", value);
	return value;
};

void scan_env(char *str){
	int i;
	if (total_paths > PATHS_MAX)
		return;		//buffer already full
	while(*str){
		i = 0;
		while((*str != ';')&&(*str)){
			paths[total_paths][i] = *str++;
			i++;
			if (i >= FILENAME_MAX)
				abort("File path supplied too large");
		}
		if(paths[total_paths][i-1] != '\\')
			paths[total_paths][i++] = '\\'; // add terminating slash if not there
		paths[total_paths][i] = '\0'; // Null terminate the string.
		total_paths++;
		if (total_paths >= PATHS_MAX)
			return;  // Return, as the path buffer is now full.
		if (!*str)
			return;
		*str++;
	}
}

unsigned int process_token_stack(){
	int i, j, k;
	
	i = token; // i holds the number of tokens to process.
	if(DEBUG){
		printf("PROCESSING STACK : ");
		for (token = 0; token < i; token++){
			printf("0x%x ", token_stack[token]);
		}
		printf("\n");
	}
	token = 0;
	while (token < i){
		switch (token_stack[token]) {
			case HASH_lib+HASH_OFFSET : 
				atStackStart();
				// Looks like we need to include a file.
				TokenIs(TOKEN_STRING);
				token++; // skip the start of string token
				while (token_stack[token] != TOKEN_END_STRING){
					filename[token-2] = ((unsigned char)token_stack[token] & 0x7f); // Convert to ASCII
					filename[token-1] = '\0'; //Null terminate!
					token++;
				}
				TokenIs(TOKEN_END_STRING);
				token++;	// Skip TOKEN_END_STRING
				atStackEnd(i);
				file_stack_ptr++;
				if (DEBUG)
					printf("filename = %s\n", filename);
				file[file_stack_ptr].handle = fopen(filename, "r");  // Let's see if it's in our current directory
				if (!file[file_stack_ptr].handle){
					// Now we just need to sort through the various include directories
					j = 0;
					while (j < total_paths){
						strcpy(tmp_filename, paths[j]);
						strcat(tmp_filename, filename);							// attach our include path
						file[file_stack_ptr].handle = fopen(tmp_filename, "r"); // Attempt to open
						if (DEBUG)
							printf("filename = %s; handle = %d\n", tmp_filename,file[file_stack_ptr].handle );
						if (file[file_stack_ptr].handle){						// We get a good handle
							strcpy(file[file_stack_ptr].filename, filename);	// So copy it to our file-open stack
							file[file_stack_ptr].line_count = 1;				// Reset line count.
							if (DEBUG)
								printf("found file: %s in %s\n", filename, paths[j]);
							break;												// and exit.
						}
						j++;
					}
					if (!file[file_stack_ptr].handle){
						abort("Unable to open file");
						exit(1);
					}
				} else {
					strcpy(file[file_stack_ptr].filename, filename);
					file[file_stack_ptr].line_count = 1;
				};
				break;

			case HASH_syscall+HASH_OFFSET : 
				atStackStart();
				fprintf(code, "\tsyscall\n");
				atStackEnd(i);
				break;

			case HASH_sysret+HASH_OFFSET : 
				atStackStart();
				fprintf(code, "\tsysret\n");
				atStackEnd(i);
				break;

			case HASH_push+HASH_OFFSET : 
				atStackStart();
				TokenIsLabelType(TYPE_REG); // Only allow 64 bit regs
				fprintf(code, "\tpush %s\n", hash_table[token_stack[token]-HASH_OFFSET].token);
				token++;
				atStackEnd(i);
				break;
				
			case HASH_pop+HASH_OFFSET : 
				atStackStart();
				TokenIsLabelType(TYPE_REG); // Only allow 64 bit regs
				fprintf(code, "\tpop %s\n", hash_table[token_stack[token]-HASH_OFFSET].token);
				token++;
				atStackEnd(i);
				break;
				
			case HASH_asm+HASH_OFFSET :
				atStackStart();
				atStackEnd(i);
				if (ch != '{') // Asm statements are to be followed immediately by a block.
					abort("{ Expected");
				getChar();
				asm_in_string = 0;
				while ((ch != '}') || (asm_in_string == 1)){
					if ((ch == '/')&&(asm_in_string == 0)) { // Skip comments
						if (look_ahead_ch == '/'){
							while (ch != CR){
								getChar();
							}
						}
					}
					fprintf(code, "%c", ch);
					getChar();
					if (ch == '\'') {
						if (asm_in_string == 1) {
							asm_in_string = 0;
						} else {
							asm_in_string = 1;
						}
					}
				}
				if(DEBUG)
					printf("\n");
				block_level--;
				break;
			
			case HASH_else+HASH_OFFSET:
				abort("Unexpected ELSE");
				break;
				
			case TOKEN_BLOCK_END:
				while ((token_stack[token] == TOKEN_BLOCK_END) && (token < i)) {
					if (DEBUG)
						printf("Calling END_BLOCK in while\n");
					if (token_stack[token+1] != HASH_else+HASH_OFFSET) {
						end_block();
					} else {
						end_block_else();
						token++;
						token++;
						atStackEnd(i);		// ELSE must ALWAYS be the last token on the stack
						if (ch != '{')		// Check for stack termination character!
							abort("Illformed IF-THEN-ELSE statement");
					}
					token++;
				}
				if (token < i) {
					// We have something other than ELSE
					// Becuase most items need to be at the start, we simply remove all
					// block ends, and reprocess as per normal.
					// We lucky becuase token = our first non } character!
					j = i - token; // make j our count!
					for (k = 0; k < j; k++){
						// Quick move the stack forward
						token_stack[k] = token_stack[token];
						token++;
					}
					token = 0;		// Set our stack pointer to 0
					i = j;			// Set our new stack size to the count!
				}
				break;
			
			case HASH_if+HASH_OFFSET:
				atStackStart();
				if (ch != '{') // If statements are to be followed immediately by a block.
					abort("{ Expected");
				if_while_stack[block_level].type = HASH_if;
				if_while_stack[block_level].offset = block_num;
				
				TokenIs(TOKEN_PARA_START);
				token++; // Lets see what we are testing?
				if (token_stack[token] == TOKEN_PARA_END) 
					abort("Unexpected ')'");
				
				// Process the first item...
				if (TokenIsLabelType(TYPE_REG)) {
					if_while_stack[block_level].if_while_test1 = hash_table[(token_stack[token]-HASH_OFFSET)].hash;
				} 
				token++;	// goto the next token?
				
				if (token_stack[token] == TOKEN_PARA_END) {
					// Look slike we are testing against zero?
					fprintf(code, "\tcmp %s, 0\n\tje .B0_END_BLOCK_0000%d\n", hash_table[if_while_stack[block_level].if_while_test1].token, if_while_stack[block_level].offset);
					token++;
					atStackEnd(i);
					break;
				} 
				
				if ((token_stack[token] < TOKEN_EQUALS) || (token_stack[token] > TOKEN_GREATERTHAN))
					abort("Expected comparison test");
				
				token++;
				
				if (TokenIsLabelType(TYPE_REG)) {
					if_while_stack[block_level].if_while_test2 = hash_table[(token_stack[token]-HASH_OFFSET)].hash;
				}

				token++;
				TokenIs(TOKEN_PARA_END); 
				
				// Now construct the test!
				fprintf(code, "\tcmp %s, %s\n", hash_table[if_while_stack[block_level].if_while_test1].token, hash_table[if_while_stack[block_level].if_while_test2].token );
				switch (token_stack[(token-2)]) {
					case TOKEN_EQUALS :	fprintf(code, "\tjne .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_NOTEQUALS : fprintf(code, "\tje .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_LESSTHAN : fprintf(code, "\tjae .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_GREATERTHAN : fprintf(code, "\tjbe .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_LESSTHANEQUALS : fprintf(code, "\tja .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_GREATERTHANEQUALS : fprintf(code, "\tjb .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_S_LESSTHAN : fprintf(code, "\tjge .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_S_GREATERTHAN : fprintf(code, "\tjle .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_S_LESSTHANEQUALS : fprintf(code, "\tjg .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_S_GREATERTHANEQUALS : fprintf(code, "\tjl .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
				}
				token++;
				atStackEnd(i);
				break;

			case HASH_while+HASH_OFFSET:
				atStackStart();
				if (ch != '{')	// While statements are to be followed immediately by a block.
					abort("{ Expected");
				if_while_stack[block_level].type = HASH_while;
				if_while_stack[block_level].offset = block_num;
				
				TokenIs(TOKEN_PARA_START);
				token++; // Lets see what we are testing?
				if (token_stack[token] == TOKEN_PARA_END) 
					abort("Unexpected ')'");
				
				// Process the first item...
				if (TokenIsLabelType(TYPE_REG)) {
					if_while_stack[block_level].if_while_test1 = hash_table[(token_stack[token]-HASH_OFFSET)].hash;
				} 
				token++;	// goto the next token?
				
				if (token_stack[token] == TOKEN_PARA_END) {
					// Look slike we are testing against zero?
					if_while_stack[block_level].comparison = TOKEN_NOTEQUALS;
					if_while_stack[block_level].if_while_test2 = HASH_zero;
					token++;
					atStackEnd(i);
					break;
				} 
				
				if ((token_stack[token] < TOKEN_EQUALS) || (token_stack[token] > TOKEN_GREATERTHAN))
					abort("Expected comparison test");
				
				token++;
				
				if (TokenIsLabelType(TYPE_REG)) {
					if_while_stack[block_level].if_while_test2 = hash_table[(token_stack[token]-HASH_OFFSET)].hash;
				} 

				token++;
				TokenIs(TOKEN_PARA_END);
				if_while_stack[block_level].comparison = token_stack[(token-2)]; // Save the type of test for later
				token++;
				atStackEnd(i);
				fprintf(code, "\t.B0_END_BLOCK_0000%d:\n", if_while_stack[block_level].offset);
				break;
				
			case HASH_proc+HASH_OFFSET :
				atStackStart();
				if (ch != '{')	// Proc decl statements are to be followed immediately by a block.
					abort("{ Expected");
				isHash(token_stack[token]);
				if (global != 0) 
					abort("Unable to nest proc definitions");
				global = token_stack[token];
				if (hash_table[(global-HASH_OFFSET)].token_type == 0) {
					hash_table[(global-HASH_OFFSET)].token_type = TYPE_PROC;
				} else {
					abort("Unable to redeclare procedure?");
				}
				fprintf(code, "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
				fprintf(code, "; %s Function Code;\n", hash_table[(global-HASH_OFFSET)].token);
				fprintf(code, ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n");				
				fprintf(data, "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
				fprintf(data, "; %s Function Variables ;\n", hash_table[(global-HASH_OFFSET)].token);
				fprintf(data, ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n");				
				fprintf(code, "align 16\n%s:\n", hash_table[(global-HASH_OFFSET)].token);
				local_var_offset = 0;
				// Now clean up the hash table of all local variables.
				for (j = 0; j < HASH_TABLE_SIZE; j++) {
					if ((hash_table[j].token_type & (TYPE_LOCAL)) > 0 ){
						if(DEBUG)
							printf("Erasing 0x%x -> 0x%x = %s ,Type: 0x%x\n", j, hash_table[j].hash, hash_table[j].token, hash_table[j].token_type);
						hash_table[j].token[0] = 0;
						hash_table[j].hash = 0;
						hash_table[j].token_type = 0;
						hash_table[j].local_offset = 0;
					}
				};
				// Now process the parameters
				// token should be on the proc
				token++;
				// move to the first para?
				TokenIs(TOKEN_PARA_START);
				token++; // Lets see what we are testing?
				if (token_stack[token] == TOKEN_PARA_END) {
					// I guess we have no parameters.
					token++;
					atStackEnd(i);
					break;	// Let's get outa here!
				}
				// Alrightly all proc parameters are type m64 so this going to be a bit easier?
				while(token_stack[token] != TOKEN_PARA_END) {
					IsLabelAllocated();
					hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M64+TYPE_LOCAL;
					hash_table[(token_stack[token]-HASH_OFFSET)].local_offset = local_var_offset;
					fprintf(data, "%s_%s equ %d\n", hash_table[(global-HASH_OFFSET)].token, hash_table[(token_stack[token]-HASH_OFFSET)].token , local_var_offset);
					local_var_offset += 8;
					token++;
					if(token_stack[token] == TOKEN_COMMA)
						token++;
				}
				token++;
				atStackEnd(i);
				break;
				
			case HASH_m8+HASH_OFFSET :
			case HASH_m16+HASH_OFFSET :
			case HASH_m32+HASH_OFFSET :
			case HASH_m64+HASH_OFFSET :
				atStackStart();
				if (global == 0) {
					if (token_stack[token] == TOKEN_ARRAY_START) {
						// This gets a little complicated?
						toki = 0;
						token++;
						while (token_stack[token] != TOKEN_ARRAY_END) {
							token_buffer[toki] = (char)token_stack[token];
							token_buffer[toki+1] = '\0';
							toki++;
							token++;
						}
						token++; // Skip end of array size indicator.
						isHash(token_stack[token]);
						switch (token_stack[0]) {
							case HASH_m8+HASH_OFFSET :
								fprintf(data, "%s rb %s\n", hash_table[(token_stack[token]-HASH_OFFSET)].token , token_buffer);
								IsLabelAllocated();
								hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M8+TYPE_ARRAY+TYPE_GLOBAL;
								break;
							case HASH_m16+HASH_OFFSET :
								fprintf(data, "%s rw %s\n", hash_table[(token_stack[token]-HASH_OFFSET)].token, token_buffer );
								IsLabelAllocated();
								hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M16+TYPE_ARRAY+TYPE_GLOBAL;
								break;
							case HASH_m32+HASH_OFFSET :
								fprintf(data, "%s rd %s\n", hash_table[(token_stack[token]-HASH_OFFSET)].token, token_buffer );
								IsLabelAllocated();
								hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M32+TYPE_ARRAY+TYPE_GLOBAL;
								break;
							case HASH_m64+HASH_OFFSET :
								fprintf(data, "%s rq %s\n", hash_table[(token_stack[token]-HASH_OFFSET)].token, token_buffer );
								IsLabelAllocated();
								hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M64+TYPE_ARRAY+TYPE_GLOBAL;
								break;
						}
						token++;
						atStackEnd(i);
					} else {
						isHash(token_stack[token]);
						switch (token_stack[token-1]) {
							case HASH_m8+HASH_OFFSET :
								fprintf(data, "%s db ", hash_table[(token_stack[token]-HASH_OFFSET)].token );
								IsLabelAllocated();
								hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M8+TYPE_GLOBAL;
								break;
							case HASH_m16+HASH_OFFSET :
								fprintf(data, "%s dw ", hash_table[(token_stack[token]-HASH_OFFSET)].token );
								IsLabelAllocated();
								hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M16+TYPE_GLOBAL;
								break;
							case HASH_m32+HASH_OFFSET :
								fprintf(data, "%s dd ", hash_table[(token_stack[token]-HASH_OFFSET)].token );
								IsLabelAllocated();
								hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M32+TYPE_GLOBAL;
								break;
							case HASH_m64+HASH_OFFSET :
								fprintf(data, "%s dq ", hash_table[(token_stack[token]-HASH_OFFSET)].token );
								IsLabelAllocated();
								hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M64+TYPE_GLOBAL;
								break;
						}
						token++;
						if (token != i) {
							// We have tokens that follow?
							TokenIs(TOKEN_EQUATE);
							token++;
							while (token < i){
								if (token_stack[token] == TOKEN_STRING) {
									TokenIs(TOKEN_STRING);
									token++;
									if (token_stack[token-4] == HASH_m8+HASH_OFFSET)
										abort("Strings must be encoded with at least m16");
									// Before outputing the string, lets find the length of the string.
									j = 0;
									while (token_stack[token] != TOKEN_END_STRING){
										j++;
										token++;
									}
									token = token - j; // Reset the token back to it's correct value
									j += 2;	// Add 2 for two word fields used to hold the buffer size, and utilised size
									fprintf(data, "0%xh,0%xh,", j, j);
									outputString(i);
									TokenIs(TOKEN_END_STRING);
									token++;
								} else {
									if (token_stack[token] > TOKEN_OFFSET)
										abort("Immediate Expected");
									while ((token_stack[token] < TOKEN_OFFSET) && (token != i)) {
										fprintf(data, "%c", token_stack[token] );
										token++;
									}
								}
								if((token_stack[token] == TOKEN_COMMA) && (token != i)){
									fprintf(data, ",");
									token++;
								}
							}
							fprintf(data, "\n");
						} else {
							fprintf(data, " 0\n");
						}
					atStackEnd(i);
					}
				} else {
					// We have a local, and global -> current proc
					if (token_stack[token] == TOKEN_ARRAY_START) {
						// This gets a little complicated?
						toki = 0;
						token++;
						if (token_stack[token] == TOKEN_ARRAY_END)
							abort("Unexpected ]");
						while (token_stack[token] != TOKEN_ARRAY_END) {
							if(token_stack[token] > TOKEN_OFFSET)
								abort("Immediate value expected");
							token_buffer[toki] = (char)token_stack[token];
							token_buffer[toki+1] = '\0';
							toki++;
							token++;
						}
						token++; // Skip end of array size indicator.
					} else {
						token_buffer[0] = '1';
						token_buffer[1] = 0;
					}
					//token buffer is our size in ASCII
					isHash(token_stack[token]);
					fprintf(data, "%s_%s equ %d\n", hash_table[(global-HASH_OFFSET)].token, hash_table[(token_stack[token]-HASH_OFFSET)].token , local_var_offset);
					
					switch (token_stack[0]) {
						case HASH_m8+HASH_OFFSET :
							IsLabelAllocated();
							local_var_offset = local_var_offset + (dhtoi(token_buffer));
							hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M8+TYPE_LOCAL;
							break;
						case HASH_m16+HASH_OFFSET :
							IsLabelAllocated();
							local_var_offset = local_var_offset + (dhtoi(token_buffer) * 2);
							hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M16+TYPE_LOCAL;
							break;
						case HASH_m32+HASH_OFFSET :
							IsLabelAllocated();
							local_var_offset = local_var_offset + (dhtoi(token_buffer) * 4);
							hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M32+TYPE_LOCAL;
							break;
						case HASH_m64+HASH_OFFSET :
							IsLabelAllocated();
							local_var_offset = local_var_offset + (dhtoi(token_buffer) * 8);
							hash_table[(token_stack[token]-HASH_OFFSET)].token_type = TYPE_M64+TYPE_LOCAL;
							break;
					}
					//set the used stack frame for the current proc.
					hash_table[(global-HASH_OFFSET)].local_offset = local_var_offset;
					token++;
					atStackEnd(i);
				}
				break;
			
			case TOKEN_NOT: 
				atStackStart();
				//TokenIsLabelType(TYPE_REG);
				if (token_stack[token] < HASH_OFFSET)
					abort("Expected Token/Label");
				if ((token_stack[token] & (TYPE_REG + TYPE_REG_SHORT)) == 0 )
					abort("Expected Register");
				fprintf(code, "\tnot %s\n", hash_table[token_stack[token]-HASH_OFFSET].token);
				token++;
				atStackEnd(i);
				break;

			case TOKEN_MINUS: 
				atStackStart();
				//TokenIsLabelType(TYPE_REG);
				if (token_stack[token] < HASH_OFFSET)
					abort("Expected Token/Label");
				if ((token_stack[token] & (TYPE_REG + TYPE_REG_SHORT)) == 0 )
					abort("Expected Register");
				fprintf(code, "\tneg %s\n", hash_table[token_stack[token]-HASH_OFFSET].token);
				token++;
				atStackEnd(i);
				break;

				
			case HASH_exit+HASH_OFFSET :
				atStackStart();
				TokenIs(TOKEN_PARA_START);
				token++;
				if (token_stack[token] != TOKEN_PARA_END){
					if ((token_stack[token] < TOKEN_OFFSET) || (token_stack[token] == TOKEN_MINUS)) {
						// We have an immediate load
						fprintf(code, "\tmov r0, ");
						if (token_stack[token] == TOKEN_MINUS) {
							token++;
							fprintf(code, "-");
						}
						outputNumber(i);
						fprintf(code, "\n");
					} else {
						// We should have a reg										
						TokenIsLabelType(TYPE_REG);  // Only allow 64bit reg
						if ((token_stack[token]-HASH_OFFSET) != HASH_r0)	// If the reg is r0, then don't output code!
							fprintf(code, "\tmov r0, %s\n", hash_table[token_stack[token]-HASH_OFFSET].token);
						token++;
					}
					TokenIs(TOKEN_PARA_END);
				} else {
					fprintf(code, "\tmov r0, 0\n");
				}
				fprintf(code, "\tjmp _B0_sys_exit\n");
				token++;
				atStackEnd(i);
				break;
				
			case HASH_return+HASH_OFFSET :
				atStackStart();
				TokenIs(TOKEN_PARA_START);
				token++;
				if (token_stack[token] != TOKEN_PARA_END){
					if ((token_stack[token] < TOKEN_OFFSET) || (token_stack[token] == TOKEN_MINUS)) {
						// We have an immediate load
						fprintf(code, "\tmov r0, ");
						if (token_stack[token] == TOKEN_MINUS) {
							token++;
							fprintf(code, "-");
						}
						outputNumber(i);
						fprintf(code, "\n");
					} else {
						// We should have a reg										
						TokenIsLabelType(TYPE_REG);		// Only allow 64bit reg.
						if ((token_stack[token]-HASH_OFFSET) != HASH_r0)	// If the reg is r0, then don't output code!
							fprintf(code, "\tmov r0, %s\n", hash_table[token_stack[token]-HASH_OFFSET].token);
						token++;
					}
					TokenIs(TOKEN_PARA_END);
				} else {
					fprintf(code, "\tmov r0, 0\n");
				}
				fprintf(code, "\tret\n");
				token++;
				atStackEnd(i);
				break;
			
			default :
				if(DEBUG)
					printf("token index = %d\n", token);
				if ( token_stack[token] < TOKEN_ARRAY_START)
					abort("Invalid construct");
				if ( token_stack[token] == TOKEN_ARRAY_START) {
					//Process global memory reference;
					fprintf(code, "\tmov [");
					token++;	//Increase token pointer;
					if (token_stack[token] == TOKEN_ARRAY_END)
						abort("Unexpected end of memory reference");
					if (token_stack[token] < TOKEN_OFFSET) {
						//we have direct numerical reference
						outputNumber(i);
						token++;
						fprintf(code, "], ");
					} else {
						//we should be dealing with a register
						TokenIsLabelType(TYPE_REG);
						fprintf(code, "%s", hash_table[token_stack[token]-HASH_OFFSET].token);
						token++;
						if (token_stack[token] == TOKEN_ADD){
							// Looks like a complex memory pointer operation.
							fprintf(code, "+");
							token++;
							if (token_stack[token] > TOKEN_OFFSET) {
								// Should be a reg?
								TokenIsLabelType(TYPE_REG);
								fprintf(code, "%s", hash_table[token_stack[token]-HASH_OFFSET].token); // Output the reg
								token++;
								// Here we should have either a + or a *
								if ((token_stack[token] != TOKEN_ADD) &&
									(token_stack[token] != TOKEN_MULTIPLY) &&
									(token_stack[token] != TOKEN_ARRAY_END))
									abort("+, * or ] Expected");
								if (token_stack[token] == TOKEN_ADD) {
									// We should have an immediate
									fprintf(code, "+");
									token++;
									if (token_stack[token] > TOKEN_OFFSET)
										abort("Immediate Expected");
									outputNumber(i);
								} else {
									if (token_stack[token] == TOKEN_MULTIPLY) {
										// Handle our multiply, else fall through (it should be an ARRAY_END).
										fprintf(code, "*");
										token++;
										// This part gets tricky, as we should only have 1,2,4 or 8 here!
										if (token_stack[token] > TOKEN_OFFSET)
											abort("Immediate Expected");
										if ((token_stack[token] != '1') &&
											(token_stack[token] != '2') &&
											(token_stack[token] != '4') &&
											(token_stack[token] != '8'))
											abort("Illformed pointer expression, please revise");
										fprintf(code, "%c", token_stack[token]);
										token++; // Output the number
										if (token_stack[token] < TOKEN_OFFSET){
											if (token_stack[token] != 'h') {
												abort("Unexpected Immediate");
											}
											token++; // Advance past the 'h'
										}
										if (token_stack[token] == TOKEN_ADD){
											fprintf(code, "+");
											token++;
											if (token_stack[token] < TOKEN_OFFSET) {
												outputNumber(i);
											} else {
												abort("Expected Immediate");
											}
										}
									}
								}
							} else {
								// Else output the displacement.
								outputNumber(i);
							}
						}  else {
							if (token_stack[token] == TOKEN_MULTIPLY) {
								// Handle our multiply, else fall through (it should be an ARRAY_END).
								fprintf(code, "*");
								token++;
								// This part gets tricky, as we should only have 1,2,4 or 8 here!
								if (token_stack[token] > TOKEN_OFFSET)
									abort("Immediate Expected");
								if ((token_stack[token] != '1') &&
									(token_stack[token] != '2') &&
									(token_stack[token] != '4') &&
									(token_stack[token] != '8'))
									abort("Illformed pointer expression, please revise");
								fprintf(code, "%c", token_stack[token]);
								token++; // Output the number
								if (token_stack[token] < TOKEN_OFFSET){
									if (token_stack[token] != 'h') {
										abort("Unexpected Immediate");
									}
									token++; // Advance past the 'h'
								}
								if (token_stack[token] == TOKEN_ADD){
									fprintf(code, "+");
									token++;
									if (token_stack[token] < TOKEN_OFFSET) {
										outputNumber(i);
									} else {
										abort("Expected Immediate");
									}
								}
							}
						}
						TokenIs(TOKEN_ARRAY_END);
						fprintf(code, "], ");
						token++;
					}
					TokenIs(TOKEN_EQUATE);
					token++;
					if (token_stack[token] < TOKEN_OFFSET) {
						abort("Register Expected");
					} 
					//TokenIsLabelType(TYPE_REG);
					isHash(token_stack[token]);
					if ((hash_table[token_stack[token]-HASH_OFFSET].token_type & (TYPE_REG+TYPE_REG_SHORT) ) > 0) {
						fprintf(code, "%s\n", hash_table[token_stack[token]-HASH_OFFSET].token);
					} else {
						abort("Register Expected");
					}
					token++;
					atStackEnd(i);
				} else {
					//we must have a register, function, or label
					if (token_stack[token] == TOKEN_ARRAY_END)
						abort("Unexpected token ']'");
					if ((hash_table[token_stack[token]-HASH_OFFSET].token_type & 7) > 0) {
							// We have a label;
							if(DEBUG)
								printf("Processing line with variable destination\n");
							SetState(); // Set state to be b,e,d,' ' according to width of variable
							//state will hold the size of the transfer..., On m64 state = '', as this is the default size. No override needed.
							token++;
							if (token_stack[token] == TOKEN_ARRAY_START) {
								// we are loading an array!
								token++;
								if (token_stack[token] == TOKEN_ARRAY_END)
									abort("Unexpected token ']'");
								if (token_stack[token] < TOKEN_OFFSET) {
									// We have a direct immediate.
									switch (hash_table[token_stack[token-2]-HASH_OFFSET].token_type & (TYPE_GLOBAL+TYPE_LOCAL)) {
										case TYPE_GLOBAL:
											switch (state) {
												case 'b' : fprintf(code, "\tmov byte [%s+", hash_table[token_stack[token-2]-HASH_OFFSET].token);
															outputNumber(i);
														break;
												case 'w' : fprintf(code, "\tmov word [%s+2*", hash_table[token_stack[token-2]-HASH_OFFSET].token);
															outputNumber(i);
														break;
												case 'd' : fprintf(code, "\tmov dword [%s+4*", hash_table[token_stack[token-2]-HASH_OFFSET].token);
															outputNumber(i);
														break;
												case ' ' : fprintf(code, "\tmov qword [%s+8*", hash_table[token_stack[token-2]-HASH_OFFSET].token);
															outputNumber(i);
														break;
											}
											break;
												
										case TYPE_LOCAL:
											switch (state) {
												case 'b' : fprintf(code, "\tmov byte [r6+%s_%s+", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
															outputNumber(i);
														break;
												case 'w' : fprintf(code, "\tmov word [r6+%s_%s+2*", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
															outputNumber(i);
														break;
												case 'd' : fprintf(code, "\tmov dword [r6+%s_%s+4*", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
															outputNumber(i);
														break;
												case ' ' : fprintf(code, "\tmov qword [r6+%s_%s+8*", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
															outputNumber(i);
														break;
											}
											break;
									}
									fprintf(code, "], ");
								} else {
									// We have a reg.
									TokenIsLabelType(TYPE_REG);
									switch (hash_table[token_stack[token-2]-HASH_OFFSET].token_type & (TYPE_GLOBAL+TYPE_LOCAL)) {
										case TYPE_GLOBAL:
											switch (state) {
												case 'b' : fprintf(code, "\tmov byte [%s+%s],", hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
														break;
												case 'w' : fprintf(code, "\tmov word [%s+2*%s],", hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
														break;
												case 'd' : fprintf(code, "\tmov dword [%s+4*%s],", hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
														break;
												case ' ' : fprintf(code, "\tmov qword [%s+8*%s],", hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
														break;
											}
											break;
												
										case TYPE_LOCAL:
											switch (state) {
												case 'b' : fprintf(code, "\tmov byte [r6+%s_%s+%s],", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
														break;
												case 'w' : fprintf(code, "\tmov word [r6+%s_%s+2*%s],", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
														break;
												case 'd' : fprintf(code, "\tmov dword [r6+%s_%s+4*%s],", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
														break;
												case ' ' : fprintf(code, "\tmov qword [r6+%s_%s+8*%s],", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
														break;
											}
											break;
									}
									token++;
								}
								TokenIs(TOKEN_ARRAY_END);
								token++;
								TokenIs(TOKEN_EQUATE);
								token++;
								if (token_stack[token] < TOKEN_OFFSET) {
									// We have an immediate load.
									outputNumber(i);
									fprintf(code, "\n");
									atStackEnd(i);
								} else {
									// We should have a register
									TokenIsLabelType(TYPE_REG);
									fprintf(code, "%s%c\n", hash_table[token_stack[token]-HASH_OFFSET].token, state);
									token++;
									atStackEnd(i);
								}
							} else {
								// we are loading a single variable
								TokenIs(TOKEN_EQUATE);
								token++;
								if (token_stack[token] < TOKEN_OFFSET) {
									// We have a direct immediate variable load.
									switch (hash_table[token_stack[token-2]-HASH_OFFSET].token_type & (TYPE_GLOBAL+TYPE_LOCAL)) {
										case TYPE_GLOBAL:
											switch (state) {
												case 'b' : fprintf(code, "\tmov byte [%s], ", hash_table[token_stack[token-2]-HASH_OFFSET].token);
														break;
												case 'w' : fprintf(code, "\tmov word [%s], ", hash_table[token_stack[token-2]-HASH_OFFSET].token);
														break;
												case 'd' : fprintf(code, "\tmov dword [%s], ", hash_table[token_stack[token-2]-HASH_OFFSET].token);
														break;
												case ' ' : fprintf(code, "\tmov qword [%s], ", hash_table[token_stack[token-2]-HASH_OFFSET].token);
														break;
											}
											break;
												
										case TYPE_LOCAL:
											switch (state) {
												case 'b' : fprintf(code, "\tmov byte [r6+%s_%s], ", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
														break;
												case 'w' : fprintf(code, "\tmov word [r6+%s_%s], ", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
														break;
												case 'd' : fprintf(code, "\tmov dword [r6+%s_%s], ", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
														break;
												case ' ' : fprintf(code, "\tmov qword [r6+%s_%s], ", hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
														break;
											}
											break;
									}
									outputNumber(i);
									fprintf(code, "\n");
									atStackEnd(i);
	
								} else {
									TokenIsLabelType(TYPE_REG);
									switch (hash_table[token_stack[token-2]-HASH_OFFSET].token_type & (TYPE_GLOBAL+TYPE_LOCAL)) {
										case TYPE_GLOBAL:
												fprintf(code, "\tmov [%s], %s%c\n", hash_table[token_stack[token-2]-HASH_OFFSET].token, 
																					hash_table[token_stack[token]-HASH_OFFSET].token,
																					state);
												break;
										case TYPE_LOCAL:
												fprintf(code, "\tmov [r6+%s_%s], %s%c\n", hash_table[(global-HASH_OFFSET)].token, 
																					hash_table[token_stack[token-2]-HASH_OFFSET].token,
																					hash_table[token_stack[token]-HASH_OFFSET].token,
																					state);
												break;
									}
									token++;
									atStackEnd(i);
								}
							}
					} else {
						if (hash_table[token_stack[token]-HASH_OFFSET].token_type == TYPE_REG) {
							if(DEBUG)
								printf("Processing line with register destination\n");
							target = token_stack[token]-HASH_OFFSET; //Store hash of target.
							token++;
							TokenIs(TOKEN_EQUATE);
							token++; // Let's skip ahead for a second.
							if ((token_stack[token] == TOKEN_POINTER)||(token_stack[token] == TOKEN_STRING)) {
								// We are dealing with a pointer to either a string or label
								if (token_stack[token] == TOKEN_POINTER) token++;
								// Advance if token is a pointer, otherwise just wait.
								if (token_stack[token] == TOKEN_STRING) {
									outputDynamicString(i);
									atStackEnd(i);
								} else {
									// We are dealing with a label, but lets first check
									isHash(token_stack[token]);
									if (hash_table[token_stack[token]-HASH_OFFSET].token_type == TYPE_PROC) {
										//Process pointer to PROC!
										fprintf(code, "\tmov %s, %s\n", hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
										token++;          
										TokenIs(TOKEN_PARA_START);
										token++; // Let's skip ahead for a second.
										TokenIs(TOKEN_PARA_END);
										token++;
										atStackEnd(i);
									} else {
										if ((hash_table[token_stack[token]-HASH_OFFSET].token_type & 7) == 0) abort("Expected Data Label");
										// We definitely have a label, now set state to show size.
										SetState(); // Set state to be b,e,d,' ' according to width of variable
										//Now check to see if it's local or global?
										if ((hash_table[token_stack[token]-HASH_OFFSET].token_type & TYPE_GLOBAL) == TYPE_GLOBAL) {
											// We have a global variable
											fprintf(code, "\tmov %s, %s\n", hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
										} else {
											if ((hash_table[token_stack[token]-HASH_OFFSET].token_type & TYPE_LOCAL) != TYPE_LOCAL) abort("Expected Data Label");
											// Else we have a local variable, which takes some fudging.
											fprintf(code, "\tmov %s, r6\n", hash_table[target].token);
											fprintf(code, "\tadd %s, %s_%s\n", hash_table[target].token,hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token]-HASH_OFFSET].token);
										}
										token++;
										if ((token_stack[token] == TOKEN_ARRAY_START)&&(token!=i)){
											// We are are dealing with a pointer to an element of an array!
											// Since we want to be tricky, we'll support pointer to element using reg as well as immediate.
											// We already have target set, so we should be right.
											token++;
											if (token_stack[token] == TOKEN_ARRAY_END)
												abort("Unexpected token ']'");
											if (token_stack[token] < TOKEN_OFFSET) {
												// We have a direct immediate.
												switch (state) {
													case 'b' : fprintf(code, "\tlea %s, [%s+", hash_table[target].token, hash_table[target].token);
																outputNumber(i);
															break;
													case 'w' : fprintf(code, "\tlea %s, [%s+2*", hash_table[target].token, hash_table[target].token);
																outputNumber(i);
															break;
													case 'd' : fprintf(code, "\tlea %s, [%s+4*", hash_table[target].token, hash_table[target].token);
																outputNumber(i);
															break;
													case ' ' : fprintf(code, "\tlea %s, [%s+8*", hash_table[target].token, hash_table[target].token);
																outputNumber(i);
															break;
												}
												fprintf(code, "]\n");
											} else {
												// We have a reg.
												TokenIsLabelType(TYPE_REG);
												// We need to check that the target reg and source reg are !=
												if (target == ((token_stack[token])-HASH_OFFSET))
													abort("Destination Register and Register used for Array Index cannot be the same in pointer assignments");
												switch (state) {
													case 'b' : fprintf(code, "\tlea %s, [%s+%s]\n", hash_table[target].token, hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
															break;
													case 'w' : fprintf(code, "\tlea %s, [%s+%s*2]\n", hash_table[target].token, hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
															break;
													case 'd' : fprintf(code, "\tlea %s, [%s+%s*4]\n", hash_table[target].token, hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
															break;
													case ' ' : fprintf(code, "\tlea %s, [%s+%s*8]\n", hash_table[target].token, hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
															break;
												}
												token++;
											}
											TokenIs(TOKEN_ARRAY_END);
											token++;
										}
										atStackEnd(i);
									}
								}
							} else {
								// We have a reg, label, immediate, or proc. (pointers have already been dealth with).
								if ((token_stack[token] < TOKEN_OFFSET) || (token_stack[token] == TOKEN_MINUS)) {
									// We have an immediate load
									fprintf(code, "\tmov %s, ", hash_table[target].token);
									if (token_stack[token] == TOKEN_MINUS) {
										token++;
										fprintf(code, "-");
									}
									outputNumber(i);
									fprintf(code, "\n");
									atStackEnd(i);
								} else {
									// We have a reg, label or proc
									if (token_stack[token] == TOKEN_ARRAY_START) {
										// We have a global load into a register
										token++;
										if (token_stack[token] == TOKEN_ARRAY_END)
											abort("Unexpected ]");
										if (token_stack[token] < TOKEN_OFFSET) {
											// We have an immediate load
											fprintf(code, "\tmov %s, [", hash_table[target].token);
											outputNumber(i);
											fprintf(code, "]\n");
										} else {
											// We should have a reg!
											TokenIsLabelType(TYPE_REG);
											fprintf(code, "\tmov %s, [%s", hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
											token++;
											if (token_stack[token] == TOKEN_ADD){
												// Looks like a complex memory pointer operation.
												fprintf(code, "+");
												token++;
												if (token_stack[token] > TOKEN_OFFSET) {
													// Should be a reg?
													TokenIsLabelType(TYPE_REG);
													fprintf(code, "%s", hash_table[token_stack[token]-HASH_OFFSET].token); // Output the reg
													token++;
													// Here we should have either a + or a *
													if ((token_stack[token] != TOKEN_ADD) &&
														(token_stack[token] != TOKEN_MULTIPLY) &&
														(token_stack[token] != TOKEN_ARRAY_END))
														abort("+, * or ] Expected");
													if (token_stack[token] == TOKEN_ADD) {
														// We should have an immediate
														fprintf(code, "+");
														token++;
														if (token_stack[token] > TOKEN_OFFSET)
															abort("Immediate Expected");
														outputNumber(i);
													} else {
														if (token_stack[token] == TOKEN_MULTIPLY) {
															// Handle our multiply, else fall through (it should be an ARRAY_END).
															fprintf(code, "*");
															token++;
															// This part gets tricky, as we should only have 1,2,4 or 8 here!
															if (token_stack[token] > TOKEN_OFFSET)
																abort("Immediate Expected");
															if ((token_stack[token] != '1') &&
																(token_stack[token] != '2') &&
																(token_stack[token] != '4') &&
																(token_stack[token] != '8'))
																abort("Illformed pointer expression, please revise");
															fprintf(code, "%c", token_stack[token]);
															token++; // Output the number
															if (token_stack[token] < TOKEN_OFFSET){
																if (token_stack[token] != 'h') {
																	abort("Unexpected Immediate");
																}
																token++; // Advance past the 'h'
															}
															if (token_stack[token] == TOKEN_ADD){
																fprintf(code, "+");
																token++;
																if (token_stack[token] < TOKEN_OFFSET) {
																	outputNumber(i);
																} else {
																	abort("Expected Immediate");
																}
															}
														}
													}
												} else {
													// Else output the displacement.
													outputNumber(i);
												}
											}  else {
												if (token_stack[token] == TOKEN_MULTIPLY) {
													// Handle our multiply, else fall through (it should be an ARRAY_END).
													fprintf(code, "*");
													token++;
													// This part gets tricky, as we should only have 1,2,4 or 8 here!
													if (token_stack[token] > TOKEN_OFFSET)
														abort("Immediate Expected");
													if ((token_stack[token] != '1') &&
														(token_stack[token] != '2') &&
														(token_stack[token] != '4') &&
														(token_stack[token] != '8'))
														abort("Illformed pointer expression, please revise");
													fprintf(code, "%c", token_stack[token]);
													token++; // Output the number
													if (token_stack[token] < TOKEN_OFFSET){
														if (token_stack[token] != 'h') {
															abort("Unexpected Immediate");
														}
														token++; // Advance past the 'h'
													}
													if (token_stack[token] == TOKEN_ADD){
														fprintf(code, "+");
														token++;
														if (token_stack[token] < TOKEN_OFFSET) {
															outputNumber(i);
														} else {
															abort("Expected Immediate");
														}
													}
												}
											}
											fprintf(code, "]\n");
										}
										TokenIs(TOKEN_ARRAY_END);
										token++;
										atStackEnd(i);									
									
									} else {
										// We have a reg, label or proc
										// At this stage, the next token should be a reg, label or proc.
										// Anything else is incorrect!
										isHash(token_stack[token]);
										if (hash_table[token_stack[token]-HASH_OFFSET].token_type == TYPE_KEYWORD)
											abort("Unexpected Keyword");
										
										// The only thing we should be left with are the regs, labels or procs!
										if ((hash_table[token_stack[token]-HASH_OFFSET].token_type & 7) > 0) {
											// We have a label
											if(DEBUG)
												printf("Processing line with register destination with label source\n");
											SetState(); // Set state to be b,e,d,' ' according to width of variable
											//state will hold the size of the transfer..., On m64 state = '', as this is the default size. No override needed.
											token++;
											if ((token_stack[token] == TOKEN_ARRAY_START)&&(token!=i)) {
												// we are loading an array!
												token++;
												// Let advance 1 and see if we have an immediate or a reg...
												
												if (token_stack[token] == TOKEN_ARRAY_END)
													abort("Unexpected token ']'");
												if (token_stack[token] < TOKEN_OFFSET) {
													// We have a direct immediate.
													switch (hash_table[token_stack[token-2]-HASH_OFFSET].token_type & (TYPE_GLOBAL+TYPE_LOCAL)) {
														case TYPE_GLOBAL:
															switch (state) {
																case 'b' : fprintf(code, "\tmovzx %s, byte [%s+", hash_table[target].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
																			outputNumber(i);
																		break;
																case 'w' : fprintf(code, "\tmovzx %s, word [%s+2*", hash_table[target].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
																			outputNumber(i);
																		break;
																case 'd' :  fprintf(code, "\txor %s, %s\n", hash_table[target].token, hash_table[target].token);
																			fprintf(code, "\tmov %s%c, dword [%s+4*", hash_table[target].token, state, hash_table[token_stack[token-2]-HASH_OFFSET].token);
																			outputNumber(i);
																		break;
																case ' ' : fprintf(code, "\tmov %s, [%s+8*", hash_table[target].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
																			outputNumber(i);
																		break;
															}
															break;
																
														case TYPE_LOCAL:
															switch (state) {
																case 'b' : fprintf(code, "\tmovzx %s, byte [r6+%s_%s+", hash_table[target].token, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
																			outputNumber(i);
																		break;
																case 'w' : fprintf(code, "\tmovzx %s, word [r6+%s_%s+2*", hash_table[target].token, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
																			outputNumber(i);
																		break;
																case 'd' : fprintf(code, "\txor %s, %s\n", hash_table[target].token, hash_table[target].token);
																			fprintf(code, "\tmov %s%c, dword [r6+%s_%s+4*", hash_table[target].token, state, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
																			outputNumber(i);
																		break;
																case ' ' : fprintf(code, "\tmov %s, [r6+%s_%s+8*", hash_table[target].token, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token);
																			outputNumber(i);
																		break;
															}
															break;
													}
													fprintf(code, "]\n");
												} else {
													// We have a reg.
													TokenIsLabelType(TYPE_REG);
													switch (hash_table[token_stack[token-2]-HASH_OFFSET].token_type & (TYPE_GLOBAL+TYPE_LOCAL)) {
														case TYPE_GLOBAL:
															switch (state) {
																case 'b' : fprintf(code, "\tmovzx %s, byte [%s+%s]\n", hash_table[target].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																		break;
																case 'w' : fprintf(code, "\tmovzx %s, word [%s+2*%s]\n", hash_table[target].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																		break;
																case 'd' : fprintf(code, "\txor %s, %s\n", hash_table[target].token, hash_table[target].token);
																		fprintf(code, "\tmov %s%c, dword [%s+4*%s]\n", hash_table[target].token, state, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																		break;
																case ' ' : fprintf(code, "\tmov %s, [%s+8*%s]\n", hash_table[target].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																		break;
															}
															break;
																
														case TYPE_LOCAL:
															switch (state) {
																case 'b' : fprintf(code, "\tmovzx %s, byte [r6+%s_%s+%s]\n", hash_table[target].token, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																		break;
																case 'w' : fprintf(code, "\tmovzx %s, word [r6+%s_%s+2*%s]\n", hash_table[target].token, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																		break;
																case 'd' : fprintf(code, "\txor %s, %s\n", hash_table[target].token, hash_table[target].token);
																		fprintf(code, "\tmov %s%c, dword [r6+%s_%s+4*%s]\n", hash_table[target].token, state, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																		break;
																case ' ' : fprintf(code, "\tmov %s, [r6+%s_%s+8*%s]\n", hash_table[target].token, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token-2]-HASH_OFFSET].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																		break;
															}
															break;
													}
													token++;
												}
												TokenIs(TOKEN_ARRAY_END);
												token++;
												atStackEnd(i);
											} else {
												// we are loading a single variable
												if(DEBUG)
													printf("Processing line with register destination with label source - no array\n");
												token--;
												switch (hash_table[token_stack[token]-HASH_OFFSET].token_type & (TYPE_GLOBAL+TYPE_LOCAL)) {
													case TYPE_GLOBAL:
														switch (state) {
															case 'b' : fprintf(code, "\tmovzx %s, byte [%s]\n", hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																	break;
															case 'w' : fprintf(code, "\tmovzx %s, word [%s]\n", hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																	break;
															case 'd' : fprintf(code, "\txor %s, %s\n", hash_table[target].token, hash_table[target].token);
																	fprintf(code, "\tmov %s%c, dword [%s]\n", hash_table[target].token, state, hash_table[token_stack[token]-HASH_OFFSET].token);
																	break;
															case ' ' : fprintf(code, "\tmov %s, [%s]\n", hash_table[target].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																	break;
														}
														break;
															
													case TYPE_LOCAL:
														switch (state) {
															case 'b' : fprintf(code, "\tmovzx %s, byte [r6+%s_%s]\n", hash_table[target].token, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																	break;
															case 'w' : fprintf(code, "\tmovzx %s, word [r6+%s_%s]\n", hash_table[target].token, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																	break;
															case 'd' : fprintf(code, "\txor %s, %s\n", hash_table[target].token, hash_table[target].token);
																	fprintf(code, "\tmov %s%c, dword [r6+%s_%s]\n", hash_table[target].token, state, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																	break;
															case ' ' : fprintf(code, "\tmov %s, [r6+%s_%s]\n", hash_table[target].token, hash_table[(global-HASH_OFFSET)].token, hash_table[token_stack[token]-HASH_OFFSET].token);
																	break;
														}
														break;
												}
												token++;
												atStackEnd(i);
											}
										} else {
											if (hash_table[token_stack[token]-HASH_OFFSET].token_type == TYPE_REG) {
												// We have a register!
												token++;	// Step forward 1
												if (token != i) {
													if ((token_stack[token] != TOKEN_MULTIPLY) &&
														(token_stack[token] != TOKEN_DIVIDE) &&
														(token_stack[token] != TOKEN_MODULUS) &&
														(token_stack[token] != TOKEN_S_MULTIPLY) &&
														(token_stack[token] != TOKEN_S_DIVIDE) &&
														(token_stack[token] != TOKEN_S_MODULUS)) {
															if (target != (token_stack[token-1]-HASH_OFFSET))
																// Only output if target and first operand are different.
																fprintf(code, "\tmov %s, %s\n", hash_table[target].token, hash_table[token_stack[token-1]-HASH_OFFSET].token);
														};
													state = token_stack[token];
													switch(state) {
														case TOKEN_AND:  // If our operation is a basic AND
															fprintf(code, "\tand %s, ", hash_table[target].token);
															break;
															
														case TOKEN_OR:
															fprintf(code, "\tor %s, ", hash_table[target].token);
															break;
															
														case TOKEN_XOR:
															fprintf(code, "\txor %s, ", hash_table[target].token);
															break;
															
														case TOKEN_ADD:
															fprintf(code, "\tadd %s, ", hash_table[target].token);
															break;
															
														case TOKEN_MINUS:
															fprintf(code, "\tsub %s, ", hash_table[target].token);
															break;
															
														case TOKEN_MULTIPLY:
															if ((token_stack[token-1]-HASH_OFFSET) != HASH_r0)
																abort("Multiply Operations REQUIRE r0 as source");
															fprintf(code, "\tmul ");
															break;
															
														case TOKEN_DIVIDE:
															if ((token_stack[token-1]-HASH_OFFSET) != HASH_r0)
																abort("Division Operations REQUIRE r0 as source");
															fprintf(code, "\tdiv ");
															break;
															
														case TOKEN_MODULUS:
															if ((token_stack[token-1]-HASH_OFFSET) != HASH_r0)
																abort("Modulus Operations REQUIRE r0 as source");
															fprintf(code, "\tdiv ");
															break;
															
														case TOKEN_S_MULTIPLY:
															if ((token_stack[token-1]-HASH_OFFSET) != HASH_r0)
																abort("Signed Multiply Operations REQUIRE r0 as source");
															fprintf(code, "\timul ");
															break;
															
														case TOKEN_S_DIVIDE:
															if ((token_stack[token-1]-HASH_OFFSET) != HASH_r0)
																abort("Signed Division Operations REQUIRE r0 as source");
															fprintf(code, "\tidiv ");
															break;
															
														case TOKEN_S_MODULUS:
															if ((token_stack[token-1]-HASH_OFFSET) != HASH_r0)
																abort("Signed Modulus Operations REQUIRE r0 as source");
															fprintf(code, "\tidiv ");
															break;

														case TOKEN_RSHIFT:
															fprintf(code, "\tshr %s, ", hash_table[target].token);
															break;
															
														case TOKEN_LSHIFT:
															fprintf(code, "\tshl %s, ", hash_table[target].token);
															break;

														case TOKEN_RROTATE:
															fprintf(code, "\tror %s, ", hash_table[target].token);
															break;
															
														case TOKEN_LROTATE:
															fprintf(code, "\trol %s, ", hash_table[target].token);
															break;
	
														default:
															abort("Invalid Construct");
															break;
													}
													// We have constructed our operand
													token++;
													// Now lets see what the second operand is...
													if ((token_stack[token] < TOKEN_OFFSET) || (token_stack[token] == TOKEN_MINUS)) {
														// Looks like an immediate
														if ((state == TOKEN_MULTIPLY) ||
															(state == TOKEN_DIVIDE) ||
															(state == TOKEN_MODULUS) ||
															(state == TOKEN_S_MULTIPLY) ||
															(state == TOKEN_S_DIVIDE) ||
															(state == TOKEN_S_MODULUS)) {
																// Mul, and div require a register!
																abort("Unexpected immediate value");
															}
														// We have an immediate load
														if (token_stack[token] == TOKEN_MINUS) {
															if ((state == TOKEN_RSHIFT) ||
																(state == TOKEN_LSHIFT) ||
																(state == TOKEN_RROTATE) ||
																(state == TOKEN_LROTATE)) {
																	// Shifts MUST have a positive!
																	abort("Shift/Rotate operations require a POSITIVE shift value");
															}
															token++;
															fprintf(code, "-");
														}
														outputNumber(i);
														fprintf(code, "\n");
													} else {
														// Must be a REG, so lets get rid of the rest;
														if (token_stack[token] < HASH_OFFSET)
															abort("Expected Token/Label");

														// Lets see if we have a shift operation, and handle appropriately.
														if ((state == TOKEN_RSHIFT) || (state == TOKEN_LSHIFT) ||
															(state == TOKEN_RROTATE) || (state == TOKEN_LROTATE)){
															if (((token_stack[token]-HASH_OFFSET) != HASH_r2) &&
																((token_stack[token]-HASH_OFFSET) != HASH_r2b))
																abort("Shift/Rotate Operations REQUIRE r2 / r2b or Immediate as second operand");
															fprintf(code, "r2b\n");
														} else {
															TokenIsLabelType(TYPE_REG);
															// Everything must be okay, so lets output our second operand.
															fprintf(code, "%s\n", hash_table[token_stack[token]-HASH_OFFSET].token);
														}
														// Load the destination register if required!
														switch(state) {
															case TOKEN_MULTIPLY:
															case TOKEN_DIVIDE:
															case TOKEN_S_MULTIPLY:
															case TOKEN_S_DIVIDE:
																if (target != HASH_r0)
																	fprintf(code, "\tmov %s, r0\n", hash_table[target].token);
																break;
															case TOKEN_MODULUS:
															case TOKEN_S_MODULUS:
																if (target != HASH_r3)
																	fprintf(code, "\tmov %s, r3\n", hash_table[target].token);
																break;
														}
														token++;
													}
													atStackEnd(i);
												} else {
													// We have a single register load!
													if (target != (token_stack[token-1]-HASH_OFFSET))
														// Don't output code, if r0 = r0; type is present.
														fprintf(code, "\tmov %s, %s\n", hash_table[target].token, hash_table[token_stack[token-1]-HASH_OFFSET].token);
												}
											} else {
												// We must have a proc!
												callProc((token_stack[token])-HASH_OFFSET, target, i);
											}
										}
									}
								}
							}
						} else {
							if (hash_table[token_stack[token]-HASH_OFFSET].token_type == TYPE_REG_SHORT) {
								// Look like we have a short reg...
								// This is going to be easy, as short regs can only be used with pointer operations.
								fprintf(code, "\tmov %s, [", hash_table[token_stack[token]-HASH_OFFSET].token);
								token++;
								TokenIs(TOKEN_EQUATE);
								token++;
								TokenIs(TOKEN_ARRAY_START);
								token++;
								if (token_stack[token] == TOKEN_ARRAY_END)
									abort("Unexpected end of memory reference");
								if (token_stack[token] < TOKEN_OFFSET) {
									//we have direct numerical reference
									outputNumber(i);
									token++;
									fprintf(code, "]\n");
								} else {
									//we should be dealing with a register
									TokenIsLabelType(TYPE_REG);
									fprintf(code, "%s", hash_table[token_stack[token]-HASH_OFFSET].token);
									token++;
									if (token_stack[token] == TOKEN_ADD){
										// Looks like a complex memory pointer operation.
										fprintf(code, "+");
										token++;
										if (token_stack[token] > TOKEN_OFFSET) {
											// Should be a reg?
											TokenIsLabelType(TYPE_REG);
											fprintf(code, "%s", hash_table[token_stack[token]-HASH_OFFSET].token); // Output the reg
											token++;
											// Here we should have either a + or a *
											if ((token_stack[token] != TOKEN_ADD) &&
												(token_stack[token] != TOKEN_MULTIPLY) &&
												(token_stack[token] != TOKEN_ARRAY_END))
												abort("+, * or ] Expected");
											if (token_stack[token] == TOKEN_ADD) {
												// We should have an immediate
												fprintf(code, "+");
												token++;
												if (token_stack[token] > TOKEN_OFFSET)
													abort("Immediate Expected");
												outputNumber(i);
											} else {
												if (token_stack[token] == TOKEN_MULTIPLY) {
													// Handle our multiply, else fall through (it should be an ARRAY_END).
													fprintf(code, "*");
													token++;
													// This part gets tricky, as we should only have 1,2,4 or 8 here!
													if (token_stack[token] > TOKEN_OFFSET)
														abort("Immediate Expected");
													if ((token_stack[token] != '1') &&
														(token_stack[token] != '2') &&
														(token_stack[token] != '4') &&
														(token_stack[token] != '8'))
														abort("Illformed pointer expression, please revise");
													fprintf(code, "%c", token_stack[token]);
													token++; // Output the number
													if (token_stack[token] < TOKEN_OFFSET){
														if (token_stack[token] != 'h') {
															abort("Unexpected Immediate");
														}
														token++; // Advance past the 'h'
													}
													if (token_stack[token] == TOKEN_ADD){
														fprintf(code, "+");
														token++;
														if (token_stack[token] < TOKEN_OFFSET) {
															outputNumber(i);
														} else {
															abort("Expected Immediate");
														}
													}
												}
											}
										} else {
											// Else output the displacement.
											outputNumber(i);
										}
									}  else {
										if (token_stack[token] == TOKEN_MULTIPLY) {
											// Handle our multiply, else fall through (it should be an ARRAY_END).
											fprintf(code, "*");
											token++;
											// This part gets tricky, as we should only have 1,2,4 or 8 here!
											if (token_stack[token] > TOKEN_OFFSET)
												abort("Immediate Expected");
											if ((token_stack[token] != '1') &&
												(token_stack[token] != '2') &&
												(token_stack[token] != '4') &&
												(token_stack[token] != '8'))
												abort("Illformed pointer expression, please revise");
											fprintf(code, "%c", token_stack[token]);
											token++; // Output the number
											if (token_stack[token] < TOKEN_OFFSET){
												if (token_stack[token] != 'h') {
													abort("Unexpected Immediate");
												}
												token++; // Advance past the 'h'
											}
											if (token_stack[token] == TOKEN_ADD){
												fprintf(code, "+");
												token++;
												if (token_stack[token] < TOKEN_OFFSET) {
													outputNumber(i);
												} else {
													abort("Expected Immediate");
												}
											}
										}
									}
									TokenIs(TOKEN_ARRAY_END);
									fprintf(code, "]\n");
									token++;
								}
							} else {
								// Whatever we have left treat as proc.
								callProc(token_stack[token]-HASH_OFFSET, HASH_r0, i);							
							}
						}
					}
				}
				token = i;
				break;
		}
	}
	token = 0;
	return(1);
}

unsigned int nextToken(){
	int i;
	unsigned int UTF32;
	while (isSpace(ch)) {
		//skip whitespace
		getChar();
	}
	if (ch == '/') { // Skip comments
		if (look_ahead_ch == '/'){
			while (ch != CR){
				getChar();
			}
			return(0);
			//nextToken();
		}
	}
	if (!isdigit(ch) && !isAlpha(ch)) {
		//process operator
		switch(ch) {
			case '\'' :
				insert_token_stack(TOKEN_STRING);
				if(DEBUG)
					printf("START STRING\n");
				getChar();
				while (ch != '\'') {
					if (ch == '\\') {
						switch (look_ahead_ch) {
							case 'n' :
								insert_token_stack(CR);
								getChar();
								getChar();
								if(DEBUG)
									printf("Output 0x%x , ch == %c\n", CR, ch);
								break;
							case 'r' :
								insert_token_stack(LF);
								getChar();
								getChar();
								if(DEBUG)
									printf("Output 0x%x , ch == %c\n", LF, ch);
								break;
							case 't' :
								insert_token_stack(TAB);
								getChar();
								getChar();
								if(DEBUG)
									printf("Output 0x%x , ch == %c\n", TAB, ch);
								break;
							case '\\' :
								insert_token_stack('\\');
								getChar();
								getChar();
								if(DEBUG)
									printf("Output \\, ch == %c\n", ch);
								break;
							case '\'' :
								insert_token_stack('\'');
								getChar();
								getChar();
								if(DEBUG)
									printf("Output \', ch == %c\n", ch);
								break;
							case '\0' :
								insert_token_stack('\0');
								getChar();
								getChar();
								if(DEBUG)
									printf("Output NULL, ch == NULL\n");
							default :
								insert_token_stack(ch);
								getChar();
								break;
						}
					} else {
						if (ch == 0xffffffff)
							return(0);
						// What we need to do is handle UTF-8 input correctly.
						if (ch < 0x7f) {
							insert_token_stack(ch);
						} else {
							// We must have a UTF-8 character.
							if (ch < 0xdf) {
								// we have a 2 byte sequence
								UTF32 = ch & 0x1f;
								UTF32 = UTF32 << 6;
								getChar(); // Get our second character
								if (ch < 0x7f)
									abort("Poor UTF-8 construct");
								UTF32 = UTF32 + (ch & 0x3f);
								insert_token_stack(UTF32);
							} else {
								if (ch < 0xf0) {
									// We have a 3 byte sequence
									UTF32 = ch & 0x0f;
									UTF32 = UTF32 << 6;
									getChar(); // Get our second character
									if (ch < 0x7f)
										abort("Poor UTF-8 construct");
									UTF32 = UTF32 + (ch & 0x3f);
									UTF32 = UTF32 << 6;
									getChar(); // Get our third character
									if (ch < 0x7f)
										abort("Poor UTF-8 construct");
									UTF32 = UTF32 + (ch & 0x3f);
									insert_token_stack(UTF32);
								} else {
									// We must have a 4 byte sequence
									UTF32 = ch & 0x0f;
									UTF32 = UTF32 << 6;
									getChar(); // Get our second character
									if (ch < 0x7f)
										abort("Poor UTF-8 construct");
									UTF32 = UTF32 + (ch & 0x3f);
									UTF32 = UTF32 << 6;
									getChar(); // Get our third character
									if (ch < 0x7f)
										abort("Poor UTF-8 construct");
									UTF32 = UTF32 + (ch & 0x3f);
									UTF32 = UTF32 << 6;
									getChar(); // Get our fourth character
									if (ch < 0x7f)
										abort("Poor UTF-8 construct");
									UTF32 = UTF32 + (ch & 0x3f);
									insert_token_stack(UTF32);
								}
							}
						}
						getChar();
					}
				}
				insert_token_stack(TOKEN_END_STRING);
				if(DEBUG)
					printf("END STRING\n");
				break;
			
			case '{' :
				process_token_stack(1);
				block();
				break;
				
			case '}' :
				insert_token_stack(TOKEN_BLOCK_END);
				break;
				
			case ';' :
				process_token_stack(0);
				break;
				
			case '=' :
				if (look_ahead_ch == '=') {
					getChar();
					insert_token_stack(TOKEN_EQUALS);
				} else {
					insert_token_stack(TOKEN_EQUATE);
				}
				break;	
				
			case '&' :
				if (look_ahead_ch == '&') {
					getChar();
					insert_token_stack(TOKEN_AND);
				} else {
					insert_token_stack(TOKEN_POINTER);
				}
				break;
				
			case '|' :
				insert_token_stack(TOKEN_OR);
				break;

			case '^' :
				insert_token_stack(TOKEN_XOR);
				break;
				
			case '!' :
				if (look_ahead_ch == '=') {
					getChar();
					insert_token_stack(TOKEN_NOTEQUALS);
				} else {
					insert_token_stack(TOKEN_NOT);
				}
				break;
				
			case '*' :
				insert_token_stack(TOKEN_MULTIPLY);
				break;
				
			case '+' :
				insert_token_stack(TOKEN_ADD);
				break;
				
			case '-' :
				insert_token_stack(TOKEN_MINUS);
				break;
				
			case '/' :
				insert_token_stack(TOKEN_DIVIDE);
				break;
				
			case '%' :
				insert_token_stack(TOKEN_MODULUS);
				break;
				
			case '(' :
				insert_token_stack(TOKEN_PARA_START);
				break;
				
			case ')' :
				insert_token_stack(TOKEN_PARA_END);
				break;
			case '[' :
				insert_token_stack(TOKEN_ARRAY_START);
				break;
				
			case ']' :
				insert_token_stack(TOKEN_ARRAY_END);
				break;
				
			case '<' :
				if (look_ahead_ch == '<') {
					getChar();
					if (look_ahead_ch == '<') {
						getChar();
						insert_token_stack(TOKEN_LROTATE);
					} else {
						insert_token_stack(TOKEN_LSHIFT);
					}
				} else {
					if (look_ahead_ch == '=') {
						getChar();
						insert_token_stack(TOKEN_LESSTHANEQUALS);
					} else {
						insert_token_stack(TOKEN_LESSTHAN);
					}
				}
				break;
				
			case '>' :
				if (look_ahead_ch == '>') {
					getChar();
					if (look_ahead_ch == '>') {
						getChar();
						insert_token_stack(TOKEN_RROTATE);
					} else {
						insert_token_stack(TOKEN_RSHIFT);
					}
				} else {
					if (look_ahead_ch == '=') {
						getChar();
						insert_token_stack(TOKEN_GREATERTHANEQUALS);
					} else {
						insert_token_stack(TOKEN_GREATERTHAN);
					}
				}
				break;

			case ',' :
			    insert_token_stack(TOKEN_COMMA);
				break;

			case '~' :	//Signed operation
				switch(look_ahead_ch){
					case '>' : getChar();
								if (look_ahead_ch == '=') {
									getChar();
									insert_token_stack(TOKEN_S_GREATERTHANEQUALS);
								} else {
									insert_token_stack(TOKEN_S_GREATERTHAN);
								}
								break;
								
					case '<' : getChar();
								if (look_ahead_ch == '=') {
									getChar();
									insert_token_stack(TOKEN_S_LESSTHANEQUALS);
								} else {
									insert_token_stack(TOKEN_S_LESSTHAN);
								}
								break;
								
					case '*' : getChar(); 
								insert_token_stack(TOKEN_S_MULTIPLY); 
								break;
								
					case '/' : getChar(); 
								insert_token_stack(TOKEN_S_DIVIDE); 
								break;
								
					case '%' : getChar(); 
								insert_token_stack(TOKEN_S_MODULUS); 
								break;
								
					default :
						abort("Unknown Signed operation");
						break;
				}
				break;

				
			default :
				if (ch == 0xffffffff){
					process_token_stack(0); // Clear the STACK
					return(0);
				}
				if ((ch == 0xef) && (look_ahead_ch == 0xbb)) {
					// we may have a BOM
					getChar(); // Get the next char
					if (look_ahead_ch != 0xbf)
						abort("Unknown Symbol");
					getChar(); // Move the BOM indicator 0xbf into ch.
				} else {
					abort("Unknown Symbol");
				}
				break;
		}
		getChar();
	} else {
		if (isdigit(ch)){
			//process digit
			insert_token_stack(ch);
			getChar();
			while (isxdigit(ch)){
				insert_token_stack(tolower(ch));
				getChar();
			}
			if ((ch == 'h')||(ch == 'H')){ // Include terminating 'h' if found?
				insert_token_stack('h');
				getChar();
			}
			if (isAlpha(ch)){
				abort("Unexpected Alpha");
			}
		} else {
			//process token
			
			//Clear our token buffer
			for (i = 0; i < TOKEN_MAX_SIZE; i++) {
				token_buffer[i] = 0;
			}
			
			// copy our input into the buffer
			toki = 0;
			while (isAlpha(ch) || isdigit(ch)) {
				token_buffer[toki] = ch;
				toki++;
				if (toki >= TOKEN_MAX_SIZE) abort("INTERNAL: Token Preprocessor Buffer Overflow!");
				getChar();
			}
			
			// get the hash
			token_hash = (ElfHash(&token_buffer[0])) % HASH_TABLE_SIZE + 1; //Can't have tokens = 0
			
			if (token_hash >= (HASH_TABLE_SIZE-1)) token_hash = 1;
			
			// Check for collision?
			if (hash_table[token_hash].hash == 0){ // Was ' != token_hash' for test??
				// No entry, so we just enter the hash into the table
				hash_table[token_hash].hash = token_hash;
				strcpy(&hash_table[token_hash].token, &token_buffer);
				if(DEBUG)
					printf("TOKEN : %s = 0x%x\n", hash_table[token_hash].token, hash_table[token_hash].hash);
			} else {
				// Let's see if we have the same string
				if (strcmp(&token_buffer, &hash_table[token_hash].token)) {
					// If the string are different, then we have a real problem!
					if(DEBUG)
						printf("Hash Collision Detected 0x%x = %s = %s\n", token_hash, hash_table[token_hash].token, token_buffer);
					i = 0;
					while ((hash_table[token_hash].hash != 0) && strcmp(&token_buffer, &hash_table[token_hash].token)) {
						token_hash++; // Linear refactor the hash!
						i++;
						if (i >= HASH_TABLE_SIZE-1) {
							if(DEBUG){
								printf("HASH TABLE----------\n");
								for (i = 0; i < HASH_TABLE_SIZE; i++) {
									if (hash_table[i].hash != 0)
										printf("0x%x -> 0x%x = %s\n", i, hash_table[i].hash, hash_table[i].token);
								};
							}
							abort("INTERNAL: Hash Table Overflow!");
						}
						if (token_hash >= HASH_TABLE_SIZE-1) {
							token_hash = 1; // Wrap around so we don't go off the table
						}
					}
					hash_table[token_hash].hash = token_hash;
					strcpy(&hash_table[token_hash].token, &token_buffer);
					if(DEBUG)
						printf("TOKEN : %s = 0x%x\n", hash_table[token_hash].token, hash_table[token_hash].hash);
				}
			}
			
			insert_token_stack(token_hash+HASH_OFFSET);
		}
	}
	return(0);
}

int end_block_else() {
	unsigned int old_block_num;
	block_level--;
	if(DEBUG)
		printf("Current Block Level is %d\n", block_level);
	if (block_level < 1)
		abort("Unexpected }");
	if (block_level == 1) {
		abort("Unexpected ELSE");
	} else {
		if (if_while_stack[block_level].type == HASH_if) {
			// Lets terminate the if statement
			old_block_num = if_while_stack[block_level].offset;
			if_while_stack[block_level].offset = block_num;
			fprintf(code, "\tjmp .B0_END_BLOCK_0000%d:\n", if_while_stack[block_level].offset);
			fprintf(code, "\t.B0_END_BLOCK_0000%d:\n", old_block_num);
		} else {
			abort("Unexpected ELSE");
		}
	}
	return(0);
}

int end_block(){
	block_level--;
	if(DEBUG)
		printf("Current Block Level is %d\n", block_level);
	if (block_level < 1)
		abort("Unexpected }");
	if (block_level == 1) {
		fprintf(code, "\tmov r0, 0\n\tret\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
		fprintf(code, "; End %s Function Code;\n", hash_table[(global-HASH_OFFSET)].token);
		fprintf(code, ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n");				
		fprintf(data, "\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
		fprintf(data, "; End %s Function Variables ;\n", hash_table[(global-HASH_OFFSET)].token);
		fprintf(data, ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n");				
		hash_table[(global-HASH_OFFSET)].local_offset = local_var_offset;
		global = 0;
	} else {
		// We most likely have ended a if or a while. Let's ensure that we terminate the block 
		// correctly.
		if (if_while_stack[block_level].type == HASH_if) {
			// Lets terminate the if statement
			fprintf(code, "\t.B0_END_BLOCK_0000%d:\n", if_while_stack[block_level].offset);
		} else {
			if (if_while_stack[block_level].type == HASH_while) {
				// Lets terminate the while block correctly
				fprintf(code, "\tcmp %s, %s\n", hash_table[if_while_stack[block_level].if_while_test1].token, hash_table[if_while_stack[block_level].if_while_test2].token );
				switch (if_while_stack[block_level].comparison) {
					case TOKEN_EQUALS :	fprintf(code, "\tje .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_NOTEQUALS : fprintf(code, "\tjne .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_LESSTHAN : fprintf(code, "\tjb .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset);	break;
					case TOKEN_GREATERTHAN : fprintf(code, "\tja .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_LESSTHANEQUALS : fprintf(code, "\tjbe .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset);	break;
					case TOKEN_GREATERTHANEQUALS : fprintf(code, "\tjae .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_S_LESSTHAN : fprintf(code, "\tjl .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset);	break;
					case TOKEN_S_GREATERTHAN : fprintf(code, "\tjg .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
					case TOKEN_S_LESSTHANEQUALS : fprintf(code, "\tjle .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset);	break;
					case TOKEN_S_GREATERTHANEQUALS : fprintf(code, "\tjge .B0_END_BLOCK_0000%d\n", if_while_stack[block_level].offset); break;
				}
			}
		}
		// Else fall through
	}
	return(0);
}

int block(){
	block_level++;
	if(DEBUG)
		printf("Current Block Level is %d\n", block_level);
	block_num++;
	getChar();				// Get next character
	if (ch ==  0xffffffff) { //If EOF
		fclose(file[file_stack_ptr].handle); // Close current file
		file_stack_ptr--;	//Move the file stack pointer down one
		if (file_stack_ptr < 0) {
			return(0);		// If we are now off the stack, exit
		}
		process_token_stack(0);
							// else process remaining tokens to flush the stack
							// before moving onto another file
		getChar();			// and get the next char from the previous file, so we can continue
		block_level-=2;		//Adjust block level due to way EOF is handled.
	}
	while (ch != 0xffffffff) {
		nextToken();		// get the next token, and set token variable
	}
	return(0);
}

void include_standard_output() {
	fprintf(file[0].handle, "\n;Register renaming\n\nr0 equ rax\n");
	fprintf(file[0].handle, "r0d equ eax\n");
	fprintf(file[0].handle, "r0w equ ax\n");
	fprintf(file[0].handle, "r0b equ al\n");
	fprintf(file[0].handle, "r1 equ rbx\n");
	fprintf(file[0].handle, "r1d equ ebx\n");
	fprintf(file[0].handle, "r1w equ bx\n");
	fprintf(file[0].handle, "r1b equ bl\n");
	fprintf(file[0].handle, "r2 equ rcx\n");
	fprintf(file[0].handle, "r2d equ ecx\n");
	fprintf(file[0].handle, "r2w equ cx\n");
	fprintf(file[0].handle, "r2b equ cl\n");
	fprintf(file[0].handle, "r3 equ rdx\n");
	fprintf(file[0].handle, "r3d equ edx\n");
	fprintf(file[0].handle, "r3w equ dx\n");
	fprintf(file[0].handle, "r3b equ dl\n");
	fprintf(file[0].handle, "r4 equ rdi\n");
	fprintf(file[0].handle, "r4d equ edi\n");
	fprintf(file[0].handle, "r4w equ di\n");
	fprintf(file[0].handle, "r4b equ dil\n");
	fprintf(file[0].handle, "r5 equ rsi\n");
	fprintf(file[0].handle, "r5d equ esi\n");
	fprintf(file[0].handle, "r5w equ si\n");
	fprintf(file[0].handle, "r5b equ sil\n");
	fprintf(file[0].handle, "r6 equ rbp\n");
	fprintf(file[0].handle, "r6d equ ebp\n");
	fprintf(file[0].handle, "r6w equ bp\n");
	fprintf(file[0].handle, "r6b equ bpl\n");
	fprintf(file[0].handle, "r7 equ rsp\n");
	fprintf(file[0].handle, "r7d equ esp\n");
	fprintf(file[0].handle, "r7w equ sp\n");
	fprintf(file[0].handle, "r7b equ spl\n\n");
	
	fprintf(file[0].handle, ";Default Macros\n");
	fprintf(file[0].handle, "macro UTF16_STRING name, [string]\n{\n");
	fprintf(file[0].handle, "common\n\tname:\nlocal label,label2\n\tlabel:\n");
	fprintf(file[0].handle, "\tdw (label2-label)/2\n\tdw (label2-label)/2\n");
	fprintf(file[0].handle, "\tdw string\n\tlabel2:\n}\n\n");
}

int main(int argc, char *argv[]){
	unsigned int i;
	char *pdest;
	int Help = 0;
	int Version = 0;
	int have_file = 0;
	time_start = clock();
	
	if(argc > 1){
		for(i=0;i<argc;i++){
			if(!strcmp(argv[i], "-DEBUG"))
				DEBUG = 1;
			if(!strcmp(argv[i], "-?"))
				Help = 1;
			if(!strcmp(argv[i], "-h"))
				Help = 1;
			if(!strcmp(argv[i], "-v"))
				Version = 1;
			if((argv[i][0] == '-') && (argv[i][1] == 'i')){
				path = &argv[i][2]; // Set pointer to the CLI environment
			}
			if((argv[i][0] == '-') && (argv[i][1] == 'f')){
				//Set the type of Source Output = SOURCE_TYPE
				if(!strcmp(argv[i], "-fflat")){
					SOURCE_TYPE = SOURCE_FLAT;
				} else {
					if(!strcmp(argv[i], "-f0f")){
						SOURCE_TYPE = SOURCE_0F;
					} else {
						if(!strcmp(argv[i], "-felf")){
							SOURCE_TYPE = SOURCE_ELF;
						} else {
							if(!strcmp(argv[i], "-fpe")){
								SOURCE_TYPE = SOURCE_PE;
							} else {
								printf("Base Compiler (0fh) v%s\nCopyright (c) 2005, Darran Kartaschew\nAll rights reserved.\n", B0_VERSION);
								printf("Error: Unknown Output Format?");
								exit(1);
							}
						}
					}
				}
			}
			if((argv[i][0] != '-') && (i != 0) && (have_file == 0)){
				// Else let's assume for now that it's our filename?
				strcpy(filename,argv[i]);
				have_file = 1;
			}
		}
	} else {
		PrintHelp();
	}
	if ((Help)||(!have_file))
		PrintHelp();

	if (Version){
		printf("Base Compiler (0fh) v%s\nCopyright (c) 2005, Darran Kartaschew\nAll rights reserved.\n", B0_VERSION);
		exit(0);
	}

	b0_env = getenv("B0_INCLUDE");
	total_paths = 0;
	if(path) scan_env(path);
	if(b0_env) scan_env(b0_env);
	// If you have any directories to include they should already be added.
	// total_paths = number of paths we can search!
	
	if(DEBUG){
		printf("Base Compiler (0fh) v%s\nCopyright (c) 2005, Darran Kartaschew\nAll rights reserved.\n", B0_VERSION);
		switch(SOURCE_TYPE){
			case SOURCE_FLAT: printf("Output Format: FLAT\n"); break;
			case SOURCE_0F: printf("Output Format: 0F\n"); break;
			case SOURCE_ELF: printf("Output Format: ELF\n"); break;
			case SOURCE_PE: printf("Output Format: PE\n"); break;
		}
		for (i=0;i<total_paths;i++){
			printf("search path = %s\n", paths[i]);
	}

	}
	
	for (i = 0; i < HASH_TABLE_SIZE; i++) {
		hash_table[i].hash = 0;
	};
	
	//Setup reserved labels within the hash table...
	insert_token(&TOKEN_IF[0], TYPE_KEYWORD);
	insert_token(&TOKEN_ELSE[0], TYPE_KEYWORD);
	insert_token(&TOKEN_WHILE[0], TYPE_KEYWORD);
	insert_token(&TOKEN_RETURN[0], TYPE_PROC);
	insert_token(&TOKEN_EXIT[0], TYPE_PROC);
	insert_token(&TOKEN_PROC[0], TYPE_KEYWORD);
	insert_token(&TOKEN_LIB[0], TYPE_KEYWORD);
	insert_token(&TOKEN_ASM[0], TYPE_KEYWORD);
	insert_token(&TOKEN_PUSH[0], TYPE_KEYWORD);
	insert_token(&TOKEN_POP[0], TYPE_KEYWORD);
	insert_token(&TOKEN_SYSCALL[0], TYPE_KEYWORD);
	insert_token(&TOKEN_SYSRET[0], TYPE_KEYWORD);
	
	insert_token(&TOKEN_R0[0], TYPE_REG);
	insert_token(&TOKEN_R1[0], TYPE_REG);
	insert_token(&TOKEN_R2[0], TYPE_REG);
	insert_token(&TOKEN_R3[0], TYPE_REG);
	insert_token(&TOKEN_R4[0], TYPE_REG);
	insert_token(&TOKEN_R5[0], TYPE_REG);
	insert_token(&TOKEN_R6[0], TYPE_REG);
	insert_token(&TOKEN_R7[0], TYPE_REG);
	insert_token(&TOKEN_R8[0], TYPE_REG);
	insert_token(&TOKEN_R9[0], TYPE_REG);
	insert_token(&TOKEN_R10[0], TYPE_REG);
	insert_token(&TOKEN_R11[0], TYPE_REG);
	insert_token(&TOKEN_R12[0], TYPE_REG);
	insert_token(&TOKEN_R13[0], TYPE_REG);
	insert_token(&TOKEN_R14[0], TYPE_REG);
	insert_token(&TOKEN_R15[0], TYPE_REG);

	insert_token(&TOKEN_R0B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R1B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R2B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R3B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R4B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R5B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R6B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R7B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R8B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R9B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R10B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R11B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R12B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R13B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R14B[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R15B[0], TYPE_REG_SHORT);

	insert_token(&TOKEN_R0W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R1W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R2W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R3W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R4W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R5W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R6W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R7W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R8W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R9W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R10W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R11W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R12W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R13W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R14W[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R15W[0], TYPE_REG_SHORT);

	insert_token(&TOKEN_R0D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R1D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R2D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R3D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R4D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R5D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R6D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R7D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R8D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R9D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R10D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R11D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R12D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R13D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R14D[0], TYPE_REG_SHORT);
	insert_token(&TOKEN_R15D[0], TYPE_REG_SHORT);

	insert_token(&TOKEN_FP0[0], TYPE_REG_FPU);
	insert_token(&TOKEN_FP1[0], TYPE_REG_FPU);
	insert_token(&TOKEN_FP2[0], TYPE_REG_FPU);
	insert_token(&TOKEN_FP3[0], TYPE_REG_FPU);
	insert_token(&TOKEN_FP4[0], TYPE_REG_FPU);
	insert_token(&TOKEN_FP5[0], TYPE_REG_FPU);
	insert_token(&TOKEN_FP6[0], TYPE_REG_FPU);
	insert_token(&TOKEN_FP7[0], TYPE_REG_FPU);

	insert_token(&TOKEN_ZERO[0], TYPE_REG);
	insert_token(&TOKEN_M8[0], TYPE_KEYWORD);
	insert_token(&TOKEN_M16[0], TYPE_KEYWORD);
	insert_token(&TOKEN_M32[0], TYPE_KEYWORD);
	insert_token(&TOKEN_M64[0], TYPE_KEYWORD); 
	insert_token(&TOKEN_M80[0], TYPE_KEYWORD); 
	insert_token(&TOKEN_M128[0], TYPE_KEYWORD); 
	insert_token(&TOKEN_M256[0], TYPE_KEYWORD); 
	insert_token(&TOKEN_M512[0], TYPE_KEYWORD); 

	state = 0;			// Reset code state to null;
	file_stack_ptr = 0;
	local_var_offset = 0;
	dynamic_string_count = 0; //Number of dynamic string decl.
    //file = stdin;		// Set source to stdin for testing
	if(DEBUG)
		printf("Filename = %s\n", filename);
	
	file[file_stack_ptr].handle = fopen(filename, "r");
	if (!file[file_stack_ptr].handle){
		printf("ERROR: Unable to open file: %s\n", filename);
		exit(1);
	} else {
		strcpy(file[file_stack_ptr].filename, filename);
		file[file_stack_ptr].line_count = 1;
	};
	
	// Open our first pass asm files
	code = fopen("c_output.tmp", "w+");
	data = fopen("d_output.tmp", "w+");

	if (!code){
		printf("ERROR: Unable to create temp file");
		exit(1);
	}
	if (!data){
		printf("ERROR: Unable to create temp file");
		exit(1);
	}

	
	look_ahead_ch = 0; 	// Prime the current char buffer
	token = 0;
	global = 0;			// We start from a global level
	block_level = 0;
	block_num = 0;
	while (file_stack_ptr >= 0) {
		// As long as we have a file to read, let's keep going
		block();
	}
	if(DEBUG){
		printf("EOF reached\n");
		//For testing, dump the hash table!
		printf("HASH TABLE----------\n");
		for (i = 0; i < HASH_TABLE_SIZE; i++) {
			if (hash_table[i].hash != 0)
				printf("0x%x -> 0x%x = %s ,Type: 0x%x\n", i, hash_table[i].hash, hash_table[i].token, hash_table[i].token_type);
		};
	}
	
	fclose(file[0].handle);				// Close our source file
	rewind(code);
	rewind(data);
	strcpy(filename, file[0].filename); // Let's get our original name
	
	pdest = strrchr(filename, '.');
	if (pdest != NULL) {
		i = pdest - filename;
		if (DEBUG) 
			printf("%s = %d\n", filename, i);
		filename[i] = '\0';			// Truncate the string at the last '.'
	}
	strcat(filename, ".asm");			// Append .asm to the end!
	
	file[0].handle = fopen(filename, "w");
	if (!file[0].handle){
		printf("ERROR: Unable to create file: %s\n", filename);
		exit(1);
	}
	
	switch(SOURCE_TYPE){
		case SOURCE_PE: 			
			fprintf(file[0].handle, ";; B0 EXECUTABLE\n;; PE FORMAT\n\n");
			include_standard_output();  // Include default equates and macros.
			fprintf(file[0].handle, "format PE\nuse64\norg 0h\n\nstart:\n");
			fprintf(file[0].handle, "\tcall main\n");
			fprintf(file[0].handle, "\n_B0_sys_exit:\n");
			fprintf(file[0].handle, "\tret\n");
			fprintf(file[0].handle, "\n;Since we are alpha, then a simple 'ret' should be fine?\n");
			ch = fgetc(code);
			while (ch != 0xffffffff){
				fprintf(file[0].handle, "%c", ch);
				ch = fgetc(code);
			}
			ch = fgetc(data);
			while (ch != 0xffffffff){
				fprintf(file[0].handle, "%c", ch);
				ch = fgetc(data);
			}
			break;

		case SOURCE_ELF: 
			fprintf(file[0].handle, ";; B0 EXECUTABLE\n;; ELF64 FORMAT for Linux\n\n");
			fprintf(file[0].handle, "format ELF64 executable\nuse64\nentry start\n\n");
			include_standard_output();  // Include default equates and macros.
			fprintf(file[0].handle, "macro syscall\n{\n");
			fprintf(file[0].handle, "\tint 80h\n}\n\n");

			fprintf(file[0].handle, "\n\nsection readable writeable\n\n");
			ch = fgetc(data);
			while (ch != 0xffffffff){
				fprintf(file[0].handle, "%c", ch);
				ch = fgetc(data);
			}
			
			fprintf(file[0].handle, "\nsection readable executable\n\nstart:\n\tcall main\n");
			fprintf(file[0].handle, "\n_B0_sys_exit:\n");
			fprintf(file[0].handle, "\tmov ebx,eax ;our exit code\n\tmov eax,1\n\tint 0x80\n");
			fprintf(file[0].handle, "\n;We assume Linux output for ELF64?\n");
			ch = fgetc(code);
			while (ch != 0xffffffff){
				fprintf(file[0].handle, "%c", ch);
				ch = fgetc(code);
			}
			fprintf(file[0].handle, "\n\n;EOF\n");
			break;

		case SOURCE_FLAT:
			fprintf(file[0].handle, ";; B0 EXECUTABLE\n;; FLAT FORMAT\n\n");
			include_standard_output();  // Include default equates and macros.
			fprintf(file[0].handle, "macro syscall\n{\n");
			fprintf(file[0].handle, "\tint 0ffh\n}\n\n");
			fprintf(file[0].handle, "use64\norg 0h\n\nstart:\n");
			fprintf(file[0].handle, "\tcall main\n");
			fprintf(file[0].handle, "\n_B0_sys_exit:\n");
			fprintf(file[0].handle, "\tret\n");
			fprintf(file[0].handle, "\n;Since we are flat, then a simple 'ret' should be fine?\n");
			ch = fgetc(data);
			while (ch != 0xffffffff){
				fprintf(file[0].handle, "%c", ch);
				ch = fgetc(data);
			}
			ch = fgetc(code);
			while (ch != 0xffffffff){
				fprintf(file[0].handle, "%c", ch);
				ch = fgetc(code);
			}
			break;
		case SOURCE_0F:
			fprintf(file[0].handle, ";; B0 EXECUTABLE\n;; 0F FORMAT\n\n");
			include_standard_output();  // Include default equates and macros.
			fprintf(file[0].handle, "macro syscall\n{\n");
			fprintf(file[0].handle, "\tint ffh\n}\n\n");
			fprintf(file[0].handle, "use64\norg 100000h\n");
			fprintf(file[0].handle, "db '0FEXFLAT'\n");
			fprintf(file[0].handle, "_B0_ENTRY dq start\n");
			fprintf(file[0].handle, "_B0_CODE_START dq start\n");
			fprintf(file[0].handle, "_B0_CODE_SIZE dq (_B0_CODE_END - start)\n");
			fprintf(file[0].handle, "_B0_DATA_START dq (_B0_DATA_END - _B0_DATA)\n");
			fprintf(file[0].handle, "_B0_DATA_SIZE dq start\n");
			fprintf(file[0].handle, "_B0_STACK dq 100000h ; 1MB stack\n");
			fprintf(file[0].handle, "_B0_LOCAL_THREAD dq 100000h \n");
			fprintf(file[0].handle, "\n_B0_DATA:\n");
			ch = fgetc(data);
			while (ch != 0xffffffff){
				fprintf(file[0].handle, "%c", ch);
				ch = fgetc(data);
			}
			fprintf(file[0].handle, "_B0_DATA_END:\n");
			fprintf(file[0].handle, "align 16\n\nstart:\n");
			fprintf(file[0].handle, "\tcall main\n");
			fprintf(file[0].handle, "\n_B0_sys_exit:\n");
			fprintf(file[0].handle, "\tret\n");
			fprintf(file[0].handle, "\n;Since we are flat, then a simple 'ret' should be fine?\n");
			ch = fgetc(code);
			while (ch != 0xffffffff){
				fprintf(file[0].handle, "%c", ch);
				ch = fgetc(code);
			}
			fprintf(file[0].handle, "_B0_CODE_END:\n");
			break;
	}
	
	time_end = clock();
	duration = (double)(time_end - time_start) / CLOCKS_PER_SEC;
	if(DEBUG)
		printf( "Processing Time: %2.3f seconds\n", duration );
	fclose(code);
	fclose(data);
	_unlink("c_output.tmp");
	_unlink("d_output.tmp");
	fclose(file[0].handle);
}
