From 328e34077a2017d4017f907ac69c7ed5d6c160d4 Mon Sep 17 00:00:00 2001 From: David Phillips Date: Wed, 1 Aug 2018 20:21:37 +1200 Subject: Trim leading whitespace from contextual error, detect EOF Side-note that the token location tuple maintains the correct column number to include the whitespace in the source file. Side-side note: tabs are counted as one column but many editors will count them as whatever the tabstop/tabwidth is. --- common.c | 8 +++++++- lexer.c | 7 +++++++ lexer.h | 1 + parser.c | 30 ++++++++++++++++++++++++------ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/common.c b/common.c index 96c9b72..c0e0af4 100644 --- a/common.c +++ b/common.c @@ -7,13 +7,19 @@ indicate_file_area(FILE* fd, size_t line, size_t column, size_t span) { char margin[] = " "; /* FIXME use proper line counting, not this hack */ char buf[1024]; + char *line_start = &buf; + rewind(fd); for (; line; line--) { fgets(buf, sizeof(buf), fd); } + while (*line_start == '\t' || *line_start == ' ') { + line_start++; + } + fputs(margin, stderr); - fputs(buf, stderr); + fputs(line_start, stderr); /* corner case (still needed?) - buf was just return */ if (strlen(buf) == 1 && buf[0] == '\n') { diff --git a/lexer.c b/lexer.c index a8b7716..d9810a5 100644 --- a/lexer.c +++ b/lexer.c @@ -53,6 +53,7 @@ static char buf[BUFFER_SIZE]; static FILE* fd; static size_t line_number = 0; static size_t column_number = 0; +static size_t leading_whitespace_len = 0; static struct token *tok_start = NULL; static struct token *tok_cursor = NULL; @@ -64,6 +65,7 @@ get_current_loc(void) { struct location l; l.line = line_number; l.column = column_number + 1; + l.leading_whitespace_len = leading_whitespace_len; return l; } @@ -187,6 +189,8 @@ lex_colon(void) { static int lex_line(void) { size_t length = strlen(buf); + leading_whitespace_len = 0; + while (column_number < length && column_number < strlen(buf)) { switch (buf[column_number]) { case ':': @@ -195,6 +199,9 @@ lex_line(void) { case ' ': case '\t': eat_whitespace(); + if (leading_whitespace_len == 0) { + leading_whitespace_len = column_number; + } break; case '\r': case '\n': diff --git a/lexer.h b/lexer.h index 2e27ffa..3ce15f4 100644 --- a/lexer.h +++ b/lexer.h @@ -19,6 +19,7 @@ enum TOKEN_TYPE { struct location { size_t line; size_t column; + size_t leading_whitespace_len; }; struct token { diff --git a/parser.c b/parser.c index 618df1a..f16af6c 100644 --- a/parser.c +++ b/parser.c @@ -14,9 +14,16 @@ static FILE* fd; static struct token *cursor; static const char *filename; -#define emit(...) fprintf(stderr, "%s at (%zd,%zd): ", filename, cursor->loc.line, cursor->loc.column);\ - fprintf(stderr, __VA_ARGS__);\ - indicate_file_area(fd, cursor->loc.line, cursor->loc.column, cursor->span) +/* FIXME change to varadic fuction */ +#define emit(...) \ + if (cursor) { \ + fprintf(stderr, "%s at (%zd,%zd): ", filename, cursor->loc.line, cursor->loc.column); \ + fprintf(stderr, __VA_ARGS__); \ + indicate_file_area(fd, cursor->loc.line, cursor->loc.column - cursor->loc.leading_whitespace_len, cursor->span); \ + } else { \ + fprintf(stderr, "%s: ", filename); \ + fprintf(stderr, __VA_ARGS__); \ + } //static struct op_lookup uop_handlers[] = { @@ -42,9 +49,13 @@ expect(enum TOKEN_TYPE e) { char *expected_desc = "(internal error)"; char *observed_desc = "(internal error)"; - if (cursor->type != e) { + if (!cursor || cursor->type != e) { expected_desc = get_token_description(e); - observed_desc = get_token_description(cursor->type); + if (cursor) { + observed_desc = get_token_description(cursor->type); + } else { + observed_desc = "end of file"; + } emit("Error: Expected %s, got %s\n", expected_desc, observed_desc); return 1; } @@ -54,7 +65,9 @@ expect(enum TOKEN_TYPE e) { static void kerchunk() { - cursor = cursor->next; + if (cursor) { + cursor = cursor->next; + } } int @@ -64,6 +77,11 @@ parse(const char *fname, FILE *f, struct token *t) { filename = fname; cursor = t; + /* Eat leading EOL tokens */ + while (cursor && cursor->type == TOK_EOL) { + kerchunk(); + } + if (expect(TOK_MODULE)) { return 1; } -- cgit v1.1