From 2520b79fdf6c344c358e21518b1a5fbcccb21095 Mon Sep 17 00:00:00 2001
From: Thomas Voss <mail@thomasvoss.com>
Date: Mon, 19 Feb 2024 22:43:36 +0100
Subject: Make error messages great again

---
 src/c8asm/assembler.c |   8 ++--
 src/c8asm/common.h    |   3 ++
 src/c8asm/lexer.c     |  27 ++++++-------
 src/c8asm/parser.c    | 107 +++++++++++++++++++++++---------------------------
 src/common/cerr.c     |   6 +--
 5 files changed, 70 insertions(+), 81 deletions(-)

(limited to 'src')

diff --git a/src/c8asm/assembler.c b/src/c8asm/assembler.c
index 8ccf9b0..ffa9025 100644
--- a/src/c8asm/assembler.c
+++ b/src/c8asm/assembler.c
@@ -54,16 +54,14 @@ getaddr(struct raw_addr a)
 	   labels that aren’t integer-literals by that. */
 	if (lbl = getlabel(a.sv))
 		return lbl->addr + 0x200;
-	die_at_pos_with_code(filename, filebuf, a.sv, a.sv.p - baseptr, E_LNEXISTS);
+	DIE_AT_POS_WITH_CODE(a.sv, a.sv.p, E_LNEXISTS);
 }
 
 void
 pushlabel(struct labels *dst, struct label lbl)
 {
-	if (getlabel(lbl.sv)) {
-		die_at_pos_with_code(filename, filebuf, lbl.sv, lbl.sv.p - baseptr,
-		                     E_LEXISTS);
-	}
+	if (getlabel(lbl.sv))
+		DIE_AT_POS_WITH_CODE(lbl.sv, lbl.sv.p, E_LEXISTS);
 	dapush(dst, lbl);
 }
 
diff --git a/src/c8asm/common.h b/src/c8asm/common.h
index 49af0f7..aa32b2b 100644
--- a/src/c8asm/common.h
+++ b/src/c8asm/common.h
@@ -3,6 +3,9 @@
 
 #include <rune.h>
 
+#define DIE_AT_POS_WITH_CODE(HL, P, ...) \
+	die_at_pos_with_code(filename, filebuf, (HL), (P)-baseptr, __VA_ARGS__);
+
 extern size_t filesize;
 extern const char *filename;
 extern const char8_t *baseptr;
diff --git a/src/c8asm/lexer.c b/src/c8asm/lexer.c
index 3d2a3bf..87835a9 100644
--- a/src/c8asm/lexer.c
+++ b/src/c8asm/lexer.c
@@ -10,9 +10,6 @@
 #define ISDIGIT(n)   ((n) >= '0' && (n) <= '9')
 #define U8MOV(sv, n) ((sv)->p += (n), (sv)->len -= (n))
 
-#define die_at_pos_with_code(HL, OFF, ...) \
-	die_at_pos_with_code(filename, filebuf, (HL), (OFF), __VA_ARGS__)
-
 #define E_BASE         "integer with invalid base specifier"
 #define E_EXTRA        "unknown extraneous character"
 #define E_IDENTCCHAR   "illegal character in identifier"
@@ -68,12 +65,12 @@ lexfile(void)
 	return toks;
 }
 
+#define DIE_AT_POS_WITH_CODE2(HL, ...) \
+	DIE_AT_POS_WITH_CODE((HL), sv->p - w, __VA_ARGS__)
+
 void
 lexline(struct tokens *toks, struct u8view *sv)
 {
-#define _die_at_pos_with_code(HL, ...) \
-	die_at_pos_with_code((HL), sv->p - baseptr - w, __VA_ARGS__)
-
 	struct token tok;
 
 	for (;;) {
@@ -117,7 +114,7 @@ lexline(struct tokens *toks, struct u8view *sv)
 					break;
 				default:
 					if (!ISDIGIT(ch))
-						_die_at_pos_with_code(tok.sv, E_BASE);
+						DIE_AT_POS_WITH_CODE2(tok.sv, E_BASE);
 				}
 			}
 
@@ -130,10 +127,10 @@ out:
 			if (ch == '.') {
 				tok.sv.len += w = u8next(&ch, &sv->p, &sv->len);
 				if (!w || rprop_is_pat_ws(ch))
-					_die_at_pos_with_code(tok.sv, E_IDENTLOST);
+					DIE_AT_POS_WITH_CODE2(tok.sv, E_IDENTLOST);
 				if (ch != '_' && !rprop_is_xids(ch)) {
 					U8MOV(&tok.sv, 1);
-					_die_at_pos_with_code(tok.sv, E_IDENTSCHAR);
+					DIE_AT_POS_WITH_CODE2(tok.sv, E_IDENTSCHAR);
 				}
 			}
 
