From e1bd6c39c32d43693913f0c4b2cf232ddcbbb5f7 Mon Sep 17 00:00:00 2001 From: Manlio Perillo Date: Sun, 25 Dec 2022 18:42:27 +0100 Subject: [PATCH] parser: improve error reporting In main.c, define the macro YY_CTX_LOCAL in order to have access to the parsing context and the macro YY_INPUT in order to have access to the current line number. In order to make these macro visible to parser.c, include parser.c in main.c. Add the yyerror function for improved error report, showing the current line and additional context. Update the Makefile, removing the full.c file. --- grammar/Makefile | 7 ++----- grammar/main.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/grammar/Makefile b/grammar/Makefile index c2c7344..98655c7 100644 --- a/grammar/Makefile +++ b/grammar/Makefile @@ -10,11 +10,8 @@ build: build/parser.c: grammar.y | build peg $^ > $@ -build/full.c: main.c build/parser.c - cat $^ > $@ - -build/parser: build/full.c +build/parser: main.c | build/parser.c $(CC) -O3 -o $@ $^ -build/parser_debug: build/full.c +build/parser_debug: main.c $(CC) -O3 -o $@ $^ -DYY_DEBUG diff --git a/grammar/main.c b/grammar/main.c index d7f57a9..217abcd 100644 --- a/grammar/main.c +++ b/grammar/main.c @@ -1,10 +1,50 @@ #include -int yyparse(); +FILE* input = NULL; +static int lineno = 0; +static char* filename= NULL; + +#define YY_CTX_LOCAL + +#define YY_INPUT(ctx, buf, result, max) { \ + int c = getc(input); \ + if (c == '\n') ++lineno; \ + result = (EOF == c) ? 0 : (*(buf) = c, 1); \ +} + +#include "build/parser.c" + +void yyerror(yycontext* ctx, char* message) { + fprintf(stderr, "%s:%d: %s", filename, lineno, message); + + if (ctx->__pos < ctx->__limit || !feof(input)) { + // Find the offending line. + int pos = ctx->__limit; + while (ctx->__pos < pos) { + if (ctx->__buf[pos] == '\n') { + ++pos; + break; + } + + --pos; + } + + ctx->__buf[ctx->__limit] = '\0'; + fprintf(stderr, "%s", ctx->__buf + pos); + } + + fprintf(stderr, "\n"); +} int main() { - if (yyparse() == 0) { - fprintf(stderr, "Failed!\n"); + input = stdin; + lineno = 1; + filename = ""; + + yycontext ctx; + memset(&ctx, 0, sizeof(yycontext)); + if (yyparse(&ctx) == 0) { + yyerror(&ctx, "syntax error\n"); return 1; }