diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2021-02-01 21:51:25 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2021-02-01 21:51:25 +0200 |
commit | edf38541a5d038bea74052cb169c9017ed7a2e8a (patch) | |
tree | 3738e25a4e8b8cf6cd892b5efb7fd139a93e759d | |
parent | 4c7dfbc3e0296f36c5692ae87c6699f36c641fc8 (diff) | |
download | xenv-edf38541a5d038bea74052cb169c9017ed7a2e8a.tar.gz xenv-edf38541a5d038bea74052cb169c9017ed7a2e8a.tar.bz2 |
Parse input #line directives.
-rw-r--r-- | xenv.l | 76 |
1 files changed, 70 insertions, 6 deletions
@@ -19,11 +19,13 @@ #include <unistd.h> #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <sysexits.h> #include <assert.h> char const *progname; /* Program name */ -char const *filename; /* Name of the input file. */ +char *filename; /* Name of the input file. */ +size_t filename_size; /* Size of memory allocated for filename. */ unsigned lineno; /* Line number in the input file. */ int undef_error_option; /* Treat undefined variables as error. */ int synclines_option; /* Generate `#line NUM "FILE"' lines. */ @@ -52,6 +54,8 @@ static void expand_inline_flop(void); static int cond_peek(void); static void cond_push(int result); static int cond_pop(void); + +static int parse_line_directive(char *text); /* * Given a '$$' preprocessor statement TEXT, find the variable identifier @@ -101,6 +105,26 @@ xstrdup(char *str) enomem(); return p; } + +char * +xrealloc(char *ptr, size_t size) +{ + char *p = realloc(ptr, size); + if (!p) + enomem(); + return p; +} + +static void +set_filename(char const *name, size_t len) +{ + if (len + 1 > filename_size) { + filename_size = len + 1; + filename = xrealloc(filename, filename_size); + } + memcpy(filename, name, len); + filename[len] = 0; +} %} IDENT [a-zA-Z_][a-zA-Z_0-9]* WS [ \t][ \t]* @@ -133,7 +157,13 @@ OWS [ \t]* <SQ>"'" { BEGIN(save_state); ECHO; } "'" { save_state = YYSTATE; BEGIN(SQ); ECHO; } - + +<INITIAL>^"#line ".*\n { + if (parse_line_directive(yytext)) { + ECHO; + lineno++; + } + } <INITIAL>"${*" { save_state = YYSTATE; BEGIN(COMMENT); } <COMMENT>[^*\n]* /* eat anything that's not a '*' */ <COMMENT>"*"+[^*}\n]* /* eat up '*'s not followed by '}'s */ @@ -349,7 +379,7 @@ struct expand_inline { char *varname; /* type == EXP_ASSIGN - assign the expansion to that variable */ struct { /* type == EXP_ERROR - location of the error */ - char const *filename; + char *filename; unsigned lineno; } loc; }; @@ -382,7 +412,7 @@ expand_inline_push(int type, char *varname, int varlen, int suppress) memcpy(ep->varname, varname, varlen); ep->varname[varlen] = 0; } else if (type == EXP_ERROR) { - ep->loc.filename = filename; + ep->loc.filename = xstrdup(filename); ep->loc.lineno = lineno; } ep->fp = yyout; @@ -467,6 +497,7 @@ expand_inline_pop(void) fprintf(stderr, "%s:%u: ", ep->loc.filename, ep->loc.lineno); + free(ep->loc.filename); rewind(yyout); while ((c = fgetc(yyout)) != EOF) fputc(c, stderr); @@ -481,7 +512,10 @@ expand_inline_pop(void) emit_syncline = 1; } } - } + } else + /* FIXME: Emit syncline only if there were newlines in the + suppressed text. */ + emit_syncline = 1; if (ep->type == EXP_ASSIGN) free(ep->varname); @@ -549,6 +583,36 @@ cond_pop(void) return cond_stack[cond_tos--].result; } +static int +parse_line_directive(char *text) +{ + unsigned long n; + char *fname, *p; + + text += sizeof("#line ")-1; + + n = strtoul(text, &p, 10); + if ((n == 0 && errno == ERANGE) || n > INT_MAX || + !(*p == 0 || *p == ' ' || *p == '\t' || *p == '\n')) + return 1; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '\n' || *p == 0) { + lineno = (int) n; + return 0; + } + if (*p != '"') + return 1; + p++; + fname = p; + p = strchr(fname, '"'); + if (!p) + return 1; + set_filename(fname, p - fname); + lineno = n; + return 0; +} + /* * Input file handling. */ @@ -568,7 +632,7 @@ open_input(char const *name) exit(errno == ENOENT ? EX_NOINPUT : EX_OSERR); } yyin = fp; - filename = name; + set_filename(name, strlen(name)); lineno = 1; if (synclines_option) fprintf(yyout, "#line %u \"%s\"\n", lineno, filename); |