@@ -147,7 +144,7 @@ out:
 						.p = sv->p - w,
 						.len = w,
 					};
-					_die_at_pos_with_code(hl, E_IDENTCCHAR);
+					DIE_AT_POS_WITH_CODE2(hl, E_IDENTCCHAR);
 				}
 
 				tok.sv.len += w;
@@ -159,7 +156,7 @@ out:
 				if (ch == '"')
 					goto found;
 			}
-			_die_at_pos_with_code(tok.sv, E_UNTERMINATED);
+			DIE_AT_POS_WITH_CODE2(tok.sv, E_UNTERMINATED);
 found:
 		} else if (ch == ':') {
 			tok.kind = T_COLON;
@@ -167,7 +164,7 @@ found:
 			goto end;
 		} else {
 			struct u8view hl = {.p = sv->p - w, .len = w};
-			_die_at_pos_with_code(hl, E_EXTRA);
+			DIE_AT_POS_WITH_CODE2(hl, E_EXTRA);
 		}
 
 		/* The colon is the only token that isn’t whitespace separated */
@@ -175,7 +172,7 @@ found:
 			w = u8next(&ch, &sv->p, &sv->len);
 			if (!w || !rprop_is_pat_ws(ch)) {
 				struct u8view hl = {.p = sv->p - w, .len = w};
-				_die_at_pos_with_code(hl, E_EXTRA);
+				DIE_AT_POS_WITH_CODE2(hl, E_EXTRA);
 			}
 		}
 
@@ -189,10 +186,10 @@ end:;
 		.sv.len = 0,
 	};
 	dapush(toks, tok);
-
-#undef _die_at_pos_with_code
 }
 
+#undef DIE_AT_POS_WITH_CODE2
+
 bool
 skipws(struct u8view *sv)
 {
diff --git a/src/c8asm/parser.c b/src/c8asm/parser.c
index 5a68fad..208511d 100644
--- a/src/c8asm/parser.c
+++ b/src/c8asm/parser.c
@@ -11,14 +11,11 @@
 #include "macros.h"
 #include "parser.h"
 
-#define E_BADLABEL  "identifier ‘%.*s’ cannot be used as a label"
-#define E_EARLY     "expected %s but input ended prematurely"
-#define E_EXPECTED2 "expected %s but got %s"
-#define E_EXPECTED  "expected %s but got %s ‘%.*s’"
-#define E_INSTR     "got unknown instruction ‘%.*s’"
-#define E_TOOLARGE  "expected %s but got out-of-range integer ‘%.*s’"
-
-#define die_with_off(P, ...) die_with_off(filename, (P)-baseptr, __VA_ARGS__)
+#define E_BADLABEL "identifier cannot be used as a label"
+#define E_EARLY    "expected %s but input ended prematurely"
+#define E_EXPECTED "expected %s but got %s"
+#define E_INSTR    "got unknown instruction"
+#define E_TOOLARGE "expected %s but got out-of-range integer"
 
 enum numsize {
 	NS_NIBBLE = 0xF,
@@ -94,7 +91,7 @@ parselabel(void)
 			.name = tokens->buf[i].sv,
 		};
 		if (regtype(lbl.name) != RT_NONE)
-			die_with_off(lbl.name.p, E_BADLABEL, U8_PRI_ARGS(lbl.name));
+			DIE_AT_POS_WITH_CODE(lbl.name, lbl.name.p, E_BADLABEL);
 		dapush(&ast, lbl);
 		i += 2;
 		return true;
@@ -115,7 +112,7 @@ parseop(void)
 	}
 
 	if (!(op = oplookup(tok.sv.p, tok.sv.len)))
-		die_with_off(tok.sv.p, E_INSTR, U8_PRI_ARGS(tok.sv));
+		DIE_AT_POS_WITH_CODE(tok.sv, tok.sv.p, E_INSTR);
 	op->pfn();
 }
 
@@ -126,7 +123,7 @@ parseaddr(struct token tok)
 		return (struct raw_addr){.val = parsenum(tok, NS_ADDR)};
 	if (tok.kind == T_IDENT) {
 		if (regtype(tok.sv) != RT_NONE)
-			die_with_off(tok.sv.p, E_BADLABEL, U8_PRI_ARGS(tok.sv));
+			DIE_AT_POS_WITH_CODE(tok.sv, tok.sv.p, E_BADLABEL);
 		return (struct raw_addr){.label = true, .sv = tok.sv};
 	}
 	unreachable();
