commit ef80474926e643782b6684c10ec7367bd2a1ed01
parent 63959a59c2526161431457084565f13ffa939916
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sat, 25 Apr 2026 14:42:41 -0700
M1pp: track source line numbers and report them in error messages
Diffstat:
| M | M1pp/M1pp.c | | | 49 | ++++++++++++++++++++++++++++++++++++++----------- |
1 file changed, 38 insertions(+), 11 deletions(-)
diff --git a/M1pp/M1pp.c b/M1pp/M1pp.c
@@ -127,6 +127,7 @@ struct TextSpan {
struct Token {
int kind;
int tight;
+ int line;
struct TextSpan text;
};
@@ -178,6 +179,9 @@ static int output_need_space;
static int stream_top;
static int next_expansion_id;
static int scope_depth;
+static int current_line;
+static int error_line;
+static const char *input_path;
static struct Token *arg_starts[MAX_PARAMS];
static struct Token *arg_ends[MAX_PARAMS];
@@ -189,6 +193,7 @@ static const char *error_msg;
static int fail(const char *msg)
{
error_msg = msg;
+ error_line = current_line;
return 0;
}
@@ -213,13 +218,14 @@ static char *append_text_len(const char *s, int len)
}
static int push_token(struct Token *buf, int *count, int max_count,
- int kind, int tight, struct TextSpan text)
+ int kind, int tight, int line, struct TextSpan text)
{
if (*count >= max_count) {
return fail("token overflow");
}
buf[*count].kind = kind;
buf[*count].tight = tight;
+ buf[*count].line = line;
buf[*count].text = text;
*count += 1;
return 1;
@@ -255,6 +261,7 @@ static int lex_source(const char *src)
* LPAREN's tight bit is consulted, to decide whether %FOO(...) /
* !(...) etc. are paren-call forms. */
int i = 0;
+ int line = 1;
int saw_separator = 1;
while (src[i] != '\0') {
@@ -262,6 +269,8 @@ static int lex_source(const char *src)
int len;
int tight;
+ current_line = line;
+
if (is_space_no_nl((unsigned char)src[i])) {
saw_separator = 1;
i++;
@@ -269,9 +278,10 @@ static int lex_source(const char *src)
}
if (src[i] == '\n') {
if (!push_token(source_tokens, &source_count, MAX_TOKENS,
- TOK_NEWLINE, 0, (struct TextSpan){src + i, 1})) {
+ TOK_NEWLINE, 0, line, (struct TextSpan){src + i, 1})) {
return 0;
}
+ line++;
saw_separator = 1;
i++;
continue;
@@ -283,6 +293,9 @@ static int lex_source(const char *src)
start = i;
i++;
while (src[i] != '\0' && src[i] != quote) {
+ if (src[i] == '\n') {
+ line++;
+ }
i++;
}
if (src[i] == quote) {
@@ -290,7 +303,7 @@ static int lex_source(const char *src)
}
len = i - start;
if (!push_token(source_tokens, &source_count, MAX_TOKENS,
- TOK_STRING, tight, (struct TextSpan){src + start, len})) {
+ TOK_STRING, tight, current_line, (struct TextSpan){src + start, len})) {
return 0;
}
saw_separator = 0;
@@ -299,7 +312,7 @@ static int lex_source(const char *src)
if (src[i] == '#' && src[i + 1] == '#') {
tight = !saw_separator;
if (!push_token(source_tokens, &source_count, MAX_TOKENS,
- TOK_PASTE, tight, (struct TextSpan){src + i, 2})) {
+ TOK_PASTE, tight, line, (struct TextSpan){src + i, 2})) {
return 0;
}
i += 2;
@@ -316,7 +329,7 @@ static int lex_source(const char *src)
if (src[i] == '(') {
tight = !saw_separator;
if (!push_token(source_tokens, &source_count, MAX_TOKENS,
- TOK_LPAREN, tight, (struct TextSpan){src + i, 1})) {
+ TOK_LPAREN, tight, line, (struct TextSpan){src + i, 1})) {
return 0;
}
i++;
@@ -326,7 +339,7 @@ static int lex_source(const char *src)
if (src[i] == ')') {
tight = !saw_separator;
if (!push_token(source_tokens, &source_count, MAX_TOKENS,
- TOK_RPAREN, tight, (struct TextSpan){src + i, 1})) {
+ TOK_RPAREN, tight, line, (struct TextSpan){src + i, 1})) {
return 0;
}
i++;
@@ -336,7 +349,7 @@ static int lex_source(const char *src)
if (src[i] == ',') {
tight = !saw_separator;
if (!push_token(source_tokens, &source_count, MAX_TOKENS,
- TOK_COMMA, tight, (struct TextSpan){src + i, 1})) {
+ TOK_COMMA, tight, line, (struct TextSpan){src + i, 1})) {
return 0;
}
i++;
@@ -346,7 +359,7 @@ static int lex_source(const char *src)
if (src[i] == '{') {
tight = !saw_separator;
if (!push_token(source_tokens, &source_count, MAX_TOKENS,
- TOK_LBRACE, tight, (struct TextSpan){src + i, 1})) {
+ TOK_LBRACE, tight, line, (struct TextSpan){src + i, 1})) {
return 0;
}
i++;
@@ -356,7 +369,7 @@ static int lex_source(const char *src)
if (src[i] == '}') {
tight = !saw_separator;
if (!push_token(source_tokens, &source_count, MAX_TOKENS,
- TOK_RBRACE, tight, (struct TextSpan){src + i, 1})) {
+ TOK_RBRACE, tight, line, (struct TextSpan){src + i, 1})) {
return 0;
}
i++;
@@ -381,7 +394,7 @@ static int lex_source(const char *src)
}
len = i - start;
if (!push_token(source_tokens, &source_count, MAX_TOKENS,
- TOK_WORD, tight, (struct TextSpan){src + start, len})) {
+ TOK_WORD, tight, line, (struct TextSpan){src + start, len})) {
return 0;
}
saw_separator = 0;
@@ -654,6 +667,7 @@ static int define_fielded_macro(struct TextSpan base, const char *suffix,
m->param_count = 0;
body_tok.kind = TOK_WORD;
body_tok.tight = 0;
+ body_tok.line = current_line;
if (!emit_decimal_text(value, &body_tok.text)) {
return 0;
}
@@ -1071,6 +1085,7 @@ static int push_local_label_token(const struct Token *tok, int expansion_id)
out.kind = TOK_WORD;
out.tight = 0;
+ out.line = current_line;
out.text.ptr = text_buf + start;
out.text.len = total;
return push_pool_token(out);
@@ -1438,6 +1453,9 @@ static int eval_expr_range(struct TokenSpan span, long long *out)
if (pos >= span.end) {
break;
}
+ if (pos->line > 0) {
+ current_line = pos->line;
+ }
if (pos->kind == TOK_LPAREN) {
enum ExprOp op;
@@ -1541,6 +1559,7 @@ static int emit_hex_value(unsigned long long value, int bytes)
}
tok.kind = TOK_STRING;
tok.tight = 0;
+ tok.line = current_line;
tok.text.ptr = text_ptr;
tok.text.len = total_len;
return emit_token(&tok);
@@ -1643,6 +1662,7 @@ static int expand_builtin_call(struct Stream *s, const struct Token *tok)
out_tok.kind = TOK_STRING;
out_tok.tight = 0;
+ out_tok.line = current_line;
out_tok.text.ptr = text_ptr;
out_tok.text.len = out_len;
s->pos = end_pos;
@@ -1733,6 +1753,9 @@ static int process_tokens(void)
}
tok = s->pos;
+ if (tok->line > 0) {
+ current_line = tok->line;
+ }
if (tok->kind == TOK_WORD && token_text_eq(tok, "%macro")) {
if (!define_macro(s)) {
@@ -1834,6 +1857,7 @@ int main(int argc, char **argv)
return 1;
}
+ input_path = argv[1];
in = fopen(argv[1], "rb");
if (in == NULL) {
perror(argv[1]);
@@ -1853,7 +1877,10 @@ int main(int argc, char **argv)
input_buf[nread] = '\0';
if (!lex_source(input_buf) || !process_tokens()) {
- fprintf(stderr, "m1macro: %s\n", error_msg != NULL ? error_msg : "failed");
+ fprintf(stderr, "%s:%d: m1macro: %s\n",
+ input_path != NULL ? input_path : "?",
+ error_line,
+ error_msg != NULL ? error_msg : "failed");
return 1;
}