shithub: scc

Download patch

ref: d08a9f8c391f91f7413eb8b66cd6d6391fac5a31
parent: 5802f79d5895bf827622249d04a2599b9d0c6049
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Wed May 27 15:16:55 EDT 2015

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.

--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -246,7 +246,7 @@
 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 @@
 /* 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
--- 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 @@
 			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 @@
 	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 @@
 {
 	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 @@
 static void
 parameter(void)
 {
-	for (;;) {
+	while (!paramerr) {
 		nextcpp();
 		switch (yytoken) {
 		case ')':
@@ -153,7 +161,7 @@
 	}
 }
 
-static bool
+static int
 parsepars(char *buffer, char **listp, int nargs)
 {
 	int n;
@@ -165,7 +173,7 @@
 		return 0;
 	next();
 
-	n = 0;
+	paramerr = n = 0;
 	argp = buffer;
 	arglen = INPUTSIZ;
 	if (ahead() != ')') {
@@ -172,14 +180,19 @@
 		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 @@
  * 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 @@
 	}
 
 	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 @@
 	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 @@
 	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 @@
 		*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)
-		error("too much parameters in macro");
+	if (n > NR_MACROARG) {
+		printerr("too much parameters in macro");
+		return NULL;
+	}
 
 set_nargs:
 	*nargs = n;
@@ -306,7 +329,7 @@
  * 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 @@
 	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 @@
 	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 @@
 
 	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 @@
 
 	if (!string(&s, &file, delim))
 		goto bad_include;
-	cleanup(s);
 	if (delim == '"' && addinput(file, NULL, NULL))
 		return;
 
@@ -432,12 +462,15 @@
 		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 @@
 
 	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 @@
 		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 @@
 {
 	if (cppoff)
 		return;
-	error("#error %s", s);
+	printerr("#error %s", s);
 }
 
 static void
@@ -493,18 +529,19 @@
 	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 @@
 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 @@
 {
 	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 @@
 {
 	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 @@
 		return 1;
 	}
 incorrect:
-	error("invalid preprocessor directive #%s", yytext);
+	printerr("invalid preprocessor directive #%s", yytext);
+	return 1;
 }
--- a/cc1/error.c
+++ b/cc1/error.c
@@ -15,8 +15,10 @@
 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 @@
 	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
--- a/cc1/lex.c
+++ b/cc1/lex.c
@@ -606,9 +606,9 @@
 {
 	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();
 	}