@@ -192,7 +189,7 @@ parsenum(struct token tok, enum numsize size)
 			              : size == NS_BYTE   ? "byte"
 			              : size == NS_ADDR   ? "address"
 			                                  : (unreachable(), nullptr);
-			die_with_off(tok.sv.p, E_TOOLARGE, s, U8_PRI_ARGS(tok.sv));
+			DIE_AT_POS_WITH_CODE(tok.sv, tok.sv.p, E_TOOLARGE, s);
 		}
 
 		acc *= tok.base;
@@ -207,19 +204,15 @@ reqnext(const char *want, tokkind msk)
 {
 	struct token t;
 
-	if (i >= tokens->len)
-		die_with_off(baseptr + filesize - 1, E_EARLY, want);
+	if (i >= tokens->len) {
+		DIE_AT_POS_WITH_CODE((struct u8view){}, baseptr + filesize - 1, E_EARLY,
+		                     want);
+	}
 
 	if ((t = tokens->buf[i++]).kind & msk)
 		return t;
-	if (t.kind == T_EOL) {
-		die_at_pos_with_code(filename, filebuf, (struct u8view){},
-		                     t.sv.p - baseptr, E_EXPECTED2, want,
-		                     tokrepr(t.kind));
-	}
-
-	die_at_pos_with_code(filename, filebuf, t.sv, t.sv.p - baseptr, E_EXPECTED,
-	                     want, tokrepr(t.kind), U8_PRI_ARGS(t.sv));
+	DIE_AT_POS_WITH_CODE(t.kind == T_EOL ? (struct u8view){} : t.sv, t.sv.p,
+	                     E_EXPECTED, want, tokrepr(t.kind));
 }
 
 #define I(...) ((struct dir){.kind = D_INSTR, .instr = (__VA_ARGS__)})
@@ -230,8 +223,8 @@ reqnext(const char *want, tokkind msk)
 		struct instr ins = {.kind = (T)}; \
 		struct token tok = reqnext("v-register", T_IDENT); \
 		if (regtype(tok.sv) & ~RT_VX) { \
-			die_with_off(tok.sv.p, E_EXPECTED, "v-register", \
-			             tokrepr(tok.kind), U8_PRI_ARGS(tok.sv)); \
+			DIE_AT_POS_WITH_CODE(tok.sv, tok.sv.p, E_EXPECTED, "v-register", \
+			                     tokrepr(tok.kind)); \
 		} \
 		ins.args[ins.len++].val = hexval(tok.sv.p[1]); \
 		dapush(&ast, I(ins)); \
@@ -242,12 +235,12 @@ reqnext(const char *want, tokkind msk)
 		struct token lhs = reqnext("v-register", T_IDENT); \
 		struct token rhs = reqnext("v-register", T_IDENT); \
 		if (regtype(lhs.sv) & ~RT_VX) { \
-			die_with_off(lhs.sv.p, E_EXPECTED, "v-register", \
-			             tokrepr(lhs.kind), U8_PRI_ARGS(lhs.sv)); \
+			DIE_AT_POS_WITH_CODE(lhs.sv, lhs.sv.p, E_EXPECTED, "v-register", \
+			                     tokrepr(lhs.kind)); \
 		} \
 		if (regtype(rhs.sv) & ~RT_VX) { \
-			die_with_off(rhs.sv.p, E_EXPECTED, "v-register", \
-			             tokrepr(rhs.kind), U8_PRI_ARGS(rhs.sv)); \
+			DIE_AT_POS_WITH_CODE(rhs.sv, rhs.sv.p, E_EXPECTED, "v-register", \
+			                     tokrepr(rhs.kind)); \
 		} \
 		ins.args[ins.len++].val = hexval(lhs.sv.p[1]); \
 		ins.args[ins.len++].val = hexval(rhs.sv.p[1]); \
