From cc5a6d978144bda90220bd10866c4fd908d07546 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sat, 3 Aug 2019 15:02:08 +0900 Subject: [PATCH] Improve error message Now, chibicc can print out an error message with an error location like this: $ ./chibicc 1+foo 1+foo ^ expected a number --- main.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index 5cf2bee..cefd99d 100644 --- a/main.c +++ b/main.c @@ -21,6 +21,9 @@ struct Token { int len; // Token length }; +// Input string +static char *current_input; + // Reports an error and exit. static void error(char *fmt, ...) { va_list ap; @@ -30,6 +33,29 @@ static void error(char *fmt, ...) { exit(1); } +// Reports an error location and exit. +static void verror_at(char *loc, char *fmt, va_list ap) { + int pos = loc - current_input; + fprintf(stderr, "%s\n", current_input); + fprintf(stderr, "%*s", pos, ""); // print pos spaces. + fprintf(stderr, "^ "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + exit(1); +} + +static void error_at(char *loc, char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + verror_at(loc, fmt, ap); +} + +static void error_tok(Token *tok, char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + verror_at(tok->loc, fmt, ap); +} + // Consumes the current token if it matches `s`. static bool equal(Token *tok, char *op) { return memcmp(tok->loc, op, tok->len) == 0 && op[tok->len] == '\0'; @@ -38,14 +64,14 @@ static bool equal(Token *tok, char *op) { // Ensure that the current token is `s`. static Token *skip(Token *tok, char *s) { if (!equal(tok, s)) - error("expected '%s'", s); + error_tok(tok, "expected '%s'", s); return tok->next; } // Ensure that the current token is TK_NUM. static int get_number(Token *tok) { if (tok->kind != TK_NUM) - error("expected a number"); + error_tok(tok, "expected a number"); return tok->val; } @@ -58,8 +84,9 @@ static Token *new_token(TokenKind kind, char *start, char *end) { return tok; } -// Tokenize `p` and returns new tokens. -static Token *tokenize(char *p) { +// Tokenize `current_input` and returns new tokens. +static Token *tokenize(void) { + char *p = current_input; Token head = {}; Token *cur = &head; @@ -86,7 +113,7 @@ static Token *tokenize(char *p) { continue; } - error("invalid token"); + error_at(p, "invalid token"); } cur = cur->next = new_token(TK_EOF, p, p); @@ -97,7 +124,8 @@ int main(int argc, char **argv) { if (argc != 2) error("%s: invalid number of arguments", argv[0]); - Token *tok = tokenize(argv[1]); + current_input = argv[1]; + Token *tok = tokenize(); printf(" .globl main\n"); printf("main:\n");