changeset 370:8764142b3192

Convert internal error/warning handling framework to a new unified system Replace the ad hoc error and warning handling with a new system that codifies the errors with specific codes. This makes it possible in the future for error numbers to be used for testing and other purposes. It also makes sure the error strings themselves are consistent. Thanks to Erik G <erik@6809.org> for the patch.
author William Astle <lost@l-w.ca>
date Mon, 22 Jun 2015 18:49:38 -0600
parents 682524a1f32f
children 2593fd529be5
files lwasm/insn_bitbit.c lwasm/insn_gen.c lwasm/insn_indexed.c lwasm/insn_logicmem.c lwasm/insn_rel.c lwasm/insn_rlist.c lwasm/insn_rtor.c lwasm/insn_tfm.c lwasm/lwasm.c lwasm/lwasm.h lwasm/macro.c lwasm/os9.c lwasm/pass1.c lwasm/pass2.c lwasm/pass4.c lwasm/pass5.c lwasm/pass6.c lwasm/pragma.c lwasm/pseudo.c lwasm/section.c lwasm/struct.c lwasm/symbol.c
diffstat 22 files changed, 332 insertions(+), 243 deletions(-) [+]
line wrap: on
line diff
--- a/lwasm/insn_bitbit.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/insn_bitbit.c	Mon Jun 22 18:49:38 2015 -0600
@@ -46,39 +46,39 @@
 	}
 	else
 	{
-		lwasm_register_error(as, l, "Bad register");
+		lwasm_register_error(as, l, E_REGISTER_BAD);
 		return;
 	}
 	
 	if (*(*p)++ != ',')
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	lwasm_save_expr(l, 0, e);
 	if (*(*p)++ != ',')
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	lwasm_save_expr(l, 1, e);
 
 	if (*(*p)++ != ',')
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 
@@ -89,7 +89,7 @@
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	lwasm_save_expr(l, 2, e);
@@ -106,26 +106,26 @@
 	e = lwasm_fetch_expr(l, 0);
 	if (!lw_expr_istype(e, lw_expr_type_int))
 	{
-		lwasm_register_error(as, l, "Bit number must be fully resolved");
+		lwasm_register_error(as, l, E_BITNUMBER_UNRESOLVED);
 		return;
 	}
 	v1 = lw_expr_intval(e);
 	if (v1 < 0 || v1 > 7)
 	{
-		lwasm_register_error(as, l, "Invalid bit number");
+		lwasm_register_error(as, l, E_BITNUMBER_INVALID);
 		v1 = 0;
 	}
 
 	e = lwasm_fetch_expr(l, 1);
 	if (!lw_expr_istype(e, lw_expr_type_int))
 	{
-		lwasm_register_error(as, l, "Bit number must be fully resolved");
+		lwasm_register_error(as, l, E_BITNUMBER_UNRESOLVED);
 		return;
 	}
 	v2 = lw_expr_intval(e);
 	if (v2 < 0 || v2 > 7)
 	{
-		lwasm_register_error(as, l, "Invalid bit number");
+		lwasm_register_error(as, l, E_BITNUMBER_INVALID);
 		v2 = 0;
 	}
 	l -> pb = (l -> lint << 6) | (v1 << 3) | v2;
@@ -137,7 +137,7 @@
 		v2 = v1 - ((l -> dpval) << 8);
 		if (v2 > 0xFF || v2 < 0)
 		{
-			lwasm_register_error(as, l, "Byte overflow");
+			lwasm_register_error(as, l, E_BYTE_OVERFLOW);
 			return;
 		}
 	}
--- a/lwasm/insn_gen.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/insn_gen.c	Mon Jun 22 18:49:38 2015 -0600
@@ -43,7 +43,7 @@
 
 	if (!**p)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 
@@ -93,7 +93,7 @@
 	s = lwasm_parse_expr(as, p);
 	if (!s)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -276,7 +276,7 @@
 			if (l -> lint == 1)
 			{
 				if (i < -128 || i > 127)
-					lwasm_register_error(as, l, "Byte overflow");
+					lwasm_register_error(as, l, E_BYTE_OVERFLOW);
 			}
 			lwasm_emitexpr(l, e, l -> lint);
 		}
@@ -294,7 +294,7 @@
 {
 	if (**p == '#')
 	{
-		lwasm_register_error(as, l, "Immediate mode not allowed");
+		lwasm_register_error(as, l, E_IMMEDIATE_INVALID);
 		return;
 	}
 	
@@ -328,7 +328,7 @@
 		as -> exprwidth = 16;
 		if (!e)
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			return;
 		}
 		l -> len = OPLEN(instab[l -> insn].ops[3]) + 1;
@@ -377,7 +377,7 @@
 			i = lw_expr_intval(e);
 			if (i < -128 || i > 255)
 			{
-				lwasm_register_error(as, l, "Byte overflow");
+				lwasm_register_error(as, l, E_BYTE_OVERFLOW);
 			}
 		}
 
@@ -399,7 +399,7 @@
 		e = lwasm_parse_expr(as, p);
 		if (!e)
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			return;
 		}
 		l -> len = OPLEN(instab[l -> insn].ops[3]) + 2;
@@ -460,7 +460,7 @@
 		e = lwasm_parse_expr(as, p);
 		if (!e)
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			return;
 		}
 		l -> len = OPLEN(instab[l -> insn].ops[3]) + 4;
@@ -524,7 +524,7 @@
 		as -> exprwidth = 16;
 		if (!e)
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			return;
 		}
 		l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
@@ -532,7 +532,7 @@
 	}
 	else
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 	}
 }
 
@@ -548,7 +548,7 @@
 		i = lw_expr_intval(e);
 		if (i < -128 || i > 255)
 		{
-			lwasm_register_error(as, l, "Byte overflow");
+			lwasm_register_error(as, l, E_BYTE_OVERFLOW);
 		}
 	}
 	lwasm_emitexpr(l, e, 1);
--- a/lwasm/insn_indexed.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/insn_indexed.c	Mon Jun 22 18:49:38 2015 -0600
@@ -169,7 +169,7 @@
 		e = lwasm_parse_expr(as, p);
 		if (!e || **p != ']')
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			return;
 		}
 		lwasm_save_expr(l, 0, e);
@@ -199,7 +199,7 @@
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	lwasm_save_expr(l, 0, e);
@@ -207,7 +207,7 @@
 	// now look for a comma; if not present, explode
 	if (*(*p)++ != ',')
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -215,7 +215,7 @@
 	rn = lwasm_lookupreg3(reglist, p);
 	if (rn < 0)
 	{
-		lwasm_register_error(as, l, "Bad register");
+		lwasm_register_error(as, l, E_REGISTER_BAD);
 		return;
 	}
 	
@@ -223,7 +223,7 @@
 	{
 		if (**p != ']')
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			return;
 		}
 		else
@@ -250,7 +250,7 @@
 	{
 		if (l -> lint == 1)
 		{
-			lwasm_register_error(as, l, "n,W cannot be 8 bit");
+			lwasm_register_error(as, l, E_NW_8);
 			return;
 		}
 
@@ -588,7 +588,7 @@
 		i = lw_expr_intval(e);
 		if (i < -128 || i > 127)
 		{
-			lwasm_register_error(as, l, "Byte overflow");
+			lwasm_register_error(as, l, E_BYTE_OVERFLOW);
 		}
 	}
 	
