scc

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

commit e87b3ab194e7cf293c90f555b96a9278c1698215
parent cd6d1548bbb6365822d9b690bb85b2b582778b2e
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date:   Sat, 23 May 2015 10:04:08 +0200

Add expansion of macros

Diffstat:
Mcc1/cc1.h | 5++++-
Mcc1/cpp.c | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcc1/lex.c | 14++++++++++----
3 files changed, 146 insertions(+), 5 deletions(-)

diff --git a/cc1/cc1.h b/cc1/cc1.h @@ -1,4 +1,5 @@ +#define INPUTSIZ 120 /* * Definition of structures @@ -271,7 +272,7 @@ extern char *getfname(void); extern unsigned short getfline(void); extern void setfname(char *name); extern void setfline(unsigned short line); -extern bool addinput(char *fname); +extern char *addinput(char *fname); extern void setnamespace(int ns); extern void setsafe(int type); #define accept(t) ((yytoken == (t)) ? next() : 0) @@ -289,6 +290,7 @@ extern Node *expr(void), *negate(Node *np); /* cpp.c */ extern char *preprocessor(char *s); +extern bool expand(Symbol *sym); /* * Definition of global variables @@ -296,6 +298,7 @@ extern char *preprocessor(char *s); extern struct yystype yylval; extern char yytext[]; extern unsigned yytoken; +extern unsigned short yylen; extern Type *voidtype, *pvoidtype, *booltype, *uchartype, *chartype, diff --git a/cc1/cpp.c b/cc1/cpp.c @@ -11,6 +11,138 @@ /* TODO: preprocessor error must not rise recover */ +static char *argp; +static unsigned arglen; +static Symbol *lastmacro; + +static void +nextcpp(void) +{ + next(); + if (yytoken == EOFTOK) { + error("unterminated argument list invoking macro \"%s\"", + lastmacro->name); + } + if (yylen + 1 > arglen) { + error("argument overflow invoking macro \"%s\"", + lastmacro->name); + } + memcpy(argp, yytext, yylen); + argp += yylen; + *argp++ = ' '; + arglen -= yylen + 1; +} + +static void +paren(void) +{ + for (;;) { + nextcpp(); + switch (yytoken) { + case ')': + return; + case '(': + paren(); + break; + } + } +} + +static void +parameter(void) +{ + for (;;) { + nextcpp(); + switch (yytoken) { + case ')': + case ',': + argp -= 2; + *argp++ = '\0'; + return; + case '(': + paren(); + break; + } + } +} + +static bool +parsepars(char *buffer, char **listp, int nargs) +{ + int n; + + if (nargs == -1) + return 1; + + if (ahead() != '(') + return 0; + next(); + + n = 0; + argp = buffer; + arglen = INPUTSIZ; + if (ahead() != ')') { + do { + *listp++ = argp; + parameter(); + } while (++n < NR_MACROARG && yytoken == ','); + } + + if (n == NR_MACROARG) + error("too much parameters in macro \"%s\"", lastmacro->name); + if (n != nargs) { + error("macro \"%s\" passed %d arguments, but it takes %d", + lastmacro->name, n, nargs); + } + return 1; +} + +/* + * sym->u.s is a string with the following format: + * dd#string + * where dd is the number of arguments of the macro + * (-1 if it is a macro without arguments), and string + * is the macro definition, where @dd@ indicates the + * parameter number dd + */ +bool +expand(Symbol *sym) +{ + unsigned len; + char *arglist[NR_MACROARG], buffer[INPUTSIZ]; + char c, *bp, *arg, *s = sym->u.s; + + lastmacro = sym; + if (!parsepars(buffer, arglist, atoi(s))) + return 0; + + bp = addinput(NULL); + len = INPUTSIZ-1; + for (s += 3; c = *s; ++s) { + if (c != '@') { + if (len-- == 0) + goto expansion_too_long; + *bp++ = c; + } else { + unsigned size; + + arg = arglist[atoi(++s)]; + size = strlen(arg); + if (size > len) + goto expansion_too_long; + memcpy(bp, arg, size); + bp += size; + len -= size; + s += 2; + } + } + *bp = '\0'; + return 1; + +expansion_too_long: + error("expansion of macro \"%s\" is too long", lastmacro->name); +} + /* * Parse an argument list (par0, par1, ...) and creates * an array with pointers to all the arguments in the diff --git a/cc1/lex.c b/cc1/lex.c @@ -11,7 +11,6 @@ #include "../inc/cc.h" #include "cc1.h" -#define INPUTSIZ 120 typedef struct input Input; @@ -32,7 +31,7 @@ static unsigned lex_ns = NS_IDEN; static int safe, eof, incomment; static Input *input; -bool +char * addinput(char *fname) { Input *ip; @@ -44,7 +43,7 @@ addinput(char *fname) if (fname) { if ((fp = fopen(fname, "r")) == NULL) - return 0; + return NULL; fname = xstrdup(fname); } else if (!input) { fp = stdin; @@ -63,7 +62,7 @@ addinput(char *fname) ip->nline = nline; ip->fp = fp; input = ip; - return 1; + return input->line; } static void @@ -386,6 +385,8 @@ iden(void) input->p = p; tok2str(); yylval.sym = lookup(lex_ns); + if (yylval.sym->ns == NS_CPP && expand(yylval.sym)) + return 0; if (yylval.sym->token != IDEN) yylval.token = yylval.sym->u.token; return yylval.sym->token; @@ -511,6 +512,7 @@ next(void) { char c; +repeat: skipspaces(); if (eof) { strcpy(yytext, "<EOF>"); @@ -528,6 +530,10 @@ next(void) yytoken = character(); else yytoken = operator(); + + if (!yytoken) + goto repeat; + lex_ns = NS_IDEN; return yytoken; }