@@ -270,8 +263,8 @@ parseop_add(void)
 			ins.kind = I_ADD_VX_B;
 			ins.args[ins.len++].val = parsenum(tok, NS_BYTE);
 		} else if (regtype(tok.sv) != RT_VX) {
-			die_with_off(tok.sv.p, E_EXPECTED, "v-register", tokrepr(tok.kind),
-			             U8_PRI_ARGS(tok.sv));
+			DIE_AT_POS_WITH_CODE(tok.sv, tok.sv.p, E_EXPECTED, "v-register",
+			                     tokrepr(tok.kind));
 		} else {
 			ins.kind = I_ADD_VX_VY;
 			ins.args[ins.len++].val = hexval(tok.sv.p[1]);
@@ -281,14 +274,14 @@ parseop_add(void)
 		ins.kind = I_ADD_I_VX;
 		tok = reqnext("v-register", T_IDENT);
 		if (regtype(tok.sv) != RT_VX) {
-			die_with_off(tok.sv.p, E_EXPECTED, "v-register", tokrepr(tok.kind),
-			             U8_PRI_ARGS(tok.sv));
+			DIE_AT_POS_WITH_CODE(tok.sv, tok.sv.p, E_EXPECTED, "v-register",
+			                     tokrepr(tok.kind));
 		}
 		ins.args[ins.len++].val = hexval(tok.sv.p[1]);
 		break;
 	default:
-		die_with_off(tok.sv.p, E_EXPECTED, "v- or i-register",
-		             tokrepr(tok.kind), U8_PRI_ARGS(tok.sv));
+		DIE_AT_POS_WITH_CODE(tok.sv, tok.sv.p, E_EXPECTED, "v- or i-register",
+		                     tokrepr(tok.kind));
 	}
 
 	dapush(&ast, I(ins));
@@ -354,12 +347,12 @@ parseop_drw(void)
 	op3 = reqnext("nibble", T_NUMBER);
 
 	if (regtype(op1.sv) != RT_VX) {
-		die_with_off(op1.sv.p, E_EXPECTED, "v-register", tokrepr(op1.kind),
-		             U8_PRI_ARGS(op1.sv));
+		DIE_AT_POS_WITH_CODE(op1.sv, op1.sv.p, E_EXPECTED, "v-register",
+		                     tokrepr(op1.kind));
 	}
 	if (regtype(op2.sv) != RT_VX) {
-		die_with_off(op2.sv.p, E_EXPECTED, "v-register", tokrepr(op2.kind),
-		             U8_PRI_ARGS(op2.sv));
+		DIE_AT_POS_WITH_CODE(op2.sv, op2.sv.p, E_EXPECTED, "v-register",
+		                     tokrepr(op2.kind));
 	}
 
 	ins.args[ins.len++].val = hexval(op1.sv.p[1]);
@@ -389,8 +382,8 @@ parseop_jp(void)
 	} else if (op.kind == T_IDENT) {
 		ins.kind = I_JP_V0_A;
 		if (op.sv.len != 2 || !memeq(op.sv.p, "v0", 2)) {
-			die_with_off(op.sv.p, E_EXPECTED, "v0-register or address",
-			             tokrepr(op.kind), U8_PRI_ARGS(op.sv));
+			DIE_AT_POS_WITH_CODE(op.sv, op.sv.p, E_EXPECTED,
+			                     "v0-register or address", tokrepr(op.kind));
 		}
 		ins.args[ins.len++] = parseaddr(reqnext("address", T_NUMBER | T_IDENT));
 	} else
@@ -412,8 +405,8 @@ parseop_ld(void)
 		ins.kind = rt == RT_DT ? I_LD_DT : I_LD_ST;
 		op = reqnext("v-register", T_IDENT);
 		if (regtype(op.sv) != RT_VX) {
-			die_with_off(op.sv.p, E_EXPECTED, "v-register", tokrepr(op.kind),
-			             U8_PRI_ARGS(op.sv));
+			DIE_AT_POS_WITH_CODE(op.sv, op.sv.p, E_EXPECTED, "v-register",
+			                     tokrepr(op.kind));
 		}
 		ins.args[ins.len++].val = hexval(op.sv.p[1]);
 		break;
@@ -441,9 +434,9 @@ parseop_ld(void)
 				ins.args[ins.len++].val = hexval(op.sv.p[1]);
 				break;
 			default:
-				die_with_off(op.sv.p, E_EXPECTED,
-				             "v-, k-, or dt-register, or byte",
-				             tokrepr(op.kind), U8_PRI_ARGS(op.sv));
+				DIE_AT_POS_WITH_CODE(op.sv, op.sv.p, E_EXPECTED,
+				                     "v-, k-, or dt-register, or byte",
+				                     tokrepr(op.kind));
 			}
 
 			break;
@@ -457,8 +450,8 @@ parseop_ld(void)
 		break;
 
 	default:
