diff lwasm/lwasm.c @ 375:71f507f404f1

Add "testmode" pragma Add a pragma to allow testing more easily. Thanks to Erik G <erik@6809.org> for the patch.
author William Astle <lost@l-w.ca>
date Mon, 13 Jul 2015 20:35:16 -0600
parents 8e25147c2aa8
children 35d4213e6657
line wrap: on
line diff
--- a/lwasm/lwasm.c	Mon Jul 13 20:31:56 2015 -0600
+++ b/lwasm/lwasm.c	Mon Jul 13 20:35:16 2015 -0600
@@ -27,6 +27,7 @@
 #include <lw_expr.h>
 #include <lw_alloc.h>
 #include <lw_string.h>
+#include <lw_error.h>
 
 #include "lwasm.h"
 #include "instab.h"
@@ -269,16 +270,98 @@
 	}
 }
 
-void lwasm_register_error_real(asmstate_t *as, line_t *l, lwasm_errorcode_t err, const char *msg)
+/* keeping this as a separate error output for stability in unit test scripts */
+void lwasm_error_testmode(line_t *cl, const char* msg, int fatal)
+{
+	cl -> as -> testmode_errorcount++;
+	fprintf(stderr, "line %d: %s : %s\n", cl->lineno, msg, cl->ltext);
+	if (fatal == 1) lw_error("aborting\n");
+}
+
+/* parse unit test input data from comment field */
+void lwasm_parse_testmode_comment(line_t *l, lwasm_testflags_t *flags, lwasm_errorcode_t *err, int *len, char **buf)
+{
+	*flags = 0;
+
+	if (!l)
+		return;
+
+	char* s = strstr(l -> ltext, ";.");
+	if (s == NULL) return;
+
+	char* t = strstr(s, ":");
+	if (t == NULL)
+	{
+		/* parse: ;.8E0FCE (emitted code) */
+
+		if (buf == NULL) return;
+
+		int i;
+		*flags = TF_EMIT;
+
+		s = s + 2;	/* skip ;. prefix */
+		t = s;
+		while (*t > 32) t++;
+
+		if ((t - s) & 1)
+		{
+			lwasm_error_testmode(l, "bad test data (wrong length of hex chars)", 1);
+			return;
+		}
+
+		*len = (t - s) / 2;
+
+		t = lw_alloc(*len);
+		*buf = t;
+
+		for (i = 0; i < *len; i++)
+		{
+			int val;
+			sscanf(s, "%2x", &val);
+			*t++ = (char) val;
+			s += 2;
+		}
+	}
+	else
+	{
+		/* parse: ;.E:1000 or ;.E:7 (warnings or errors) */
+		*flags = TF_ERROR;
+
+		char ch = toupper(*(t - 1));
+		if (ch != 'E') lwasm_error_testmode(l, "bad test data (expected E: flag)", 1);
+		sscanf(t + 1, "%d", (int*) err);
+	}
+}
+
+void lwasm_register_error_real(asmstate_t *as, line_t *l, lwasm_errorcode_t error_code, const char *msg)
 {
 	lwasm_error_t *e;
 
 	if (!l)
 		return;
 
+	if (CURPRAGMA(l, PRAGMA_TESTMODE))
+	{
+		lwasm_testflags_t flags;
+		lwasm_errorcode_t testmode_error_code;
+		lwasm_parse_testmode_comment(l, &flags, &testmode_error_code, NULL, NULL);
+		if (flags == TF_ERROR)
+		{
+			l -> len = 0;	/* null out bogus line */
+			l -> insn = -1;
+			l -> err_testmode = error_code;
+			if (testmode_error_code == error_code) return;		/* expected error: ignore and keep assembling */
+
+			char buf[128];
+			sprintf(buf, "wrong error code (%d)", error_code);
+			lwasm_error_testmode(l, buf, 0);
+			return;
+		}
+	}
+
 	e = lw_alloc(sizeof(lwasm_error_t));
 
-	if (err >= 1000)
+	if (error_code >= 1000)
 	{
 		e->next = l->warn;
 		l->warn = e;
@@ -291,6 +374,7 @@
 		as->errorcount++;
 	}
 	
+	e -> code = error_code;
 	e -> charpos = -1;
 
 	e -> mess = lw_strdup(msg);
@@ -984,11 +1068,11 @@
 			continue;
 		for (e = cl -> err; e; e = e -> next)
 		{
-			fprintf(stderr, "ERROR: %s\n", e -> mess);
+			fprintf(stderr, "ERROR: %s (%d)\n", e -> mess, e -> code);
 		}
 		for (e = cl -> warn; e; e = e -> next)
 		{
-			fprintf(stderr, "WARNING: %s\n", e -> mess);
+			fprintf(stderr, "WARNING: %s (%d)\n", e -> mess, e -> code);
 		}
 		fprintf(stderr, "%s:%05d %s\n\n", cl -> linespec, cl -> lineno, cl -> ltext);
 	}