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:
M | cc1/cc1.h | | | 5 | ++++- |
M | cc1/cpp.c | | | 132 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | cc1/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;
}