-		die_with_off(op.sv.p, E_EXPECTED, "v-, i-, dt-, or st-register",
-		             tokrepr(op.kind), U8_PRI_ARGS(op.sv));
+		DIE_AT_POS_WITH_CODE(op.sv, op.sv.p, E_EXPECTED,
+		                     "v-, i-, dt-, or st-register", tokrepr(op.kind));
 	}
 
 	dapush(&ast, I(ins));
@@ -486,8 +479,8 @@ parseop_rnd(void)
 	op2 = reqnext("byte", T_NUMBER);
 
 	if (regtype(op1.sv) != RT_VX) {
-		die_with_off(op1.sv.p, E_EXPECTED, "v-register", tokrepr(op1.kind),
-		             U8_PRI_ARGS(op1.sv));
+		DIE_AT_POS_WITH_CODE(op1.sv, op1.sv.p, E_EXPECTED, "v-register",
+		                     tokrepr(op1.kind));
 	}
 
 	ins.args[ins.len++].val = hexval(op1.sv.p[1]);
@@ -511,16 +504,16 @@ parseop_se(void)
 	op2 = reqnext("byte or v-register", T_IDENT | T_NUMBER);
 
 	if (regtype(op1.sv) != RT_VX) {
-		die_with_off(op1.sv.p, E_EXPECTED, "v-register", tokrepr(op1.kind),
-		             U8_PRI_ARGS(op1.sv));
+		DIE_AT_POS_WITH_CODE(op1.sv, op1.sv.p, E_EXPECTED, "v-register",
+		                     tokrepr(op1.kind));
 	}
 	ins.args[ins.len++].val = hexval(op1.sv.p[1]);
 
 	switch (op2.kind) {
 	case T_IDENT:
 		if (regtype(op2.sv) != RT_VX) {
-			die_with_off(op2.sv.p, E_EXPECTED, "v-register", tokrepr(op2.kind),
-			             U8_PRI_ARGS(op2.sv));
+			DIE_AT_POS_WITH_CODE(op2.sv, op2.sv.p, E_EXPECTED, "v-register",
+			                     tokrepr(op2.kind));
 		}
 		ins.kind = I_SE_VX_VY;
 		ins.args[ins.len++].val = hexval(op2.sv.p[1]);
@@ -570,16 +563,16 @@ parseop_sne(void)
 	op2 = reqnext("byte or v-register", T_IDENT | T_NUMBER);
 
 	if (regtype(op1.sv) != RT_VX) {
-		die_with_off(op1.sv.p, E_EXPECTED, "v-register", tokrepr(op1.kind),
-		             U8_PRI_ARGS(op1.sv));
+		DIE_AT_POS_WITH_CODE(op1.sv, op1.sv.p, E_EXPECTED, "v-register",
+		                     tokrepr(op1.kind));
 	}
 	ins.args[ins.len++].val = hexval(op1.sv.p[1]);
 
 	switch (op2.kind) {
 	case T_IDENT:
 		if (regtype(op2.sv) != RT_VX) {
-			die_with_off(op2.sv.p, E_EXPECTED, "v-register", tokrepr(op2.kind),
-			             U8_PRI_ARGS(op2.sv));
+			DIE_AT_POS_WITH_CODE(op2.sv, op2.sv.p, E_EXPECTED, "v-register",
+			                     tokrepr(op2.kind));
 		}
 		ins.kind = I_SNE_VX_VY;
 		ins.args[ins.len++].val = hexval(op2.sv.p[1]);
diff --git a/src/common/cerr.c b/src/common/cerr.c
index 819df4a..98bca0f 100644
--- a/src/common/cerr.c
+++ b/src/common/cerr.c
@@ -19,7 +19,6 @@
 
 #define SGR_BOLD "\33[1m"
 #define SGR_DONE "\33[0m"
-#define SGR_WARN "\33[1;35m"
 #define SGR_ERR  "\33[1;31m"
 
 int sizelen(size_t);
@@ -27,7 +26,7 @@ int sizelen(size_t);
 static bool color;
 static const char *progname;
 
-static const char *_bold, *_done, *_warn, *_err;
+static const char *_bold, *_done, *_err;
 
 void
 cerrinit(const char *s)
@@ -43,10 +42,9 @@ cerrinit(const char *s)
 	if (color) {
 		_bold = SGR_BOLD;
 		_done = SGR_DONE;
-		_warn = SGR_WARN;
 		_err = SGR_ERR;
 	} else
-		_bold = _done = _warn = _err = "";
+		_bold = _done = _err = "";
 }
 
 void
-- 
cgit v1.2.3