--- a/lwasm/insn_logicmem.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/insn_logicmem.c	Mon Jun 22 18:49:38 2015 -0600
@@ -45,14 +45,14 @@
 	s = lwasm_parse_expr(as, p);
 	if (!s)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
 	lwasm_save_expr(l, 100, s);
 	if (**p != ',' && **p != ';')
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -78,7 +78,7 @@
 	e = lwasm_fetch_expr(l, 100);
 	if (!lw_expr_istype(e, lw_expr_type_int))
 	{
-		lwasm_register_error(as, l, "Immediate byte must be fully resolved");
+		lwasm_register_error(as, l, E_IMMEDIATE_UNRESOLVED);
 		return;
 	}
 	
@@ -86,7 +86,7 @@
 /*	if (v < -128 || v > 255)
 	{
 		fprintf(stderr, "BYTE: %d\n", v);
-		lwasm_register_error(as, l, "Byte overflow");
+		lwasm_register_error(as, l, E_BYTE_OVERFLOW);
 		return;
 	}
 */	
--- a/lwasm/insn_rel.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/insn_rel.c	Mon Jun 22 18:49:38 2015 -0600
@@ -80,7 +80,7 @@
 
 	if (!t)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 
@@ -222,14 +222,14 @@
 	{
 		if (!lw_expr_istype(e, lw_expr_type_int))
 		{
-			lwasm_register_error(as, l, "Illegal non-constant expression");
+			lwasm_register_error(as, l, E_EXPRESSION_NOT_CONST);
 			return;
 		}
 	
 		offs = lw_expr_intval(e);
 		if (l -> lint == 8 && (offs < -128 || offs > 127))
 		{
-			lwasm_register_error(as, l, "Byte overflow");
+			lwasm_register_error(as, l, E_BYTE_OVERFLOW);
 			return;
 		}
 	
--- a/lwasm/insn_rlist.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/insn_rlist.c	Mon Jun 22 18:49:38 2015 -0600
@@ -38,12 +38,12 @@
 		rn = lwasm_lookupreg2(regs, p);
 		if (rn < 0)
 		{
-			lwasm_register_error(as, l, "Bad register '%s'", *p);
+			lwasm_register_error2(as, l, E_REGISTER_BAD, "'%s'", *p);
 			return;
 		}
 		if (**p && **p != ',' && !isspace(**p))
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 		}
 		if (**p == ',')
 			(*p)++;
@@ -56,7 +56,7 @@
 		rb |= rn;
 	}
 	if (rb == 0)
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 	l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
 	l -> pb = rb;
 }
--- a/lwasm/insn_rtor.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/insn_rtor.c	Mon Jun 22 18:49:38 2015 -0600
@@ -37,7 +37,7 @@
 	r0 = lwasm_lookupreg2(!CURPRAGMA(l, PRAGMA_6809) ? regs : regs9, p);
 	if (r0 < 0 || *(*p)++ != ',')
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		r0 = r1 = 0;
 	}
 	else
@@ -45,7 +45,7 @@
 		r1 = lwasm_lookupreg2(!CURPRAGMA(l, PRAGMA_6809) ? regs : regs9, p);
 		if (r1 < 0)
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			r0 = r1 = 0;
 		}
 	}
--- a/lwasm/insn_tfm.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/insn_tfm.c	Mon Jun 22 18:49:38 2015 -0600
@@ -34,7 +34,7 @@
 	c = strchr(reglist, toupper(*(*p)++));
 	if (!c)
 	{
-		lwasm_register_error(as, l, "Unknown operation");
+		lwasm_register_error(as, l, E_UNKNOWN_OPERATION);
 		return;
 	}
 	r0 = c - reglist;
@@ -50,13 +50,13 @@
 	}
 	if (*(*p)++ != ',')
 	{
-		lwasm_register_error(as, l, "Unknown operation");
+		lwasm_register_error(as, l, E_UNKNOWN_OPERATION);
 		return;
 	}
 	c = strchr(reglist, toupper(*(*p)++));
 	if (!c)
 	{
-		lwasm_register_error(as, l, "Unknown operation");
+		lwasm_register_error(as, l, E_UNKNOWN_OPERATION);
 		return;
 	}
 	r1 = c - reglist;
@@ -74,7 +74,7 @@
 	
 	if (**p && !isspace(**p))
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 			
@@ -102,7 +102,7 @@
 		break;
 
 	default:
-		lwasm_register_error(as, l, "Unknown operation");
+		lwasm_register_error(as, l, E_UNKNOWN_OPERATION);
 		return;
 	}
 	l -> pb = (r0 << 4) | r1;
@@ -127,7 +127,7 @@
 	r0 = lwasm_lookupreg2(regs, p);
 	if (r0 < 0 || *(*p)++ != ',')
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		r0 = r1 = 0;
 	}
 	else
@@ -135,7 +135,7 @@
 		r1 = lwasm_lookupreg2(regs, p);
 		if (r1 < 0)
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			r0 = r1 = 0;
 		}
 	}
--- a/lwasm/lwasm.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/lwasm.c	Mon Jun 22 18:49:38 2015 -0600
@@ -33,8 +33,6 @@
 #include "lwasm.h"
 #include "instab.h"
 
-void lwasm_register_error(asmstate_t *as, line_t *l, const char *msg, ...);
-
 int lwasm_expr_exportable(asmstate_t *as, lw_expr_t expr)
 {
 	return 0;
@@ -48,7 +46,7 @@
 void lwasm_dividezero(void *priv)
 {
 	asmstate_t *as = (asmstate_t *)priv;
-	lwasm_register_error(as, as -> cl, "Division by zero");
+	lwasm_register_error(as, as -> cl, E_DIV0);
 }
 
 lw_expr_t lwasm_evaluate_var(char *var, void *priv)
@@ -100,7 +98,7 @@
 nomatch:
 	if (as -> badsymerr)
 	{
-		lwasm_register_error(as, as -> cl, "Undefined symbol %s", var);
+		lwasm_register_error2(as, as -> cl, E_SYMBOL_UNDEFINED, "%s", var);
 	}
 	return NULL;
 }
@@ -206,93 +204,120 @@
 	return NULL;
 }
 
