Add code generator to assembler, re compile colors.dat with assembler
diff --git a/as/as.c b/as/as.c
index 2ff5c36..1d72d97 100644
--- a/as/as.c
+++ b/as/as.c
@@ -4,6 +4,8 @@
 #include "../mnemonics.h"
 #include "map.h"
 
+#include <endian.h>
+#include <stdio.h>
 #include <string.h>
 #include <ctype.h>
 #include <stdbool.h>
@@ -20,6 +22,8 @@
 
 #define ERR "\033[31m"
 #define RESET "\033[0m"
+#define MAX_LEN (0xFFFF - 0x600)
+#define MAX_INSTS (MAX_LEN / 2)
 
 typedef struct
 {
@@ -35,6 +39,13 @@
 	};
 } inst_t;
 
+typedef struct ll_node
+{
+	struct ll_node *last;
+	char name[32];
+	uint16_t addr;
+} ll_node_t;
+
 // Normal strtok() counts 2 seperators as one, ie asdf\n\njlk is 2 lines.
 // This functions counts that as 3 lines, and will return an empty line in between.
 char *strtok_fix(char *string, const char *token)
@@ -65,6 +76,12 @@
 	return pos;
 }
 
+void putshort(uint16_t a, FILE *out)
+{
+	uint16_t le = htole16(a);
+	fwrite(&le, sizeof(uint16_t), 1, out);
+}
+
 void print_inst(inst_t *arg)
 {
 	char *arg_types =
@@ -150,6 +167,7 @@
 		(*code)++;
 		return start;
 	}
+	printf(">> lkl: **code == %c %x\n", **code, **code);
 
 	*code = start;
 
@@ -302,13 +320,13 @@
 		{
 			inst->arg_type = ARG_16;
 			inst->long_arg = num;
-			return true;
+			return ws_end(&code);
 		}
 		else if ((lbl = parse_label_name(&code)))
 		{
 			inst->arg_type = ARG_ABS;
 			strncpy(inst->label, lbl, 32);
-			return true;
+			return ws_end(&code);
 		}
 		break;
 
@@ -339,7 +357,7 @@
 
 		inst->arg_type = ARG_16;
 		inst->long_arg = num;
-		return true;
+		return ws_end(&code);
 
 	case AM_AX:
 	case AM_ZPX:
@@ -359,14 +377,17 @@
 			inst->arg_type = ARG_8;
 			inst->byte_arg = num8;
 		}
+		printf("Parsing AM_* worked, now parsing ,\n");
 		if (!skip(&code, ","))
 			return false;
 
 		skip_ws(&code);
-
-		if (tolower(*code) != (am == AM_AY || am == AM_ZPY ? 'y' : 'x'))
+		printf(", worked yup\n");
+		char reg = (am == AM_AY || am == AM_ZPY ? 'y' : 'x');
+		printf("reg is %c, *code is %c %x\n", reg, tolower(*code), tolower(*code));
+		if (tolower(*code) != reg)
 			return false;
-
+		(code)++;
 		return ws_end(&code);
 
 	case AM_ZIX:
@@ -413,15 +434,30 @@
 	return false;
 }
 
