scc

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

commit 40a039807d5241750fe54d5feac09ffda31f5e4f
parent a02c7e4fc2ca724738b578f9e1540d463079aa5a
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date:   Tue, 31 Mar 2026 09:32:18 +0200

cc1: Implement variadic macros

The code was checking for them but it didn't implement the __VA_ARGS__
parameter, so in practice they couldn't be used.

Diffstat:
Msrc/cmd/scc-cc/cc1/cc1.h | 3++-
Msrc/cmd/scc-cc/cc1/cpp.c | 52+++++++++++++++++++++++++++++++++++-----------------
Atests/cc/execute/0258-variadic.c | 26++++++++++++++++++++++++++
Mtests/cc/execute/scc-tests.lst | 3++-
4 files changed, 65 insertions(+), 19 deletions(-)

diff --git a/src/cmd/scc-cc/cc1/cc1.h b/src/cmd/scc-cc/cc1/cc1.h @@ -112,7 +112,8 @@ enum { SSTRING = 1 << 12, STYPEDEF = 1 << 13, SINITLST = 1 << 14, - SHASINIT = 1 << 15 + SHASINIT = 1 << 15, + SVARIADIC = 1 << 15, }; /* node flags */ diff --git a/src/cmd/scc-cc/cc1/cpp.c b/src/cmd/scc-cc/cc1/cpp.c @@ -144,7 +144,7 @@ unterminated: } static char * -parameter(Macro *mp) +parameter(Macro *mp, int n) { int siz; char *s, *begin, *end; @@ -164,8 +164,10 @@ parameter(Macro *mp) appendpar(mp, input->p++, 1); paren(mp); break; - case ')': case ',': + if (n+1 == mp->npars) + goto append; + case ')': begin = mp->arg; end = begin + mp->argsiz; @@ -184,6 +186,7 @@ parameter(Macro *mp) goto unterminated; continue; default: + append: appendpar(mp, input->p++, 1); break; } @@ -214,10 +217,11 @@ parsepars(Macro *mp) } disexpand = 1; - for (n = 0; n < NR_MACROARG; ++n) { + for (n = 0; n < NR_MACROARG; ) { mp->arglist = xrealloc(mp->arglist, (n+1)*sizeof(char *)); - mp->arglist[n] = parameter(mp); + mp->arglist[n] = parameter(mp, n); DBG("MACRO fetched arg '%s'", mp->arglist[n]); + n++; c = *input->p++; if (c == ')') @@ -227,9 +231,16 @@ parsepars(Macro *mp) } disexpand = 0; -checknpars: - if (n+1 == mp->npars) + if (n == mp->npars) + return 1; + + if (n == mp->npars-1 && mp->sym->flags & SVARIADIC) { + DBG("MACRO defaulted __VA_ARGS__ to \"\""); + mp->arglist = xrealloc(mp->arglist, (n+1)*sizeof(char *)); + mp->arglist[n] = xstrdup(""); return 1; + } + error("macro \"%s\" received %d arguments, but it takes %d", mp->sym->name, n, mp->npars); } @@ -521,21 +532,27 @@ getpars(Symbol *args[NR_MACROARG]) cpperror("too many parameters in macro"); return NR_MACROARG; } - if (accept(ELLIPSIS)) { - args[n++] = NULL; - break; - } - if (yytoken != IDEN) { + + if (yytoken == ELLIPSIS) { + sym = newsym(NS_IDEN, "__VA_ARGS__"); + } else if (yytoken == IDEN) { + sym = yylval.sym; + next(); + } else { cpperror("macro arguments must be identifiers"); return NR_MACROARG; } - if ((sym = install(NS_IDEN, yylval.sym)) == NULL) { + + if ((sym = install(NS_IDEN, sym)) == NULL) { errorp("duplicated macro parameter '%s'", yytext); } else { sym->flags |= SUSED; args[n++] = sym; } - next(); + + if (accept(ELLIPSIS)) + break; + } while (accept(',')); if (yytoken != ')') { @@ -647,9 +664,10 @@ wrong_concat: static void define(void) { + int n; Symbol *sym,*args[NR_MACROARG]; char buff[LINESIZ+1]; - int n; + unsigned flags = SDECLARED|SSTRING; if (cppoff) return; @@ -667,8 +685,8 @@ define(void) namespace = NS_IDEN; /* Avoid polution in NS_CPP */ if ((n = getpars(args)) == NR_MACROARG) goto delete; - if (n > 0 && !args[n-1]) /* it is a variadic function */ - --n; + if (n > 0 && strcmp(args[n-1]->name, "__VA_ARGS__") == 0) + flags |= SVARIADIC; sprintf(buff, "%02d#", n); if (!getdefs(args, n, buff+3, LINESIZ-3)) @@ -680,7 +698,7 @@ define(void) free(sym->u.s); } else { sym = install(NS_CPP, sym); - sym->flags |= SDECLARED|SSTRING; + sym->flags |= flags; } sym->u.s = xstrdup(buff); diff --git a/tests/cc/execute/0258-variadic.c b/tests/cc/execute/0258-variadic.c @@ -0,0 +1,26 @@ +#define A(x,y) x+y +#define B(x,y, ...) (x+y+ __VA_ARGS__ ## 0) +#define C(x, ...) test(x, __VA_ARGS__) + +int +test(int n1, int n2, int n3, int n4) +{ + return n1 + n2 + n3 + n4; +} + +int +main(void) +{ + int x = 3; + + if (A(1,x) != 4) + return 1; + if (B(1,x) != 4) + return 2; + if (B(2,x,3) != 35) + return 3; + if (C(1, 2, 3, 4) != 10) + return 4; + + return 0; +} diff --git a/tests/cc/execute/scc-tests.lst b/tests/cc/execute/scc-tests.lst @@ -192,7 +192,7 @@ 0199-voidpcast.c 0200-cpp.c [TODO] 0201-cpp.c -0202-variadic.c [TODO] +0202-variadic.c 0203-comment.c 0204-cast.c 0205-cpparg.c @@ -248,3 +248,4 @@ 0255-init.c 0256-ary.c 0257-main.c +0258-variadic.c