-void lwasm_register_error_real(asmstate_t *as, line_t *l, char *iptr, const char *msg, va_list args)
+const char* lwasm_lookup_error(lwasm_errorcode_t error_code)
+{
+	switch (error_code)
+	{
+		case E_6309_INVALID:			return "Illegal use of 6309 instruction in 6809 mode";
+		case E_6809_INVALID:			return "Illegal use of 6809 instruction in 6309 mode";
+		case E_ALIGNMENT_INVALID:		return "Invalid alignment";
+		case E_BITNUMBER_INVALID:		return "Invalid bit number";
+		case E_BITNUMBER_UNRESOLVED:	return "Bit number must be fully resolved";
+		case E_BYTE_OVERFLOW:			return "Byte overflow";
+		case E_CONDITION_P1:			return "Conditions must be constant on pass 1";
+		case E_DIRECTIVE_OS9_ONLY:		return "Directive only valid for OS9 target";
+		case E_DIV0:					return "Division by zero";
+		case E_EXEC_ADDRESS:			return "Exec address not constant!";
+		case E_EXPRESSION_BAD:			return "Bad expression";
+		case E_EXPRESSION_NOT_CONST:	return "Expression must be constant";
+		case E_EXPRESSION_NOT_RESOLVED: return "Expression not fully resolved";
+		case E_FILE_OPEN:				return "Cannot open file";
+		case E_FILENAME_MISSING:		return "Missing filename";
+		case E_FILL_INVALID:			return "Invalid fill length";
+		case E_IMMEDIATE_INVALID:		return "Immediate mode not allowed";
+		case E_IMMEDIATE_UNRESOLVED:	return "Immediate byte must be fully resolved";
+		case E_INSTRUCTION_FAILED:		return "Instruction failed to resolve.";
+		case E_INSTRUCTION_SECTION:		return "Instruction generating output outside of a section";
+		case E_LINE_ADDRESS:			return "Cannot resolve line address";
+		case E_LINED_ADDRESS:			return "Cannot resolve line data address";
+		case E_OBJTARGET_ONLY:			return "Only supported for object target";
+		case E_OPCODE_BAD:				return "Bad opcode";
+		case E_OPERAND_BAD:				return "Bad operand";
+		case E_PADDING_BAD:				return "Bad padding";
+		case E_PRAGMA_UNRECOGNIZED:		return "Unrecognized pragma string";
+		case E_REGISTER_BAD:			return "Bad register";
+		case E_SETDP_INVALID:			return "SETDP not permitted for object target";
+		case E_SETDP_NOT_CONST:			return "SETDP must be constant on pass 1";
+		case E_STRING_BAD:				return "Bad string condition";
+		case E_SYMBOL_BAD:				return "Bad symbol";
+		case E_SYMBOL_MISSING:			return "Missing symbol";
+		case E_SYMBOL_UNDEFINED_EXPORT: return "Undefined exported symbol";
+		case E_MACRO_DUPE:				return "Duplicate macro definition";
+		case E_MACRO_ENDM:				return "ENDM without MACRO";
+		case E_MACRO_NONAME:			return "Missing macro name";
+		case E_MACRO_RECURSE:			return "Attempt to define a macro inside a macro";
+		case E_MODULE_IN:				return "Already in a module!";
+		case E_MODULE_NOTIN:			return "Not in a module!";
+		case E_NEGATIVE_BLOCKSIZE:		return "Negative block sizes make no sense!";
+		case E_NEGATIVE_RESERVATION:	return "Negative reservation sizes make no sense!";
+		case E_NW_8:					return "n,W cannot be 8 bit";
+		case E_SECTION_END:				return "ENDSECTION without SECTION";
+		case E_SECTION_EXTDEP:			return "EXTDEP must be within a section";
+		case E_SECTION_FLAG:			return "Unrecognized section flag";
+		case E_SECTION_NAME:			return "Need section name";
+		case E_SECTION_TARGET:			return "Cannot use sections unless using the object target";
+		case E_STRUCT_DUPE:				return "Duplicate structure definition";
+		case E_STRUCT_NONAME:			return "Cannot declare a structure without a symbol name.";
+		case E_STRUCT_NOSYMBOL:			return "Structure definition with no effect - no symbol";
+		case E_STRUCT_RECURSE:			return "Attempt to define a structure inside a structure";
+		case E_SYMBOL_DUPE:				return "Multiply defined symbol";
+		case E_UNKNOWN_OPERATION:		return "Unknown operation";
+
+		case W_ENDSTRUCT_WITHOUT:		return "ENDSTRUCT without STRUCT";
+		case W_DUPLICATE_SECTION:		return "Section flags can only be specified the first time; ignoring duplicate definition";
+		case W_NOT_SUPPORTED:			return "Not supported";
+
+		default:						return "Error";
+	}
+}
+
+void lwasm_register_error_real(asmstate_t *as, line_t *l, lwasm_errorcode_t err, const char *msg)
 {
 	lwasm_error_t *e;
-	char errbuff[1024];
 
 	if (!l)
 		return;
 
 	e = lw_alloc(sizeof(lwasm_error_t));
-	
-	e -> next = l -> err;
-	l -> err = e;
-	e -> charpos = -1;
-	
-	if (iptr)
-		e -> charpos = iptr - l -> ltext + 1;
-	
-	as -> errorcount++;
-	
-	(void)vsnprintf(errbuff, 1024, msg, args);
-	e -> mess = lw_strdup(errbuff);
-}
 
-void lwasm_register_error(asmstate_t *as, line_t *l, const char *msg, ...)
-{
-	va_list args;
-	
-	va_start(args, msg);
-	
-	lwasm_register_error_real(as, l, NULL, msg, args);
+	if (err >= 1000)
+	{
+		e->next = l->warn;
+		l->warn = e;
+		as->warningcount++;
+	}
+	else
+	{
+		e->next = l->err;
+		l->err = e;
+		as->errorcount++;
+	}
 	
-	va_end(args);
-}
+	e -> charpos = -1;
 
-void lwasm_register_error_n(asmstate_t *as, line_t *l, char *iptr, const char *msg, ...)
-{
-	va_list args;
-	
-	va_start(args, msg);
-	
-	lwasm_register_error_real(as, l, iptr, msg, args);
-	
-	va_end(args);
+	e -> mess = lw_strdup(msg);
 }
 
-void lwasm_register_warning_real(asmstate_t *as, line_t *l, char *iptr, const char *msg, va_list args)
+void lwasm_register_error(asmstate_t *as, line_t *l, lwasm_errorcode_t err)
 {
-	lwasm_error_t *e;
-	char errbuff[1024];
-	
-	if (!l)
-		return;
-
-	e = lw_alloc(sizeof(lwasm_error_t));
-	
-	e -> next = l -> warn;
-	l -> warn = e;
-	
-	e -> charpos = -1;
-	if (iptr)
-		e -> charpos = iptr - l -> ltext + 1;
-	
-	as -> warningcount++;
-	
-	(void)vsnprintf(errbuff, 1024, msg, args);
-	e -> mess = lw_strdup(errbuff);
+	lwasm_register_error_real(as, l, err, lwasm_lookup_error(err));
 }
 
-void lwasm_register_warning(asmstate_t *as, line_t *l, const char *msg, ...)
+void lwasm_register_error2(asmstate_t *as, line_t *l, lwasm_errorcode_t err, const char* fmt, ...)
 {
+	char errbuff[1024];
+	char f[128];
+
+	sprintf(f, "%s %s", lwasm_lookup_error(err), fmt);
+
 	va_list args;
-	
-	va_start(args, msg);
-	
-	lwasm_register_warning_real(as, l, NULL, msg, args);
-	
-	va_end(args);
-}
+
+	va_start(args, fmt);
 
-void lwasm_register_warning_n(asmstate_t *as, line_t *l, char *iptr, const char *msg, ...)
-{
-	va_list args;
-	
-	va_start(args, msg);
-	
-	lwasm_register_warning_real(as, l, iptr, msg, args);
-	
+	(void) vsnprintf(errbuff, 1024, f, args);
+
+	lwasm_register_error_real(as, l, err, errbuff);
+
 	va_end(args);
 }
 
@@ -308,7 +333,7 @@
 {
 	if (cl -> as -> output_format == OUTPUT_OBJ && cl -> csect == NULL)
 	{
-		lwasm_register_error(cl -> as, cl, "Instruction generating output outside of a section");
+		lwasm_register_error(cl -> as, cl, E_INSTRUCTION_SECTION);
 		return;
 	}
 	if (cl -> outputl < 0)
@@ -817,7 +842,7 @@
 
 			if (l -> csect == NULL)
 			{
-				lwasm_register_error(l -> as, l, "Instruction generating output outside of a section");
+				lwasm_register_error(l -> as, l, E_INSTRUCTION_SECTION);
 				return -1;
 			}
 			
@@ -871,7 +896,7 @@
 				lwasm_emit(l, 0);
 			return 0;
 		}
