commit c24c773d732b95df1f5d612d5ec54f265506d7e0
parent 9cd10aa29ae615f703ec0c91275cd9c413e38c01
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Wed, 27 May 2015 15:23:42 +0200
Add string builder to the preprocessor
The string builder creates a string from one parameter
of the macro.
Diffstat:
M | cc1/cpp.c | | | 43 | +++++++++++++++++++++++++++++++------------ |
1 file changed, 31 insertions(+), 12 deletions(-)
diff --git a/cc1/cpp.c b/cc1/cpp.c
@@ -143,7 +143,7 @@ parameter(void)
switch (yytoken) {
case ')':
case ',':
- argp -= 2;
+ argp -= 3;
*argp++ = '\0';
return;
case '(':
@@ -197,8 +197,8 @@ bool
expand(Symbol *sym)
{
unsigned len;
- char *arglist[NR_MACROARG], buffer[BUFSIZE];
- char c, *bp, *arg, *s = sym->u.s;
+ char *arglist[NR_MACROARG], arguments[INPUTSIZ], buffer[BUFSIZE];
+ char prevc, c, *bp, *lim, *arg, *s = sym->u.s;
if (sym == symfile) {
sprintf(buffer, "\"%s\"", getfname());
@@ -210,25 +210,33 @@ expand(Symbol *sym)
}
macroname = sym->name;
- if (!parsepars(buffer, arglist, atoi(s)))
+ if (!parsepars(arguments, arglist, atoi(s)))
return 0;
- bp = buffer;
len = INPUTSIZ-1;
- for (s += 3; c = *s; ++s) {
+ bp = buffer;
+ for (prevc = '\0', s += 3; c = *s; prevc = c, ++s) {
if (c != '@') {
+ if (c == '#')
+ continue;
if (len-- == 0)
goto expansion_too_long;
*bp++ = c;
} else {
unsigned size;
+ if (prevc == '#')
+ len -= 2;
arg = arglist[atoi(++s)];
size = strlen(arg);
if (size > len)
goto expansion_too_long;
+ if (prevc == '#')
+ *bp++ = '"';
memcpy(bp, arg, size);
bp += size;
+ if (prevc == '#')
+ *bp++ = '"';
len -= size;
s += 2;
}
@@ -292,6 +300,7 @@ set_nargs:
*nargs = n;
return s;
}
+
/*
* Copy a string define, and substitute formal arguments of the
* macro into strings in the form @XX@, where XX is the position
@@ -302,18 +311,24 @@ copydefine(char *s, char *args[], char *buff, int bufsiz, int nargs)
{
int n;
size_t ncopy;
- char arroba[6], *p, **bp, c;
+ char arroba[6], *p, **bp, c, prevc;
- while ((c = *s) && bufsiz > 0) {
+ for (prevc = '\0'; c = *s++; prevc = c) {
if (!isalpha(c) && c != '_' || nargs < 1) {
+ if (bufsiz-- == 0)
+ goto too_long;
+ if (prevc == '#')
+ goto bad_stringer;
*buff++ = c;
- ++s, --bufsiz;
- continue;
+ if (c != '#')
+ continue;
+ while (isspace(*++s))
+ /* nothing */;
}
/* found an identifier, is it one of the macro arguments? */
- for (p = s+1; isalnum(c = *p) || c == '_'; ++p)
+ for (p = s; isalnum(c = *p) || c == '_'; ++p)
/* nothing */;
- ncopy = p - s;
+ ncopy = p - --s;
bp = args;
for (n = 0; n < nargs; ++n) {
if (strncmp(s, *bp++, ncopy))
@@ -322,6 +337,8 @@ copydefine(char *s, char *args[], char *buff, int bufsiz, int nargs)
s = arroba, ncopy = 4;
break;
}
+ if (n == nargs && prevc == '#')
+ goto bad_stringer;
if ((bufsiz -= ncopy) < 0)
goto too_long;
memcpy(buff, s, ncopy);
@@ -332,6 +349,8 @@ copydefine(char *s, char *args[], char *buff, int bufsiz, int nargs)
*buff = '\0';
return s;
+bad_stringer:
+ error("'#' is not followed by a macro parameter");
too_long:
error("macro definition too long");
}