scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

commit d08a9f8c391f91f7413eb8b66cd6d6391fac5a31
parent 5802f79d5895bf827622249d04a2599b9d0c6049
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Wed, 27 May 2015 19:16:55 +0200

Improve error handling in cpp.c

cpp errors must not recover, because they only affect to the
current line, and they can create problems with the code seen
by the compiler, so the best option is to return to a return
value errors.

Diffstat:
Mcc1/cc1.h | 4++--
Mcc1/cpp.c | 170++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mcc1/error.c | 8++++----
Mcc1/lex.c | 4++--
4 files changed, 115 insertions(+), 71 deletions(-)

diff --git a/cc1/cc1.h b/cc1/cc1.h @@ -246,7 +246,7 @@ enum { extern void error(char *fmt, ...); extern void warn(char *fmt, ...); extern void unexpected(void); -extern void softerror(char *fmt, ...); +extern void printerr(char *fmt, ...); /* types.c */ extern bool eqtype(Type *tp1, Type *tp2); @@ -299,7 +299,7 @@ extern Node *expr(void), *negate(Node *np); /* cpp.c */ extern void icpp(void); extern bool cpp(char *s); -extern bool expand(Symbol *sym); +extern int expand(Symbol *sym); /* * Definition of global variables diff --git a/cc1/cpp.c b/cc1/cpp.c @@ -11,12 +11,11 @@ #include "../inc/cc.h" #include "cc1.h" -/* TODO: preprocessor error must not rise recover */ - static char *argp, *macroname; static unsigned arglen; static Symbol *symline, *symfile; static unsigned char ifstatus[NR_COND]; +static int paramerr; unsigned cppctx; @@ -64,8 +63,10 @@ iden(char **str) break; ++s; } - if (bp == &yytext[IDENTSIZ]) - error("identifier too long in preprocessor"); + if (bp == &yytext[IDENTSIZ]) { + printerr("identifier too long in preprocessor"); + return 0; + } *bp = '\0'; while (isspace(*s)) @@ -99,7 +100,7 @@ cleanup(char *s) while (isspace(*s)) ++s; if (*s != '\0') - error("trailing characters after preprocessor directive"); + printerr("trailing characters after preprocessor directive"); } static void @@ -107,23 +108,30 @@ nextcpp(void) { next(); if (yytoken == EOFTOK) { - error("unterminated argument list invoking macro \"%s\"", + printerr("unterminated argument list invoking macro \"%s\"", macroname); + goto mark_error; } if (yylen + 1 > arglen) { - error("argument overflow invoking macro \"%s\"", + printerr("argument overflow invoking macro \"%s\"", macroname); + goto mark_error; } memcpy(argp, yytext, yylen); argp += yylen; *argp++ = ' '; arglen -= yylen + 1; + return; + +mark_error: + paramerr = 1; + yytoken = 0; } static void paren(void) { - for (;;) { + while (!paramerr) { nextcpp(); switch (yytoken) { case ')': @@ -138,7 +146,7 @@ paren(void) static void parameter(void) { - for (;;) { + while (!paramerr) { nextcpp(); switch (yytoken) { case ')': @@ -153,7 +161,7 @@ parameter(void) } } -static bool +static int parsepars(char *buffer, char **listp, int nargs) { int n; @@ -165,21 +173,26 @@ parsepars(char *buffer, char **listp, int nargs) return 0; next(); - n = 0; + paramerr = n = 0; argp = buffer; arglen = INPUTSIZ; if (ahead() != ')') { do { *listp++ = argp; parameter(); - } while (++n < NR_MACROARG && yytoken == ','); + } while (!paramerr && ++n < NR_MACROARG && yytoken == ','); } - if (n == NR_MACROARG) - error("too much parameters in macro \"%s\"", macroname); + if (paramerr) + return -1; + if (n == NR_MACROARG) { + printerr("too much parameters in macro \"%s\"", macroname); + return -1; + } if (n != nargs) { - error("macro \"%s\" passed %d arguments, but it takes %d", + printerr("macro \"%s\" passed %d arguments, but it takes %d", macroname, n, nargs); + return -1; } return 1; } @@ -193,10 +206,11 @@ parsepars(char *buffer, char **listp, int nargs) * parameter number dd */ #define BUFSIZE ((INPUTSIZ > FILENAME_MAX+2) ? INPUTSIZ : FILENAME_MAX+2) -bool +int expand(Symbol *sym) { unsigned len; + int r; char *arglist[NR_MACROARG], arguments[INPUTSIZ], buffer[BUFSIZE]; char prevc, c, *bp, *lim, *arg, *s = sym->u.s; @@ -210,8 +224,8 @@ expand(Symbol *sym) } macroname = sym->name; - if (!parsepars(arguments, arglist, atoi(s))) - return 0; + if ((r = parsepars(arguments, arglist, atoi(s))) < 1) + return r; len = INPUTSIZ-1; bp = buffer; @@ -247,7 +261,8 @@ add_macro: return 1; expansion_too_long: - error("expansion of macro \"%s\" is too long", macroname); + printerr("expansion of macro \"%s\" is too long", macroname); + return -1; } #undef BUFSIZE @@ -275,12 +290,16 @@ parseargs(char *s, char *args[NR_MACROARG], int *nargs) for (n = 1; n <= NR_MACROARG; ++n) { while (isspace(*s)) ++s; - if (!isalpha(*s) && *s != '_') - error("macro arguments must be identifiers"); + if (!isalpha(*s) && *s != '_') { + printerr("macro arguments must be identifiers"); + return NULL; + } for (endp = s+1; isalnum(*endp) || *endp == '_'; ++endp) /* nothing */; - if ((len = endp - s) > IDENTSIZ) - error("macro argument too long"); + if ((len = endp - s) > IDENTSIZ) { + printerr("macro argument too long"); + return NULL; + } *args++ = s; for (s = endp; isspace(*s); ++s) *s = '\0'; @@ -288,13 +307,17 @@ parseargs(char *s, char *args[NR_MACROARG], int *nargs) *s++ = '\0'; if (c == ')') break; - if (c == ',') + if (c == ',') { continue; - else - error("macro parameters must be comma-separated"); + } else { + printerr("macro parameters must be comma-separated"); + return NULL; + } + } + if (n > NR_MACROARG) { + printerr("too much parameters in macro"); + return NULL; } - if (n > NR_MACROARG) - error("too much parameters in macro"); set_nargs: *nargs = n; @@ -306,7 +329,7 @@ set_nargs: * macro into strings in the form @XX@, where XX is the position * of the argument in the argument list. */ -static char * +static bool copydefine(char *s, char *args[], char *buff, int bufsiz, int nargs) { int n; @@ -347,12 +370,14 @@ copydefine(char *s, char *args[], char *buff, int bufsiz, int nargs) if (bufsiz == 0) goto too_long; *buff = '\0'; - return s; + return 1; bad_stringer: - error("'#' is not followed by a macro parameter"); + printerr("'#' is not followed by a macro parameter"); + return 0; too_long: - error("macro definition too long"); + printerr("macro definition too long"); + return 0; } static char * @@ -361,14 +386,17 @@ mkdefine(char *s) int nargs; char *args[NR_MACROARG], buff[LINESIZ+1]; - s = parseargs(s, args, &nargs); + if ((s = parseargs(s, args, &nargs)) == NULL) + return NULL; sprintf(buff, "%02d#", nargs); while (isspace(*s)) ++s; - if (*s != '\0') - s = copydefine(s, args, buff+3, LINESIZ-3, nargs); + if (*s == '\0') + buff[0] = '\0'; + else if (!copydefine(s, args, buff+3, LINESIZ-3, nargs)) + return NULL; return xstrdup(buff); } @@ -380,12 +408,15 @@ define(char *s) if (cppoff) return; - if (!iden(&s)) - error("#define must have an identifier as parameter"); + if (!iden(&s)) { + printerr("#define must have an identifier as parameter"); + return; + } for (t = s + strlen(s) + 1; isspace(*--t); *t = '\0') /* nothing */; - s = mkdefine(s); + if ((s = mkdefine(s)) == NULL) + return; sym = lookup(NS_CPP); if ((sym->flags & ISDEFINED) && sym->ns == NS_CPP) { @@ -420,7 +451,6 @@ include(char *s) if (!string(&s, &file, delim)) goto bad_include; - cleanup(s); if (delim == '"' && addinput(file, NULL, NULL)) return; @@ -432,12 +462,15 @@ include(char *s) memcpy(path, *bp, dirlen); memcpy(path+dirlen, file, filelen); if (addinput(path, NULL, NULL)) - return; + break; } - error("included file '%s' not found", file); + if (*bp) + printerr("included file '%s' not found", file); + cleanup(s); + return; bad_include: - error("#include expects \"FILENAME\" or <FILENAME>"); + printerr("#include expects \"FILENAME\" or <FILENAME>"); } static void @@ -448,8 +481,10 @@ line(char *s) if (cppoff) return; - if ((n = strtol(s, &s, 10)) <= 0 || n > USHRT_MAX) - error("first parameter of #line is not a positive integer"); + if ((n = strtol(s, &s, 10)) <= 0 || n > USHRT_MAX) { + printerr("first parameter of #line is not a positive integer"); + return; + } switch (*s) { case ' ': @@ -461,15 +496,16 @@ line(char *s) if (*s++ != '"' && !string(&s, &file, '"')) goto bad_file; setfname(file); - cleanup(s); case '\0': end_string: setfline(n-1); - return; + break;; default: bad_file: - error("second parameter of #line is not a valid filename"); + printerr("second parameter of #line is not a valid filename"); + break; } + cleanup(s); } static void @@ -484,7 +520,7 @@ usererr(char *s) { if (cppoff) return; - error("#error %s", s); + printerr("#error %s", s); } static void @@ -493,18 +529,19 @@ ifclause(char *s, int isdef) Symbol *sym; unsigned n = cppctx++; - if (cppctx == NR_COND-1) - error("too much nesting levels of conditional inclusion"); - + if (cppctx == NR_COND-1) { + printerr("too much nesting levels of conditional inclusion"); + return; + } if (!iden(&s)) { - error("no macro name given in #%s directive", + printerr("no macro name given in #%s directive", (isdef) ? "ifdef" : "ifndef"); + return; } - cleanup(s); - sym = lookup(NS_CPP); if (!(ifstatus[n] = (sym->flags & ISDEFINED) != 0 == isdef)) ++cppoff; + cleanup(s); } static void @@ -522,11 +559,13 @@ ifndef(char *s) static void endif(char *s) { - if (cppctx == 0) - error("#endif without #if"); - cleanup(s); + if (cppctx == 0) { + printerr("#endif without #if"); + return; + } if (!ifstatus[--cppctx]) --cppoff; + cleanup(s); } static void @@ -534,10 +573,12 @@ elseclause(char *s) { struct ifstatus *ip; - if (cppctx == 0) - error("#else without #ifdef/ifndef"); - cleanup(s); + if (cppctx == 0) { + printerr("#else without #ifdef/ifndef"); + return; + } cppoff += (ifstatus[cppctx-1] ^= 1) ? -1 : 1; + cleanup(s); } static void @@ -545,8 +586,10 @@ undef(char *s) { Symbol *sym; - if (!iden(&s)) - error("no macro name given in #undef directive"); + if (!iden(&s)) { + printerr("no macro name given in #undef directive"); + return; + } sym = lookup(NS_CPP); sym->flags &= ~ISDEFINED; cleanup(s); @@ -585,5 +628,6 @@ cpp(char *s) return 1; } incorrect: - error("invalid preprocessor directive #%s", yytext); + printerr("invalid preprocessor directive #%s", yytext); + return 1; } diff --git a/cc1/error.c b/cc1/error.c @@ -15,8 +15,10 @@ static unsigned nerrors; static void warn_helper(int flag, char *fmt, va_list va) { - if (!flag) + if (flag == 0) return; + if (flag < 0) + failure = 1; fprintf(stderr, "%s:%s:%u: ", (flag < 0) ? "error" : "warning", getfname(), getfline()); vfprintf(stderr, fmt, va); @@ -46,18 +48,16 @@ error(char *fmt, ...) va_start(va, fmt); warn_helper(-1, fmt, va); va_end(va); - failure = 1; discard(); } void -softerror(char *fmt, ...) +printerr(char *fmt, ...) { va_list va; va_start(va, fmt); warn_helper(-1, fmt, va); va_end(va); - failure = 1; } void diff --git a/cc1/lex.c b/cc1/lex.c @@ -606,9 +606,9 @@ expect(unsigned tok) { if (yytoken != tok) { if (isgraph(tok)) - softerror("expected '%c' before '%s'", tok, yytext); + printerr("expected '%c' before '%s'", tok, yytext); else - softerror("unexpected '%s'", yytext); + printerr("unexpected '%s'", yytext); } else { next(); }