+// Since program counter can never be < $600, return 0 on failure
+uint16_t ll_find(ll_node_t *head, char *name)
+{
+	ll_node_t *last = head;
+	while (last)
+	{
+		head = last;
+		if (!strcasecmp(head->name, name))
+			return head->addr;
+		last = head->last;
+	}
+	return 0;
+}
+
 uint32_t assemble(char *code, FILE *out)
 {
-	uintptr_t num_insts = 0,
-		pc = 0x600;
+	uint16_t num_insts = 0;
+	uint16_t pc = 0x600;
 	uint32_t line_no = 1;
-	map_t *labels = new_map();
+	ll_node_t *last_node = NULL;
 	char *line,
 		*orig_line,
 		*line_start;
+	inst_t **insts = calloc(sizeof(inst_t), MAX_INSTS);
 
 	printf("Assembling File\n");
 	printf("%s\n", code);
@@ -435,10 +471,11 @@
 		
 		if (*line == 0)
 			goto end_of_line;
-		printf("line %d: \033[36m%.12s\033[0m\n", line_no, line);
 		
 		skip_ws(&line);
-
+		
+		printf("line %d: \033[36m%.12s\033[0m\n", line_no, line);
+		
 		if (is_eol(*line))
 		{
 			printf("skip_ws() brought us to EOL\n");
@@ -446,26 +483,30 @@
 		}
 		
 		char *label = parse_label(&line);
+		printf(">> label == %.5s %p\n", label, label);
 		skip_ws(&code);
-		if (is_eol(*line))
-			goto end_of_line;
+		//if (is_eol(*line))
+		//	goto end_of_line;
 		char *mn = parse_inst(&line);
-		printf(" skipping %d ", skip_ws(&line));
-		//printf("\033[33m%s\033[0m\n", line);
 		
 		bool no_argument = false;
-		printf("eol is %c ($%x)\n", *line, *line);
 		if (is_eol(*line))
 		{
 			no_argument = true;
-			printf("... no argument\n");
 		}
 		int32_t mnemonic = -1;
 
 		if (label)
 		{
-			map_set(labels, label, (void *)pc);
-			printf("Set label %s at $%lx\n", label, pc);
+			printf("Storing label %s\n", label);
+			ll_node_t *head = malloc(sizeof(ll_node_t));
+			head->last = last_node;
+			strncpy(head->name, label, 32);
+			// strncpy won't zero the last byte if its over 32 bytes long
+			head->name[31] = 0;
+			head->addr = pc;
+			last_node = head;
+			printf("Set label %s at $%x\n", label, pc);
 		}
 
 		if (mn)
@@ -479,39 +520,113 @@
 			MNEMONICS
 			{
 				printf(ERR "Could not parse instruction on line %d\n%s\n" RESET, line_no, orig_line);
+				free(line_start);
 				goto cleanup;
 			}
 #undef MN
 
 			printf("Got instruction %s %d\n", mn, mnemonic);
 
-			inst_t arg;
+			inst_t *arg = malloc(sizeof(inst_t));
+			arg->line = line_no;
 			// printf("Parsing '%s'\n", line);
 #define INST(_mn, am, op, len) \
 			if ((no_argument && (_mn == AM_IMP || _mn == AM_ACC))		\
-				 || (mnemonic == _mn && parse_arg(line, am, &arg)))		\
+				 || (mnemonic == _mn && parse_arg(line, am, arg)))		\
 			{															\
-				arg.opcode = op;										\
+				printf("AM_ succeeded: %s\n", #am);						\
+				arg->opcode = op;										\
 				pc += len;												\
-				print_inst(&arg);										\
+				print_inst(arg);										\
 			}															\
 			else
 
 			INSTRUCTIONS
 			{
 				printf("\033[31mCould not be parsed: %s '%s'\033[0m\n", mn, line);
+				free(line_start);
+				goto cleanup;
 			}
 #undef INST
+
+			insts[num_insts++] = arg;
 		}
 	end_of_line:
 		line_no++;
-		printf("Line is %d\n", line_no);
 		orig_line = strtok_fix(NULL, "\n");
 		free(line_start);
 	}
 
+	// Generate machine code
+	for (int i = 0, curr_pc = 0x600; insts[i]; i++)
+	{
+		putc(insts[i]->opcode, out);
+
+		switch (insts[i]->arg_type)
+		{
+		case ARG_8:
+			putc(insts[i]->byte_arg, out);
+			curr_pc += 2;
+			break;
+		case ARG_16:
+			putshort(insts[i]->long_arg, out);
+			curr_pc += 3;
+			break;
+		case ARG_8REL:
+			putc(insts[i]->rel_arg, out);
+			curr_pc += 2;
+			break;
+		case ARG_ABS:
+		{
+			uint16_t lbl;
+			if (!(lbl = ll_find(last_node, insts[i]->label)))
+			{
+				printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n", insts[i]->line, insts[i]->label);
+				goto cleanup;
+			}
+			curr_pc += 3;
+
+			putshort(lbl, out);
+			break;
+		}
+		case ARG_REL:
+		{
+			uint16_t lbl;
+			if (!(lbl = ll_find(last_node, insts[i]->label)))
+			{
+				printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n", insts[i]->line, insts[i]->label);
+				goto cleanup;
+			}
+			curr_pc += 2;
+			int16_t diff = lbl - curr_pc;
+			printf("ARG_REL, pc (after) == %x, diff = %d\n", curr_pc, diff);
+			if ((diff < 0 ? -diff : diff) > 0xFF)
+			{
+				printf(ERR "Error on line %d: label '%s' is too far away for a relative jump" RESET "\n", insts[i]->line, insts[i]->label);
+				printf("pc == %hx, label is at %hx\n", curr_pc, lbl);
+				goto cleanup;
+			}
+			putshort((uint8_t) diff, out);
+			break;
+		}
+		default:
+			curr_pc++;
+		}
+	}
+	
 cleanup:
-	free_map(labels);
+	printf("-----\n");
+	printf("At end, there are %d instructions\n", num_insts);
+	while (last_node)
+	{
+		ll_node_t *curr_node = last_node;
+		last_node = curr_node->last;
+		free(curr_node);
+	}
+	for (int i = 0; insts[i]; i++)
+		free(insts[i]);
+	free(insts);
+	fflush(out);
 
 	return num_insts;
 }