diff options
author | Himbeer <himbeer@disroot.org> | 2024-09-19 21:59:35 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-09-19 22:09:49 +0200 |
commit | 68effb746fc33f90b6fe537893f18ac0aac4e7f0 (patch) | |
tree | 9906b31bd5866014cf9c74fbd7ee6c40faeb048a | |
parent | a278c311ee4a76c5855d4a8339c15c054a6eca19 (diff) |
Store token locations and include them in parsing error messages
-rw-r--r-- | include/lex.h | 11 | ||||
-rw-r--r-- | src/lex.c | 22 | ||||
-rw-r--r-- | src/main.c | 2 | ||||
-rw-r--r-- | src/parse.c | 12 |
4 files changed, 39 insertions, 8 deletions
diff --git a/include/lex.h b/include/lex.h index ba1596d..51485a5 100644 --- a/include/lex.h +++ b/include/lex.h @@ -103,8 +103,14 @@ struct number { } value; }; +struct location { + const char *file; + int line, column; +}; + struct token { enum lexical_token token; + struct location loc; union { struct number num; const char *str; @@ -117,11 +123,14 @@ struct lexer { char *buf; size_t bufsz, buflen; struct token un; + struct location loc; }; -void lex_init(struct lexer *lexer, FILE *f); +void lex_init(struct lexer *lexer, FILE *f, const char *filename); void lex_finish(struct lexer *lexer); +struct location lex_loc(struct lexer *lexer); + enum lexical_token lex(struct lexer *lexer, struct token *out); void unlex(struct lexer *lexer, const struct token *in); bool match(struct lexer *lexer, enum lexical_token token); @@ -46,7 +46,7 @@ const char *tokens[] = { }; void -lex_init(struct lexer *lexer, FILE *f) +lex_init(struct lexer *lexer, FILE *f, const char *filename) { lexer->in = f; lexer->c[0] = 0; @@ -55,6 +55,9 @@ lex_init(struct lexer *lexer, FILE *f) lexer->bufsz = 2; lexer->buflen = 0; lexer->un.token = T_NONE; + lexer->loc.file = filename; + lexer->loc.line = 1; + lexer->loc.column = 0; } void @@ -63,6 +66,15 @@ lex_finish(struct lexer *lexer) fclose(lexer->in); } +struct location +lex_loc(struct lexer *lexer) +{ + if (lexer->un.token != T_NONE) { + return lexer->un.loc; + } + return lexer->loc; +} + static uint32_t next(struct lexer *lexer) { if (lexer->c[0]) { @@ -75,6 +87,13 @@ static uint32_t next(struct lexer *lexer) return c; } + if (c == '\n') { + ++lexer->loc.line; + lexer->loc.column = 0; + } else { + ++lexer->loc.column; + } + lexer->c[1] = c; return c; } @@ -240,6 +259,7 @@ lex(struct lexer *lexer, struct token *out) } uint32_t c = wgetc(lexer); + out->loc = lexer->loc; if (c == C_EOF) { out->token = T_EOF; return out->token; @@ -41,7 +41,7 @@ main(int argc, char *argv[]) return EXIT_ABNORMAL; } - lex_init(&lexer, in); + lex_init(&lexer, in, path); parse(&lexer, &ast); lex_finish(&lexer); } diff --git a/src/parse.c b/src/parse.c index a047424..2fa3ee4 100644 --- a/src/parse.c +++ b/src/parse.c @@ -5,8 +5,10 @@ #include "util.h" static noreturn void -error(const char *fmt, ...) +error(struct location loc, const char *fmt, ...) { + fprintf(stderr, "%s:%d:%d ", loc.file, loc.line, loc.column); + va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); @@ -34,7 +36,7 @@ parse_path(struct lexer *lexer, struct ast_path *out) struct token name; if (lex(lexer, &name) != T_NAME) { - error("syntax error: expected path"); + error(name.loc, "syntax error: expected path"); } out->segments = must_calloc(1, sizeof(const char *)); @@ -44,7 +46,7 @@ parse_path(struct lexer *lexer, struct ast_path *out) while (match(lexer, T_MODDELIM)) { if (lex(lexer, &name) != T_NAME) { - error("syntax error: expected name"); + error(name.loc, "syntax error: expected name"); } append(out, name.info.str); } @@ -60,7 +62,7 @@ parse_import(struct lexer *lexer, struct ast_import *out) } if (!parse_path(lexer, &out->path)) { - error("syntax error: expected import path"); + error(lex_loc(lexer), "syntax error: expected import path"); } struct token token; @@ -72,7 +74,7 @@ parse_import(struct lexer *lexer, struct ast_import *out) } if (!match(lexer, T_SEMICOLON)) { - error("syntax error: expected semicolon"); + error(lex_loc(lexer), "syntax error: expected semicolon"); } return true; |