scc

simple C compiler
git clone git://git.2f30.org/scc
Log | Files | Refs | README | LICENSE

commit e9ccea1272ee0193a50d7288fdddd55ed45ad53e
parent 06276ba4738710b02df4c81803655ea777ed52c9
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sun, 24 May 2015 13:05:43 +0200

Factorize the code in the preprocessor

This version is shorter and is clearer in a lot of places.

Diffstat:
Mcc1/cpp.c | 183+++++++++++++++++++++++++++++++++++++------------------------------------------
1 file changed, 85 insertions(+), 98 deletions(-)

diff --git a/cc1/cpp.c b/cc1/cpp.c @@ -1,6 +1,7 @@ #include <ctype.h> #include <inttypes.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -15,6 +16,48 @@ static char *argp; static unsigned arglen; static unsigned numif, iffalse; static Symbol *lastmacro; + +static bool +iden(char **str) +{ + char c, *bp, *s = *str; + + for (bp = yytext; bp < &yytext[IDENTSIZ]; *bp++ = c) { + if ((c = *s) == '\0' || !isalnum(c) && c != '_') + break; + ++s; + } + if (bp == &yytext[IDENTSIZ]) + error("identifier too long"); + if (bp - yytext == 0) + return 0; + *bp = '\0'; + + while (isspace(*s)) + ++s; + + *str = s; + return 1; +} + +static bool +string(char **input, char **str, char delim) +{ + char c, *s = *input; + + if (str) + *str = s; + + while ((c = *s) && c != delim) + ++s; + if (c == '\0') + return 0; + *s++ = '\0'; + *input = s; + + return 1; +} + static void cleanup(char *s) { @@ -276,17 +319,11 @@ static bool define(char *s) { char *t; - size_t len; Symbol *sym; - if (!isalnum(*s) && *s != '_') - goto bad_define; - for (t = s; isalnum(*t) || *t == '_'; ++t) - /* nothing */; - if ((len = t - s) > IDENTSIZ) - goto too_long; - strncpy(yytext, s, len); - yytext[len] = '\0'; + if (!iden(&s)) + error("macro names must be identifiers"); + sym = lookup(NS_CPP); if ((sym->flags & ISDEFINED) && sym->ns == NS_CPP) { warn("'%s' redefined", yytext); @@ -295,25 +332,16 @@ define(char *s) sym->flags |= ISDEFINED; sym->ns = NS_CPP; - for (s = t; isspace(*s); ++s) + for (t = s + strlen(s) + 1; isspace(*--t); *t = '\0') /* nothing */; - for (t = s + strlen(s); isspace(*--t); *t = '\0') - /* nothing */; - s = mkdefine(s, sym); - cleanup(s); + mkdefine(s, sym); return 1; - -too_long: - error("macro identifier too long"); -bad_define: - error("macro names must be identifiers"); } static bool include(char *s) { - char fname[FILENAME_MAX], delim, c, *p; - size_t len; + char delim, c, *p, *file; if ((c = *s++) == '>') delim = '>'; @@ -322,30 +350,15 @@ include(char *s) else goto bad_include; - for (p = s; (c = *p) && c != delim; ++p) - /* nothing */; - if (c == '\0') + if (!string(&s, &file, delim)) goto bad_include; - - len = p - s; - if (delim == '"') { - if (len >= FILENAME_MAX) - goto too_long; - strncpy(fname, s, len); - fname[len] = '\0'; - if (!addinput(fname)) - goto not_found; - } else { - abort(); - } - - cleanup(p+1); - return 1; + cleanup(s); + if (delim == '"' && addinput(file)) + return 1; + abort(); not_found: - error("included file '%s' not found", fname); -too_long: - error("file name in include too long"); + error("included file '%s' not found", s); bad_include: error("#include expects \"FILENAME\" or <FILENAME>"); } @@ -353,46 +366,36 @@ bad_include: static bool line(char *s) { - char *p, *q; + char *file; + long n; - if (!isdigit(*s)) - goto bad_line; - for (p = s; isdigit(*p); ++p) - /* nothing */; - switch (*p) { + if ((n = strtol(s, &s, 10)) <= 0 || n > USHRT_MAX) + error("first parameter of #line is not a positive integer"); + + switch (*s) { case ' ': case '\t': - while (isspace(*p)) - ++p; - if (*p != '"') - goto bad_line; - for (q = p+1; *q && *q != '"'; ++q) - /* nothing */; - if (*q == '\0') - goto bad_line; - *q = '\0'; - setfname(p); - p = q+1; - /* passthrough */ + while (isspace(*s)) + ++s; + if (*s == '\0') + goto end_string; + if (*s++ != '"' && !string(&s, &file, '"')) + goto bad_file; + setfname(file); + cleanup(s); case '\0': - /* TODO: check this atoi */ - setfline(atoi(s)-1); - cleanup(p); + end_string: + setfline(n-1); return 1; default: - goto bad_file; + bad_file: + error("second parameter of #line is not a valid filename"); } - -bad_file: - error("second parameter of #line is not a valid filename"); -bad_line: - error("first parameter of #line is not a positive integer"); } static bool pragma(char *s) { - cleanup(s); return 1; } @@ -405,21 +408,15 @@ usererr(char *s) static bool ifclause(char *s, int isdef) { - unsigned curif, len; + unsigned curif; char *endp; Symbol *sym; - while (isspace(*s)) - ++s; - for (endp = s; isalnum(*endp) || *endp == '_'; ++endp) - /* nothing */; - if ((len = endp - s) > IDENTSIZ) + if (iden(&s)) error("..."); - memcpy(yytext, s, len); - yytext[len] = '\0'; - cleanup(endp); - ++numif; + cleanup(s); + ++numif; if (iffalse == 0) { sym = lookup(NS_CPP); if ((sym->flags & ISDEFINED) != 0 == isdef) @@ -479,10 +476,8 @@ elseclause(char *s) } bool -preprocessor(char *p) +preprocessor(char *s) { - char *q; - unsigned short n; static struct { char *name; bool (*fun)(char *); @@ -499,25 +494,17 @@ preprocessor(char *p) NULL, NULL }; - while (isspace(*p)) - ++p; - if (*p != '#') + if (*s++ != '#') return 0; - for (++p; isspace(*p); ++p) - /* nothing */; - if (*p == '\0') - return 1; - for (q = p; isalpha(*q); ++q) - /* nothing */; - if ((n = q - p) == 0) + while (isspace(*s)) + ++s; + if (!iden(&s)) goto incorrect; - while (isspace(*q)) - ++q; for (bp = cmds; bp->name; ++bp) { - if (strncmp(bp->name, p, n)) + if (strcmp(bp->name, yytext)) continue; - return (*bp->fun)(q); + return (*bp->fun)(s); } incorrect: - error("incorrect preprocessor directive"); + error("invalid preprocessor directive #%s", yytext); }