scc

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

commit c30fd72ab5feaa2e1326dbed4feb7ffc581d937e
parent 67d7bcb3689d2a33d7e2c0cdda9332f74750d8cd
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Mon, 25 May 2015 16:39:57 +0200

Avoid nested expansion of macros

Nested expansion of macros are inhibited to avoid infinite recursion.

Diffstat:
Mcc1/cc1.h | 2+-
Mcc1/cpp.c | 13++++++-------
Mcc1/lex.c | 31+++++++++++++++++++++++++++----
Mcc1/main.c | 2+-
Mcc1/stmt.c | 2+-
Mcc1/symbol.c | 9++++++++-
6 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/cc1/cc1.h b/cc1/cc1.h @@ -273,7 +273,7 @@ extern char *getfname(void); extern unsigned short getfline(void); extern void setfname(char *name); extern void setfline(unsigned short line); -extern char *addinput(char *fname); +extern char *addinput(char *fname, Symbol *sym); extern void setnamespace(int ns); extern void setsafe(int type); #define accept(t) ((yytoken == (t)) ? next() : 0) diff --git a/cc1/cpp.c b/cc1/cpp.c @@ -170,7 +170,7 @@ expand(Symbol *sym) if (!parsepars(buffer, arglist, atoi(s))) return 0; - bp = addinput(NULL); + bp = addinput(NULL, sym); len = INPUTSIZ-1; for (s += 3; c = *s; ++s) { if (c != '@') { @@ -291,7 +291,7 @@ too_long: } static char * -mkdefine(char *s, Symbol *sym) +mkdefine(char *s) { int nargs; char *args[NR_MACROARG], buff[LINESIZ+1]; @@ -304,9 +304,7 @@ mkdefine(char *s, Symbol *sym) if (*s != '\0') s = copydefine(s, args, buff+3, LINESIZ-3, nargs); - sym->u.s = xstrdup(buff); - - return s; + return xstrdup(buff); } static void @@ -327,10 +325,11 @@ define(char *s) } sym->flags |= ISDEFINED; sym->ns = NS_CPP; + sym->ctx = UCHAR_MAX; for (t = s + strlen(s) + 1; isspace(*--t); *t = '\0') /* nothing */; - mkdefine(s, sym); + sym->u.s = mkdefine(s); return; } @@ -351,7 +350,7 @@ include(char *s) if (!string(&s, &file, delim)) goto bad_include; cleanup(s); - if (delim == '"' && addinput(file)) + if (delim == '"' && addinput(file, NULL)) return; abort(); diff --git a/cc1/lex.c b/cc1/lex.c @@ -19,6 +19,7 @@ struct input { unsigned short nline; FILE *fp; char *line, *begin, *p; + Symbol *macro; struct input *next; }; @@ -33,7 +34,7 @@ static int safe, eof, incomment; static Input *input; char * -addinput(char *fname) +addinput(char *fname, Symbol *sym) { Input *ip; FILE *fp; @@ -58,6 +59,7 @@ addinput(char *fname) ip = xmalloc(sizeof(Input)); ip->fname = fname; ip->next = input; + ip->macro = sym; ip->begin = ip->p = ip->line = xmalloc(INPUTSIZ); *ip->begin = '\0'; ip->nline = nline; @@ -389,15 +391,36 @@ repeat: static unsigned iden(void) { - char *p; + char *p, *t, c; for (p = input->p; isalnum(*p) || *p == '_'; ++p) /* nothing */; input->p = p; tok2str(); yylval.sym = lookup(lex_ns); - if (yylval.sym->ns == NS_CPP && expand(yylval.sym)) - return 0; + if (yylval.sym->ns == NS_CPP) { + Symbol *sym; + + if (yylval.sym != input->macro && expand(yylval.sym)) + return 0; + /* + * it is not a correct macro call, so try to find + * another definition. This is going to be expensive + * but I think it is not going to be a common case. + */ + p = yylval.sym->name; + c = *p; + for (sym = yylval.sym->hash; sym; sym = sym->hash) { + t = sym->name; + if (c == *t && !strcmp(p, t)) { + yylval.sym = sym; + goto found_iden; + } + } + yylval.sym = install(lex_ns); + yylval.sym->flags &= ~ISDEFINED; + } +found_iden: if (yylval.sym->token != IDEN) yylval.token = yylval.sym->u.token; return yylval.sym->token; diff --git a/cc1/main.c b/cc1/main.c @@ -67,7 +67,7 @@ main(int argc, char *argv[]) ikeywords(); - if (!addinput(*argv)) + if (!addinput(*argv, NULL)) die("error opening input file '%s'", *argv); for (next(); yytoken != EOFTOK; extdecl()) /* nothing */; diff --git a/cc1/stmt.c b/cc1/stmt.c @@ -164,7 +164,7 @@ Label(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) case TYPEIDEN: /* * We cannot call to insert() because the call to lookup in - * lex.c was done in NS_IDEN namespace, and it is impossibe + * lex.c was done in NS_IDEN namespace, and it is impossibe * to fix this point, because an identifier at the beginning * of a statement may be part of an expression or part of a * label. This double call to lookup() is going to generate diff --git a/cc1/symbol.c b/cc1/symbol.c @@ -129,9 +129,16 @@ install(unsigned ns) return yylval.sym; } - h = &htab[hash(yytext)]; sym = newsym(ns); sym->name = xstrdup(yytext); + + if (yylval.sym->ns == NS_CPP) { + sym->hash = yylval.sym->hash; + yylval.sym->hash = sym; + return sym; + } + + h = &htab[hash(yytext)]; sym->hash = *h; *h = sym; return sym;