-		lwasm_register_error(l -> as, l, "Expression not fully resolved");
+		lwasm_register_error(l->as, l, E_EXPRESSION_NOT_RESOLVED);
 		return -1;
 	}
 	
@@ -994,7 +1019,7 @@
 	
 	if (!e)
 	{
-		lwasm_register_error(as, as -> cl, "Bad expression");
+		lwasm_register_error(as, as -> cl, E_EXPRESSION_BAD);
 		return NULL;
 	}
 
@@ -1026,7 +1051,7 @@
 	if (!lw_expr_istype(e, lw_expr_type_int))
 	{
 		debug_message(as, 250, "Non-constant expression");
-		lwasm_register_error(as, as -> cl, "Conditions must be constant on pass 1");
+		lwasm_register_error(as, as -> cl, E_CONDITION_P1);
 		return NULL;
 	}
 	debug_message(as, 250, "Returning expression");
--- a/lwasm/lwasm.h	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/lwasm.h	Mon Jun 22 18:49:38 2015 -0600
@@ -125,9 +125,77 @@
 	sectiontab_t *next;
 };
 
+typedef enum 
+{
+	E_6309_INVALID,
+	E_6809_INVALID,
+	E_ALIGNMENT_INVALID,
+	E_BITNUMBER_UNRESOLVED,
+	E_BITNUMBER_INVALID,
+	E_BYTE_OVERFLOW,
+	E_CONDITION_P1,
+	E_DIRECTIVE_OS9_ONLY,
+	E_DIV0,
+	E_EXEC_ADDRESS,
+	E_FILL_INVALID,
+	E_IMMEDIATE_INVALID,
+	E_IMMEDIATE_UNRESOLVED,
+	E_EXPRESSION_BAD,
+	E_EXPRESSION_NOT_CONST,
+	E_EXPRESSION_NOT_RESOLVED,
+	E_FILE_OPEN,
+	E_FILENAME_MISSING,
+	E_INSTRUCTION_FAILED,
+	E_INSTRUCTION_SECTION,
+	E_LINE_ADDRESS,
+	E_LINED_ADDRESS,
+	E_MACRO_DUPE,
+	E_MACRO_ENDM,
+	E_MACRO_NONAME,
+	E_MACRO_RECURSE,
+	E_MODULE_IN,
+	E_MODULE_NOTIN,
+	E_NEGATIVE_BLOCKSIZE,
+	E_NEGATIVE_RESERVATION,
+	E_NW_8,
+	E_OPCODE_BAD,
+	E_OPERAND_BAD,
+	E_OBJTARGET_ONLY, 
+	E_PADDING_BAD,
+	E_PRAGMA_UNRECOGNIZED,
+	E_REGISTER_BAD,
+	E_SECTION_END,
+	E_SECTION_EXTDEP,
+	E_SECTION_FLAG,
+	E_SECTION_NAME,
+	E_SECTION_TARGET,
+	E_SETDP_INVALID,
+	E_SETDP_NOT_CONST,			
+	E_STRING_BAD,
+	E_STRUCT_DUPE,
+	E_STRUCT_NONAME,
+	E_STRUCT_NOSYMBOL,
+	E_STRUCT_RECURSE,
+	E_SYMBOL_BAD,
+	E_SYMBOL_DUPE,
+	E_SYMBOL_MISSING,
+	E_SYMBOL_UNDEFINED,
+	E_SYMBOL_UNDEFINED_EXPORT,
+	E_UNKNOWN_OPERATION,
+	E_USER_SPECIFIED,
+
+	/* warnings must be 1000 or greater */
+
+	W_DUPLICATE_SECTION		= 1000,
+	W_ENDSTRUCT_WITHOUT		= 1001,
+	W_NOT_SUPPORTED			= 1002,
+	W_USER_SPECIFIED		= 1003
+} lwasm_errorcode_t;
+
 typedef struct lwasm_error_s lwasm_error_t;
 struct lwasm_error_s
 {
+	lwasm_errorcode_t code;				// error code
 	char *mess;							// actual error message
 	int charpos;						// character position on line where parsing stopped
 	lwasm_error_t *next;				// ptr to next error
@@ -327,13 +395,10 @@
 
 #endif
 
-#ifndef ___lwasm_c_seen___
+void lwasm_register_error(asmstate_t *as, line_t *cl, lwasm_errorcode_t err);
+void lwasm_register_error2(asmstate_t *as, line_t *cl, lwasm_errorcode_t err, const char* fmt, ...);
 
-extern void lwasm_register_error(asmstate_t *as, line_t *cl, const char *msg, ...);
-extern void lwasm_register_warning(asmstate_t *as, line_t *cl, const char *msg, ...);
-
-extern void lwasm_register_error_n(asmstate_t *as, line_t *cl, char *iptr, const char *msg, ...);
-extern void lwasm_register_warning_n(asmstate_t *as, line_t *cl, char *iptr, const char *msg, ...);
+#ifndef ___lwasm_c_seen___
 
 extern int lwasm_next_context(asmstate_t *as);
 extern void lwasm_emit(line_t *cl, int byte);
--- a/lwasm/macro.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/macro.c	Mon Jun 22 18:49:38 2015 -0600
@@ -48,13 +48,13 @@
 	
 	if (as -> inmacro)
 	{
-		lwasm_register_error(as, l, "Attempt to define a macro inside a macro");
+		lwasm_register_error(as, l, E_MACRO_RECURSE);
 		return;
 	}
 	
 	if (!(l -> sym))
 	{
-		lwasm_register_error(as, l, "Missing macro name");
+		lwasm_register_error(as, l, E_MACRO_NONAME);
 		return;
 	}
 
@@ -65,7 +65,7 @@
 	}
 	if (m)
 	{
-		lwasm_register_error(as, l, "Duplicate macro definition");
+		lwasm_register_error(as, l, E_MACRO_DUPE);
 		return;
 	}
 	
@@ -102,7 +102,7 @@
 	
 	if (!as -> inmacro)
 	{
-		lwasm_register_error(as, l, "ENDM without MACRO");
+		lwasm_register_error(as, l, E_MACRO_ENDM);
 		return;
 	}
 	
--- a/lwasm/os9.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/os9.c	Mon Jun 22 18:49:38 2015 -0600
@@ -38,7 +38,7 @@
 	
 	if (as -> output_format != OUTPUT_OS9 && as -> output_format != OUTPUT_OBJ)
 	{
-		lwasm_register_error(as, l, "os9 directive only valid for OS9 target");
+		lwasm_register_error2(as, l, E_DIRECTIVE_OS9_ONLY, "%s", "os9");
 		return;
 	}
 	
@@ -46,7 +46,7 @@
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	lwasm_save_expr(l, 0, e);
@@ -70,14 +70,14 @@
 	
 	if (as -> output_format != OUTPUT_OS9)
 	{
-		lwasm_register_error(as, l,  "mod directive only valid for OS9 target");
+		lwasm_register_error2(as, l, E_DIRECTIVE_OS9_ONLY, "%s", "mod");
 		skip_operand(p);
 		return;
 	}
 	
 	if (as -> inmod)
 	{
-		lwasm_register_error(as, l,  "Already in a module!");
+		lwasm_register_error(as, l, E_MODULE_IN);
 		skip_operand(p);
 		return;
 	}
