aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2021-08-07 23:39:21 +0200
committerMarvin Borner2021-08-07 23:39:21 +0200
commit51c4defc436c0d119941eb6d5b953d27b5b8e6f7 (patch)
treec90b6329b81a4c4715f7860cb3a6a7b1d3174e37
parent55e5ec54eaef97e87efefc2294a5afaf8935566b (diff)
Better error logging
-rw-r--r--inc/context.h14
-rw-r--r--inc/log.h3
-rw-r--r--inc/tokenize.h1
-rw-r--r--src/context.c66
-rw-r--r--src/lint.c2
-rw-r--r--src/log.c66
-rw-r--r--src/main.c9
-rw-r--r--src/preprocess.c34
-rw-r--r--src/tokenize.c32
-rw-r--r--src/treeify.c2
10 files changed, 116 insertions, 113 deletions
diff --git a/inc/context.h b/inc/context.h
index b11e23d..5b314d7 100644
--- a/inc/context.h
+++ b/inc/context.h
@@ -2,18 +2,25 @@
#define CONTEXT_H
#include <stddef.h>
+#include <stdio.h>
typedef struct {
size_t start, end;
} ctx_string;
-struct ctx {
+struct ctx_location {
size_t line;
size_t column;
const char *path;
- char *raw;
- char *data;
+ char *data; // Raw
+ size_t size;
+};
+
+struct ctx {
+ struct ctx_location location;
+
+ char *data; // Preprocessed
size_t size;
size_t token_count;
@@ -27,6 +34,7 @@ struct ctx {
struct ctx *context_create(const char *path);
void context_destroy(struct ctx *ctx);
+void context_print(FILE *fd, struct ctx_location *location);
void context_rewind(struct ctx *ctx);
#endif
diff --git a/inc/log.h b/inc/log.h
index 4698f9c..da82233 100644
--- a/inc/log.h
+++ b/inc/log.h
@@ -3,7 +3,6 @@
#include <context.h>
-__attribute__((noreturn)) void errln(struct ctx *ctx, const char *fmt, ...);
-__attribute__((noreturn)) void err(const char *fmt, ...);
+__attribute__((noreturn)) void errln(struct ctx_location *location, const char *fmt, ...);
#endif
diff --git a/inc/tokenize.h b/inc/tokenize.h
index d1a2931..f5e8600 100644
--- a/inc/tokenize.h
+++ b/inc/tokenize.h
@@ -28,6 +28,7 @@ enum token_type {
struct token {
enum token_type type;
+ struct ctx_location location;
ctx_string string;
};
diff --git a/src/context.c b/src/context.c
index ff0291a..be93db0 100644
--- a/src/context.c
+++ b/src/context.c
@@ -1,6 +1,7 @@
#include <assert.h>
-#include <stdio.h>
+#include <math.h>
#include <stdlib.h>
+#include <string.h>
#include <context.h>
#include <tokenize.h>
@@ -10,23 +11,23 @@ struct ctx *context_create(const char *path)
{
struct ctx *ctx = calloc(1, sizeof(*ctx));
ctx->tokens = calloc(TOKENS_MAX, sizeof(*ctx->tokens));
- ctx->path = path; // TODO: strdup?
+ ctx->location.path = path; // TODO: strdup?
FILE *file = fopen(path, "r");
assert(file);
// Find size of file
fseek(file, 0, SEEK_END);
- ctx->size = ftell(file);
+ ctx->location.size = ftell(file);
rewind(file);
- assert(ctx->size);
+ assert(ctx->location.size);
- ctx->raw = malloc(ctx->size + 1);
- assert(ctx->raw);
- fread(ctx->raw, 1, ctx->size, file);
+ ctx->location.data = malloc(ctx->location.size + 1);
+ assert(ctx->location.data);
+ fread(ctx->location.data, 1, ctx->location.size, file);
fclose(file);
- ctx->raw[ctx->size] = 0;
+ ctx->location.data[ctx->location.size] = 0;
ctx->tree.head = tree_create();
ctx->tree.current = NULL;
@@ -39,10 +40,10 @@ void context_destroy(struct ctx *ctx)
if (!ctx)
return;
- if (ctx->raw)
- free(ctx->raw);
+ if (ctx->location.data)
+ free(ctx->location.data);
- if (ctx->data && ctx->data != ctx->raw)
+ if (ctx->data && ctx->data != ctx->location.data)
free(ctx->data);
if (ctx->tokens)
@@ -54,8 +55,47 @@ void context_destroy(struct ctx *ctx)
free(ctx);
}
+#define CONTEXT_COUNT 3
+void context_print(FILE *fd, struct ctx_location *location)
+{
+ size_t start_line = fmax((int)location->line - CONTEXT_COUNT, 0);
+ size_t end_line = location->line + CONTEXT_COUNT + 1;
+
+ for (size_t line = 0, index = 0; line < end_line;) {
+ if (line < start_line) {
+ if (location->data[index++] == '\n')
+ line++;
+ continue;
+ }
+
+ const char *end = strchr(location->data + index, '\n') + 1;
+ assert(end);
+ size_t length = end - (location->data + index) - 1;
+
+ if (location->line == line) {
+ int pointer_length = location->column + 9;
+ char *pointer = malloc(pointer_length); // Literally a pointer
+ fprintf(fd,
+ "\x1B[1;32m%6lu | %.*s\x1B[1;31m%c\x1B[1;32m%.*s\n\x1B[1;31m%.*s%c\x1B[0m\n",
+ line + 1, (int)location->column, location->data + index,
+ *(location->data + index + location->column),
+ (int)(length - location->column - 1),
+ location->data + index + location->column + 1, pointer_length,
+ (char *)memset(pointer, '~', pointer_length), '^');
+ free(pointer);
+ } else {
+ fprintf(fd, "%6lu | %.*s\n", line + 1, (int)length, location->data + index);
+ }
+
+ index = end - location->data;
+ line++;
+ if (index >= location->size)
+ return;
+ }
+}
+
void context_rewind(struct ctx *ctx)
{
- ctx->line = 0;
- ctx->column = 0;
+ ctx->location.line = 0;
+ ctx->location.column = 0;
}
diff --git a/src/lint.c b/src/lint.c
index 5ff1864..7c2e9da 100644
--- a/src/lint.c
+++ b/src/lint.c
@@ -17,5 +17,5 @@ void lint(struct ctx *ctx)
}
if (parens != 0)
- errln(ctx, "Invalid parens balance");
+ errln(&ctx->location, "Invalid parens balance");
}
diff --git a/src/log.c b/src/log.c
index 5820a67..0e59ea2 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,78 +1,24 @@
+#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <log.h>
-static void context_print(FILE *fd, struct ctx *ctx)
+void errln(struct ctx_location *location, const char *fmt, ...)
{
- const char *data = ctx->data ? ctx->data : ctx->raw;
+ fprintf(stderr, "\x1B[1;36m%s:%lu:%lu:\x1B[0m ", location->path, location->line + 1,
+ location->column + 1);
- // Find line, column
- size_t line = 0, column = 0, index = 0;
- for (; index < ctx->size; index++) {
- char cur = data[index];
+ fprintf(stderr, "\x1B[1;31mError:\x1B[0m ");
- column++;
-
- if (line == ctx->line && column == ctx->column)
- break;
-
- if (cur == '\n') {
- line++;
- column = 0;
- continue;
- } else if (cur == '\0') {
- fprintf(stderr, "Invalid context!");
- context_destroy(ctx);
- exit(1);
- break;
- }
- }
-
- if (++index >= ctx->size)
- return; // Couldn't find context, idc?
-
- fprintf(fd, "\x1B[1;36m%s:%ld:%ld:\x1B[0m '", ctx->path, ctx->line + 1, ctx->column + 1);
-
- // Print line context
- size_t start = ctx->column > 5 ? index - 5 : index;
- size_t end = ctx->size - index > 5 ? index + 5 : index + 1;
- for (size_t i = start; i < end; i++) {
- if (i == index) {
- fprintf(fd, "\x1B[1;32m%c\x1B[0m", data[i]);
- } else {
- fprintf(fd, "%c", data[i]);
- }
- }
- fprintf(fd, "': ");
-}
-
-void errln(struct ctx *ctx, const char *fmt, ...)
-{
- context_print(stderr, ctx);
-
- fprintf(stderr, "\x1B[1;31m");
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
va_end(ap);
- fprintf(stderr, "\x1B[0m");
- context_destroy(ctx);
- exit(1);
-}
-
-void err(const char *fmt, ...)
-{
- fprintf(stderr, "\x1B[1;31m");
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
- va_end(ap);
- fprintf(stderr, "\x1B[0m");
+ context_print(stderr, location);
exit(1);
}
diff --git a/src/main.c b/src/main.c
index 0e6807d..5827913 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,3 +1,6 @@
+#include <stdio.h>
+#include <stdlib.h>
+
#include <context.h>
#include <lint.h>
#include <log.h>
@@ -7,8 +10,10 @@
int main(int argc, char *argv[])
{
- if (argc < 2)
- err("Not enough arguments!");
+ if (argc < 2) {
+ fprintf(stderr, "Not enough arguments!");
+ exit(1);
+ }
struct ctx *ctx = context_create(argv[1]);
preprocess(ctx);
diff --git a/src/preprocess.c b/src/preprocess.c
index 8d9394a..3a0c0bc 100644
--- a/src/preprocess.c
+++ b/src/preprocess.c
@@ -1,6 +1,7 @@
#include <assert.h>
#include <math.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include <log.h>
@@ -8,43 +9,46 @@
static void preprocess_erase(struct ctx *ctx, size_t start)
{
- assert(ctx->raw[start] == '#');
+ assert(ctx->data[start] == '#');
for (size_t i = start; i < ctx->size; i++) {
- char cur = ctx->raw[i];
+ char cur = ctx->data[i];
if (cur == '\n' || cur == '\0')
break;
- ctx->raw[i] = ' '; // Spaces get skipped by tokenizer anyways
+ ctx->data[i] = ' '; // Spaces get skipped by tokenizer anyways
}
}
void preprocess(struct ctx *ctx)
{
- for (size_t i = 0; i < ctx->size; i++) {
- const char cur = ctx->raw[i];
+ ctx->size = ctx->location.size;
+ ctx->data = malloc(ctx->size);
+ memcpy(ctx->data, ctx->location.data, ctx->size);
- ctx->column++;
+ for (size_t i = 0; i < ctx->location.size; i++) {
+ const char cur = ctx->location.data[i];
+
+ ctx->location.column++;
if (cur == '\n') {
- ctx->line++;
- ctx->column = 0;
+ ctx->location.line++;
+ ctx->location.column = 0;
continue;
} else if (cur == '\0') {
break;
- } else if (cur == '#' && ctx->column == 1) {
- if (strncmp(ctx->raw + i + 1, "inc ", fmin(4, ctx->size - i)) == 0) {
+ } else if (cur == '#' && ctx->location.column == 1) {
+ if (strncmp(ctx->location.data + i + 1, "inc ",
+ fmin(4, ctx->location.size - i)) == 0) {
// TODO: Add include features
- } else if (*(ctx->raw + i + 1) == '#') {
+ } else if (*(ctx->location.data + i + 1) == '#') {
// Comment
} else {
- errln(ctx, "Invalid preprocessing directive");
+ errln(&ctx->location, "Invalid preprocessing directive");
}
preprocess_erase(ctx, i);
}
}
- ctx->data = ctx->raw;
- ctx->line = 0;
- ctx->column = 0;
+ context_rewind(ctx);
}
diff --git a/src/tokenize.c b/src/tokenize.c
index 02059a8..2a0eea6 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -13,7 +13,7 @@ static char next_non_alnum(struct ctx *ctx, size_t start)
if (!isalnum(ctx->data[i]))
return ctx->data[i];
- errln(ctx, "Unexpected end of buffer");
+ errln(&ctx->location, "Unexpected end of buffer");
}
static bool peek_to_is_alnum(struct ctx *ctx, size_t start, char ch)
@@ -28,7 +28,7 @@ static bool peek_to_is_alnum(struct ctx *ctx, size_t start, char ch)
return false;
}
- errln(ctx, "Unexpected end of buffer");
+ errln(&ctx->location, "Unexpected end of buffer");
}
static size_t peek_alnum_to(struct ctx *ctx, size_t start, char ch)
@@ -40,10 +40,10 @@ static size_t peek_alnum_to(struct ctx *ctx, size_t start, char ch)
return i;
if (!isalnum(cur))
- errln(ctx, "'%c' is not alpha-numeric", cur);
+ errln(&ctx->location, "'%c' is not alpha-numeric", cur);
}
- errln(ctx, "Unexpected end of buffer");
+ errln(&ctx->location, "Unexpected end of buffer");
}
static size_t peek_identifier(struct ctx *ctx, size_t start, char ch)
@@ -55,10 +55,10 @@ static size_t peek_identifier(struct ctx *ctx, size_t start, char ch)
return i;
if (!isalnum(cur) && (cur < '!' || cur > '~'))
- errln(ctx, "'%c' is not an identifier", cur);
+ errln(&ctx->location, "'%c' is not an identifier", cur);
}
- errln(ctx, "Unexpected end of buffer");
+ errln(&ctx->location, "Unexpected end of buffer");
}
static size_t peek_to(struct ctx *ctx, size_t start, char ch)
@@ -70,7 +70,7 @@ static size_t peek_to(struct ctx *ctx, size_t start, char ch)
return i;
}
- errln(ctx, "Unexpected end of buffer");
+ errln(&ctx->location, "Unexpected end of buffer");
}
static void token_add(struct ctx *ctx, enum token_type type, size_t start, size_t end)
@@ -79,15 +79,16 @@ static void token_add(struct ctx *ctx, enum token_type type, size_t start, size_
token.type = type;
token.string.start = start;
token.string.end = end;
+ token.location = ctx->location;
assert(++ctx->token_count < TOKENS_MAX);
ctx->tokens[ctx->token_count] = token;
if (type == NEWLINE) {
- ctx->line++;
- ctx->column = 0;
+ ctx->location.line++;
+ ctx->location.column = 0;
} else {
- ctx->column += end - start;
+ ctx->location.column += end - start;
}
}
@@ -95,15 +96,14 @@ void token_print(struct ctx *ctx, struct token *token)
{
assert(token->type != UNKNOWN);
- printf("[token type=%d] '", token->type);
+ printf("[token type=%d] ", token->type);
if (token->type == NEWLINE || token->type == END) {
printf("' (Unprintable)\n");
return;
}
- for (size_t i = token->string.start; i < token->string.end; i++)
- printf("%c", ctx->data[i]);
- printf("'\n");
+ printf("'%.*s'\n", (int)(token->string.end - token->string.start),
+ ctx->data + token->string.start);
}
void tokenize(struct ctx *ctx)
@@ -131,7 +131,7 @@ void tokenize(struct ctx *ctx)
token_add(ctx, EQUAL, i, i + 1);
continue;
case ' ':
- ctx->column++;
+ ctx->location.column++;
continue;
default:
break;
@@ -145,7 +145,7 @@ void tokenize(struct ctx *ctx)
} else { // Unnamed identifier ('_')
end_param = peek_to(ctx, start_param, ' ');
if (end_param - start_param != 1 || ctx->data[start_param] != '_')
- errln(ctx, "Invalid param identifier");
+ errln(&ctx->location, "Invalid param identifier");
}
token_add(ctx, TYPE, i, start_param - 1);
diff --git a/src/treeify.c b/src/treeify.c
index 8da6481..5539d21 100644
--- a/src/treeify.c
+++ b/src/treeify.c
@@ -12,7 +12,7 @@ static void __expect(struct ctx *ctx, struct token *token, enum token_type type,
if (token->type != type) {
printf("[DBG] %s:%d: %s\n", file, line, func);
token_print(ctx, token);
- err("Expected token of type %s!\n", type_enum);
+ errln(&token->location, "Expected token of type %s", type_enum);
}
}