@@ -88,7 +88,7 @@
 		e = lwasm_parse_expr(as, p);
 		if (!e)
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			return;
 		}
 
@@ -96,7 +96,7 @@
 
 		if (**p != ',')
 		{
-			lwasm_register_error(as, l, "Bad operand");
+			lwasm_register_error(as, l, E_OPERAND_BAD);
 			return;
 		}
 		(*p)++;
@@ -105,7 +105,7 @@
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	lwasm_save_expr(l, 5, e);
@@ -173,13 +173,13 @@
 	skip_operand(p);
 	if (as -> output_format != OUTPUT_OS9)
 	{
-		lwasm_register_error(as, l, "emod directive only valid for OS9 target");
+		lwasm_register_error2(as, l, E_DIRECTIVE_OS9_ONLY, "%s", "emod");
 		return;
 	}
 	
 	if (!(as -> inmod))
 	{
-		lwasm_register_error(as, l, "not in a module!");
+		lwasm_register_error(as, l, E_MODULE_NOTIN);
 		return;
 	}
 	
--- a/lwasm/pass1.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/pass1.c	Mon Jun 22 18:49:38 2015 -0600
@@ -322,7 +322,7 @@
 						if (expand_struct(as, cl, &p1, sym) != 0)
 						{
 							// structure expansion failed
-							lwasm_register_error(as, cl, "Bad opcode");
+							lwasm_register_error(as, cl, E_OPCODE_BAD);
 						}
 					}
 				}
@@ -334,9 +334,9 @@
 				if (instab[opnum].parse)
 				{
 					if (CURPRAGMA(cl, PRAGMA_6809) && (instab[opnum].flags & lwasm_insn_is6309))
-						lwasm_register_error(as, cl, "Illegal use of 6309 instruction in 6809 mode (%s)", sym);
+						lwasm_register_error2(as, cl, E_6309_INVALID, "(%s)", sym);
 					if (!CURPRAGMA(cl, PRAGMA_6809) && (instab[opnum].flags & lwasm_insn_is6809))
-						lwasm_register_error(as, cl, "Illegal use of 6809 instruction in 6309 mode (%s)", sym);
+						lwasm_register_error2(as, cl, E_6809_INVALID, "(%s)", sym);
 
 					if (as -> instruct == 0 || instab[opnum].flags & lwasm_insn_struct)
 					{
@@ -360,7 +360,7 @@
 						if (*p1 && !isspace(*p1) && !(cl -> err))
 						{
 							// flag bad operand error
-							lwasm_register_error(as, cl, "Bad operand (%s)", p1);
+							lwasm_register_error2(as, cl, E_OPERAND_BAD, "(%s)", p1);
 						}
 						
 						/* do a reduction on the line expressions to avoid carrying excessive expression baggage if not needed */
@@ -368,7 +368,7 @@
 					}
 					else if (as -> instruct == 1)
 					{
-						lwasm_register_error(as, cl, "Bad operand (%s)", p1);
+						lwasm_register_error2(as, cl, E_OPERAND_BAD, "(%s)", p1);
 					}
 				}
 			}
@@ -387,7 +387,7 @@
 					if (!register_symbol(as, cl, cl -> sym, cl -> daddr, symbol_flag_none))
 					{
 						// symbol error
-						// lwasm_register_error(as, cl, "Bad symbol '%s'", cl -> sym);
+						// lwasm_register_error2(as, cl, E_SYMBOL_BAD, "(%s)", cl -> sym);
 					}
 				}
 				else
@@ -395,7 +395,7 @@
 					if (!register_symbol(as, cl, cl -> sym, cl -> addr, symbol_flag_none))
 					{
 						// symbol error
-						// lwasm_register_error(as, cl, "Bad symbol '%s'", cl -> sym);
+						// lwasm_register_error2(as, cl, E_SYMBOL_BAD, "(%s)", cl -> sym);
 					}
 				}
 			}
--- a/lwasm/pass2.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/pass2.c	Mon Jun 22 18:49:38 2015 -0600
@@ -67,7 +67,7 @@
 				else
 				{
 					// undefined export - register error
-					lwasm_register_error(as, ex -> line, "Undefined exported symbol");
+					lwasm_register_error(as, ex->line, E_SYMBOL_UNDEFINED_EXPORT);
 				}
 			}
 			ex -> se = s;
--- a/lwasm/pass4.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/pass4.c	Mon Jun 22 18:49:38 2015 -0600
@@ -85,7 +85,7 @@
 			debug_message(as, 200, "Try resolve = %d/%d", sl -> len, sl -> dlen);
 			if (force && sl -> len == -1 && sl -> dlen == -1)
 			{
-				lwasm_register_error(as, sl, "Instruction failed to resolve.");
+				lwasm_register_error(as, sl, E_INSTRUCTION_FAILED);
 				return;
 			}
 		}
--- a/lwasm/pass5.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/pass5.c	Mon Jun 22 18:49:38 2015 -0600
@@ -121,11 +121,11 @@
 		{
 			if (!exprok(as, cl -> addr))
 			{
-				lwasm_register_error(as, cl, "Cannot resolve line address");
+				lwasm_register_error(as, cl, E_LINE_ADDRESS);
 			}
 			if (!exprok(as, cl -> daddr))
 			{
-				lwasm_register_error(as, cl, "Cannot resolve line data address");
+				lwasm_register_error(as, cl, E_LINED_ADDRESS);
 			}
 		}
 	}
--- a/lwasm/pass6.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/pass6.c	Mon Jun 22 18:49:38 2015 -0600
@@ -83,7 +83,7 @@
 			lwasm_reduce_expr(as, le -> expr);
 			if (!exprok(as, le -> expr))
 			{
-				lwasm_register_error(as, cl, "Invalid expression: %s", lw_expr_print(le -> expr));
+				lwasm_register_error2(as, cl, E_EXPRESSION_BAD, "%s", lw_expr_print(le -> expr));
 			}
 		}
 	}
--- a/lwasm/pragma.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/pragma.c	Mon Jun 22 18:49:38 2015 -0600
@@ -117,7 +117,7 @@
 
 	if (parse_pragma_string(as, ps, 0) == 0)
 	{
-		lwasm_register_error(as, l, "Unrecognized pragma string");
+		lwasm_register_error(as, l, E_PRAGMA_UNRECOGNIZED);
 	}
 	if (as -> pragmas & PRAGMA_NOLIST)
 		l -> pragmas |= PRAGMA_NOLIST;
--- a/lwasm/pseudo.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/pseudo.c	Mon Jun 22 18:49:38 2015 -0600
@@ -114,7 +114,7 @@
 	}
 	if (!addr)
 	{
-		lwasm_register_error(as, l, "Bad expression");
+		lwasm_register_error(as, as->cl, E_EXPRESSION_BAD);
 		addr = lw_expr_build(lw_expr_type_int, 0);
 	}
 	lwasm_save_expr(l, 0, addr);
@@ -129,7 +129,7 @@
 	if (addr)
 	{
 		if (!lw_expr_istype(addr, lw_expr_type_int))
-			lwasm_register_error(as, l, "Exec address not constant!");
+			lwasm_register_error(as, l, E_EXEC_ADDRESS);
 		else
 			as -> execaddr = lw_expr_intval(addr);
 	}
@@ -146,7 +146,7 @@
 		e = lwasm_parse_expr(as, p);
 		if (!e)
 		{
-			lwasm_register_error(as, l, "Bad expression (#%d)", i);
+			lwasm_register_error2(as, l, E_EXPRESSION_BAD, "(#%d)", i);
 			break;
 		}
 		lwasm_save_expr(l, i++, e);
@@ -181,7 +181,7 @@
 		e = lwasm_parse_expr(as, p);
 		if (!e)
 		{
-			lwasm_register_error(as, l, "Bad expression (#%d)", i);
+			lwasm_register_error2(as, l, E_EXPRESSION_BAD, "(#%d)", i);
 			break;
 		}
 		lwasm_save_expr(l, i++, e);
@@ -216,7 +216,7 @@
 		e = lwasm_parse_expr(as, p);
 		if (!e)
 		{
-			lwasm_register_error(as, l, "Bad expression (#%d)", i);
+			lwasm_register_error2(as, l, E_EXPRESSION_BAD, "(#%d)", i);
 			break;
 		}
 		lwasm_save_expr(l, i++, e);
@@ -259,7 +259,7 @@
 		e = lwasm_parse_expr(as, p);
 		if (!e)
 		{
-			lwasm_register_error(as, l, "Bad expression (#%d)", i);
+			lwasm_register_error2(as, l, E_EXPRESSION_BAD, "(#%d)", i);
 			break;
 		}
 		lwasm_save_expr(l, i++, e);
@@ -422,7 +422,7 @@
 	
 	if (!**p)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -434,7 +434,7 @@
 	
 	if (**p != delim)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	(*p)++;	
@@ -456,7 +456,7 @@
 	
 	if (!**p)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -467,7 +467,7 @@
 	
 	if (**p != delim)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	(*p)++;
@@ -490,7 +490,7 @@
 	
 	if (!**p)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -501,7 +501,7 @@
 
 	if (**p != delim)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	(*p)++;
@@ -524,7 +524,7 @@
 	expr = lwasm_parse_expr(as, p);
 	if (!expr)
 	{
-		lwasm_register_error(as, l, "Bad expression");
+		lwasm_register_error(as, l, E_EXPRESSION_BAD);
 	}
 
 	l -> lint = 0;
@@ -533,7 +533,7 @@
 		lwasm_reduce_expr(as, expr);
 		if (!lw_expr_istype(expr, lw_expr_type_int))
 		{
-			lwasm_register_error(as, l, "Expression must be constant at parse time");
+			lwasm_register_error(as, l, E_EXPRESSION_NOT_CONST);
 		}
 		else
 		{
@@ -580,7 +580,7 @@
 	{
 		if (lw_expr_intval(expr) < 0)
 		{
-			lwasm_register_error(as, l, "Negative reservation sizes make no sense! (%d)", lw_expr_intval(expr));
+			lwasm_register_error2(as, l, E_NEGATIVE_RESERVATION, "(%d)", lw_expr_intval(expr));
 			l -> len = 0;
 			l -> dlen = 0;
 			return;
@@ -598,7 +598,7 @@
 		return;
 
 	if (l -> len < 0 || l -> dlen < 0)
-		lwasm_register_error(as, l, "Expression not constant: %d %d", l -> len, l -> dlen);
+		lwasm_register_error2(as, l, E_EXPRESSION_NOT_CONST, "%d %d", l -> len, l -> dlen);
 }
 
 PARSEFUNC(pseudo_parse_rmd)
@@ -609,7 +609,7 @@
 	expr = lwasm_parse_expr(as, p);
 	if (!expr)
 	{
-		lwasm_register_error(as, l, "Bad expression");
+		lwasm_register_error(as, l, E_EXPRESSION_BAD);
 	}
 	
 	if (as -> instruct)
@@ -617,7 +617,7 @@
 		lwasm_reduce_expr(as, expr);
 		if (!lw_expr_istype(expr, lw_expr_type_int))
 		{
-			lwasm_register_error(as, l, "Expression must be constant at parse time");
+			lwasm_register_error(as, l, E_EXPRESSION_NOT_CONST);
 		}
 		else
 		{
@@ -664,7 +664,7 @@
 	{
 		if (lw_expr_intval(expr) < 0)
 		{
-			lwasm_register_error(as, l, "Negative reservation sizes make no sense! (%d)", lw_expr_intval(expr));
+			lwasm_register_error2(as, l, E_NEGATIVE_RESERVATION, "(%d)", lw_expr_intval(expr));
 			l -> len = 0;
 			l -> dlen = 0;
 			return;
@@ -682,7 +682,7 @@
 		return;
 
 	if (l -> len < 0 || l -> dlen < 0)
-		lwasm_register_error(as, l, "Expression not constant");
+		lwasm_register_error(as, l, E_EXPRESSION_NOT_CONST);
 }
 
 
@@ -694,14 +694,14 @@
 	expr = lwasm_parse_expr(as, p);
 	if (!expr)
 	{
-		lwasm_register_error(as, l, "Bad expression");
+		lwasm_register_error(as, l, E_EXPRESSION_BAD);
 	}
 	if (as -> instruct)
 	{
 		lwasm_reduce_expr(as, expr);
 		if (!lw_expr_istype(expr, lw_expr_type_int))
 		{
-			lwasm_register_error(as, l, "Expression must be constant at parse time");
+			lwasm_register_error(as, l, E_EXPRESSION_NOT_CONST);
 		}
 		else
 		{
@@ -748,7 +748,7 @@
 	{
 		if (lw_expr_intval(expr) < 0)
 		{
-			lwasm_register_error(as, l, "Negative reservation sizes make no sense! (%d)", lw_expr_intval(expr));
+			lwasm_register_error2(as, l, E_NEGATIVE_RESERVATION, "(%d)", lw_expr_intval(expr));
 			l -> len = 0;
 			l -> dlen = 0;
 			return;
@@ -766,7 +766,7 @@
 		return;
 
 	if (l -> len < 0 || l -> dlen < 0)
-		lwasm_register_error(as, l, "Expression not constant");
+		lwasm_register_error(as, l, E_EXPRESSION_NOT_CONST);
 }
 
 
@@ -777,7 +777,7 @@
 	expr = lwasm_parse_expr(as, p);
 	if (!expr)
 	{
-		lwasm_register_error(as, l, "Bad expression");
+		lwasm_register_error(as, l, E_EXPRESSION_BAD);
 	}
 	
 	lwasm_save_expr(l, 0, expr);
@@ -796,7 +796,7 @@
 	{
 		if (lw_expr_intval(expr) < 0)
 		{
-			lwasm_register_error(as, l, "Negative block sizes make no sense! (%d)", lw_expr_intval(expr));
+			lwasm_register_error2(as, l, E_NEGATIVE_BLOCKSIZE, "(%d)", lw_expr_intval(expr));
 			l -> len = 0;
 			return;
 		}
@@ -810,7 +810,7 @@
 
 	if (l -> len < 0)
 	{
-		lwasm_register_error(as, l, "Expression not constant");
+		lwasm_register_error(as, l, E_EXPRESSION_NOT_CONST);
 		return;
 	}
 
@@ -826,7 +826,7 @@
 	expr = lwasm_parse_expr(as, p);
 	if (!expr)
 	{
-		lwasm_register_error(as, l, "Bad expression");
+		lwasm_register_error(as, l, E_EXPRESSION_BAD);
 	}
 	
 	lwasm_save_expr(l, 0, expr);
@@ -845,7 +845,7 @@
 	{
 		if (lw_expr_intval(expr) < 0)
 		{
-			lwasm_register_error(as, l, "Negative block sizes make no sense! (%d)", lw_expr_intval(expr));
+			lwasm_register_error2(as, l, E_NEGATIVE_BLOCKSIZE, "(%d)", lw_expr_intval(expr));
 			l -> len = 0;
 			return;
 		}
@@ -859,7 +859,7 @@
 
 	if (l -> len < 0)
 	{
-		lwasm_register_error(as, l, "Expression not constant");
+		lwasm_register_error(as, l, E_EXPRESSION_NOT_CONST);
 		return;
 	}
 
@@ -874,7 +874,7 @@
 	expr = lwasm_parse_expr(as, p);
 	if (!expr)
 	{
-		lwasm_register_error(as, l, "Bad expression");
+		lwasm_register_error(as, l, E_EXPRESSION_BAD);
 	}
 	
 	lwasm_save_expr(l, 0, expr);
@@ -893,7 +893,7 @@
 	{
 		if (lw_expr_intval(expr) < 0)
 		{
-			lwasm_register_error(as, l, "Negative block sizes make no sense! (%d)", lw_expr_intval(expr));
+			lwasm_register_error2(as, l, E_NEGATIVE_BLOCKSIZE, "(%d)", lw_expr_intval(expr));
 			l -> len = 0;
 			return;
 		}
@@ -907,7 +907,7 @@
 
 	if (l -> len < 0)
 	{
-		lwasm_register_error(as, l, "Expression not constant");
+		lwasm_register_error(as, l, E_EXPRESSION_NOT_CONST);
 		return;
 	}
 
@@ -924,7 +924,7 @@
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -947,14 +947,14 @@
 	
 	if (!(l -> sym))
 	{
-		lwasm_register_error(as, l, "Missing symbol");
+		lwasm_register_error(as, l, E_SYMBOL_MISSING);
 		return;
 	}
 	
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -972,14 +972,14 @@
 	
 	if (!(l -> sym))
 	{
-		lwasm_register_error(as, l, "Missing symbol");
+		lwasm_register_error(as, l, E_SYMBOL_MISSING);
 		return;
 	}
 	
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -997,14 +997,14 @@
 	
 	if (as -> output_format == OUTPUT_OBJ)
 	{
-		lwasm_register_error(as, l, "SETDP not permitted for object target");
+		lwasm_register_error(as, l, E_SETDP_INVALID);
 		return;
 	}
 	
 	e = lwasm_parse_expr(as, p);
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -1012,7 +1012,7 @@
 	lwasm_reduce_expr(as, e);
 	if (!lw_expr_istype(e, lw_expr_type_int))
 	{
-		lwasm_register_error(as, l, "SETDP must be constant on pass 1");
+		lwasm_register_error(as, l, E_SETDP_NOT_CONST);
 		lw_expr_destroy(e);
 		return;
 	}
@@ -1034,8 +1034,7 @@
 		return;
 	}
 	
-	lwasm_register_warning(as, l, "IFP1 if is not supported; ignoring");
-	
+	lwasm_register_error2(as, l, W_NOT_SUPPORTED, "%s", "IFP1");
 }
 
 PARSEFUNC(pseudo_parse_ifp2)
@@ -1050,7 +1049,7 @@
 		return;
 	}
 	
-	lwasm_register_warning(as, l, "IFP2 if is not supported; ignoring");
+	lwasm_register_error2(as, l, W_NOT_SUPPORTED, "%s", "IFP2");
 }
 
 PARSEFUNC(pseudo_parse_ifeq)
@@ -1308,13 +1307,13 @@
 
 PARSEFUNC(pseudo_parse_error)
 {
-	lwasm_register_error(as, l, "User error: %s", *p);
+	lwasm_register_error2(as, l, E_USER_SPECIFIED, "%s", *p);
 	skip_operand(p);
 }
 
 PARSEFUNC(pseudo_parse_warning)
 {
-	lwasm_register_warning(as, l, "User warning: %s", *p);
+	lwasm_register_error2(as, l, W_USER_SPECIFIED, "%s", *p);
 	l -> len = 0;
 	skip_operand(p);
 }
@@ -1329,7 +1328,7 @@
 	
 	if (!**p)
 	{
-		lwasm_register_error(as, l, "Missing filename");
+		lwasm_register_error(as, l, E_FILENAME_MISSING);
 		return;
 	}
 	
@@ -1354,7 +1353,7 @@
 	fp = input_open_standalone(as, fn, &rfn);
 	if (!fp)
 	{
-		lwasm_register_error(as, l, "Cannot open file");
+		lwasm_register_error(as, l, E_FILE_OPEN);
 		lw_free(fn);
 		return;
 	}
@@ -1376,7 +1375,7 @@
 	fp = fopen(l -> lstr, "rb");
 	if (!fp)
 	{
-		lwasm_register_error(as, l, "Cannot open file (emit)!");
+		lwasm_register_error2(as, l, E_FILE_OPEN, "%s", "(emit)!");
 		return;
 	}
 	
@@ -1402,7 +1401,7 @@
 		
 	if (!**p)
 	{
-		lwasm_register_error(as, l, "Missing filename");
+		lwasm_register_error(as, l, E_FILENAME_MISSING);
 		return;
 	}
 	
@@ -1446,7 +1445,7 @@
 	lw_expr_t e;
 	if (!**p)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -1454,7 +1453,7 @@
 	
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -1471,7 +1470,7 @@
 	}
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad padding");
+		lwasm_register_error(as, l, E_PADDING_BAD);
 		return;
 	}
 	
@@ -1492,7 +1491,7 @@
 		align = lw_expr_intval(e);
 		if (align < 1)
 		{
-			lwasm_register_error(as, l, "Invalid alignment");
+			lwasm_register_error(as, l, E_ALIGNMENT_INVALID);
 			return;
 		}
 	}
@@ -1548,14 +1547,14 @@
 	lw_expr_t e, e1;
 	if (!**p)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
 	e1 = lwasm_parse_expr(as, p);
 	if (**p != ',')
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	(*p)++;
@@ -1563,7 +1562,7 @@
 	
 	if (!e)
 	{
-		lwasm_register_error(as, l, "Bad operand");
+		lwasm_register_error(as, l, E_OPERAND_BAD);
 		return;
 	}
 	
@@ -1572,7 +1571,7 @@
 
 	if (!e1)
 	{
-		lwasm_register_error(as, l, "Bad padding");
+		lwasm_register_error(as, l, E_PADDING_BAD);
 		return;
 	}
 }
@@ -1595,7 +1594,7 @@
 		if (align < 0)
 		{
 			lw_expr_destroy(te);
-			lwasm_register_error(as, l, "Invalid fill length");
+			lwasm_register_error(as, l, E_FILL_INVALID);
 			return;
 		}
 	}
@@ -2052,7 +2051,7 @@
 	tstr = strcond_parsearg(p);
 	if (!**p || isspace(**p))	
 	{
-		lwasm_register_error(as, l, "Bad string condition");
+		lwasm_register_error(as, l, E_STRING_BAD);
 		return;
 	}
 		
@@ -2064,7 +2063,7 @@
 	
 	if (strops[strop].str == NULL)
 	{
-		lwasm_register_error(as, l, "Bad string condition");
+		lwasm_register_error(as, l, E_STRING_BAD);
 	}
 
 	tv = (*(strops[strop].fn))(p);
--- a/lwasm/section.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/section.c	Mon Jun 22 18:49:38 2015 -0600
@@ -37,13 +37,13 @@
 
 	if (as -> output_format != OUTPUT_OBJ)
 	{
-		lwasm_register_error(as, l, "Cannot use sections unless using the object target");
+		lwasm_register_error(as, l, E_SECTION_TARGET);
 		return;
 	}
 	
 	if (!**p)
 	{
-		lwasm_register_error(as, l, "Need section name");
+		lwasm_register_error(as, l, E_SECTION_NAME);
 		return;
 	}
 
@@ -81,7 +81,7 @@
 	}
 	if (s && opts)
 	{
-		lwasm_register_warning(as, l, "Section flags can only be specified the first time; ignoring duplicate definition");
+		lwasm_register_error(as, l, W_DUPLICATE_SECTION);
 	}
 	if (!s)
 	{
@@ -125,7 +125,7 @@
 			}
 			else
 			{
-				lwasm_register_error(as, l, "Unrecognized section flag");
+				lwasm_register_error(as, l, E_SECTION_FLAG);
 				lw_free(sn);
 				lw_free(opts);
 				lw_free(s -> name);
@@ -158,7 +158,7 @@
 {
 	if (as -> output_format != OUTPUT_OBJ)
 	{
-		lwasm_register_error(as, l, "Cannot use sections unless using the object target");
+		lwasm_register_error(as, l, E_SECTION_TARGET);
 		return;
 	}
 
@@ -166,7 +166,7 @@
 
 	if (!(as -> csect))
 	{
-		lwasm_register_error(as, l, "ENDSECTION without SECTION");
+		lwasm_register_error(as, l, E_SECTION_END);
 		return;
 	}
 
@@ -192,7 +192,7 @@
 	
 	if (as -> output_format != OUTPUT_OBJ)
 	{
-		lwasm_register_error(as, l, "EXPORT only supported for object target");
+		lwasm_register_error2(as, l, E_OBJTARGET_ONLY, "(%s)", "EXPORT");
 		return;
 	}
 
@@ -223,7 +223,7 @@
 	}
 	if (!sym)
 	{
-		lwasm_register_error(as, l, "No symbol for EXPORT");
+		lwasm_register_error2(as, l, E_SYMBOL_MISSING, "for %s", "EXPORT");
 		return;
 	}
 	
@@ -254,7 +254,7 @@
 	
 	if (as -> output_format != OUTPUT_OBJ)
 	{
-		lwasm_register_error(as, l, "IMPORT only supported for object target");
+		lwasm_register_error2(as, l, E_OBJTARGET_ONLY, "(%s)", "IMPORT");
 		return;
 	}
 	
@@ -285,7 +285,7 @@
 	}
 	if (!sym)
 	{
-		lwasm_register_error(as, l, "No symbol for IMPORT");
+		lwasm_register_error2(as, l, E_SYMBOL_MISSING, "for %s", "IMPORT");
 		return;
 	}
 	
@@ -314,13 +314,13 @@
 	
 	if (as -> output_format != OUTPUT_OBJ)
 	{
-		lwasm_register_error(as, l, "EXTDEP only supported for object target");
+		lwasm_register_error2(as, l, E_OBJTARGET_ONLY, "(%s)", "EXTDEP");
 		return;
 	}
 	
 	if (!as -> csect)
 	{
-		lwasm_register_error(as, l, "EXTDEP must be within a section");
+		lwasm_register_error(as, l, E_SECTION_EXTDEP);
 		return;
 	}
 	
@@ -347,7 +347,7 @@
 	}
 	if (!sym)
 	{
-		lwasm_register_error(as, l, "No symbol for EXTDEP");
+		lwasm_register_error2(as, l, E_SYMBOL_MISSING, "for %s", "EXTDEP");
 		return;
 	}
 	
--- a/lwasm/struct.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/struct.c	Mon Jun 22 18:49:38 2015 -0600
@@ -34,13 +34,13 @@
 	
 	if (as -> instruct)
 	{
-		lwasm_register_error(as, l, "Attempt to define a structure inside a structure");
+		lwasm_register_error(as, l, E_STRUCT_RECURSE);
 		return;
 	}
 	
 	if (l -> sym == NULL)
 	{
-		lwasm_register_error(as, l, "Structure definition with no effect - no symbol");
+		lwasm_register_error(as, l, E_STRUCT_NOSYMBOL);
 		return;
 	}
 	
@@ -52,7 +52,7 @@
 	
 	if (s)
 	{
-		lwasm_register_error(as, l, "Duplicate structure definition");
+		lwasm_register_error(as, l, E_STRUCT_DUPE);
 		return;
 	}
 	
@@ -138,7 +138,7 @@
 		
 	if (as -> instruct == 0)
 	{
-		lwasm_register_warning(as, l, "endstruct without struct");
+		lwasm_register_error(as, l, W_ENDSTRUCT_WITHOUT);
 		skip_operand(p);
 		return;
 	}
@@ -206,7 +206,7 @@
 	
 	if (!(l -> sym))
 	{
-		lwasm_register_error(as, l, "Cannot declare a structure without a symbol name.");
+		lwasm_register_error(as, l, E_STRUCT_NONAME);
 		return -1;
 	}
 
--- a/lwasm/symbol.c	Mon Jun 22 18:38:30 2015 -0600
+++ b/lwasm/symbol.c	Mon Jun 22 18:49:38 2015 -0600
@@ -90,18 +90,18 @@
 	{
 		if (!sym || !*sym)
 		{
-			lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+			lwasm_register_error2(as, cl, E_SYMBOL_BAD, "(%s)", sym);
 			return NULL;
 		}
 		if (*(unsigned char *)sym < 0x80 && (!strchr(SSYMCHARS, *sym) && !strchr(sym + 1, '$') && !strchr(sym + 1, '@') && !strchr(sym + 1, '?')))
 		{
-			lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+			lwasm_register_error2(as, cl, E_SYMBOL_BAD, "(%s)", sym);
 			return NULL;
 		}
 
 		if ((*sym == '$' || *sym == '@') && (sym[1] >= '0' && sym[1] <= '9'))
 		{
-			lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+			lwasm_register_error2(as, cl, E_SYMBOL_BAD, "(%s)", sym);
 			return NULL;
 		}
 	}
@@ -116,7 +116,7 @@
 		// bad symbol
 		if (!(flags & symbol_flag_nocheck) && *(unsigned char *)cp < 0x80 && !strchr(SYMCHARS, *cp))
 		{
-			lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+			lwasm_register_error2(as, cl, E_SYMBOL_BAD, "(%s)", sym);
 			return NULL;
 		}
 	}
@@ -163,7 +163,7 @@
 	if (se && version == -1)
 	{
 		// multiply defined symbol
-		lwasm_register_error(as, cl, "Multiply defined symbol (%s)", sym);
+		lwasm_register_error2(as, cl, E_SYMBOL_DUPE, "(%s)", sym);
 		return NULL;
 	}