cproc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/cproc
Log | Files | Refs | Submodules | README | LICENSE

commit ed8f52d4a65d8a06aa01a247eab39e65ec5334e1
parent dc17fcc04661f3d8ac5c0e9ba870b9d42979f8da
Author: Michael Forney <mforney@mforney.org>
Date:   Sun, 22 Mar 2020 13:13:17 -0700

pp: Implement variadic macros

Diffstat:
Mpp.c | 31++++++++++++++++++++++++-------
Atest/preprocess-macro-vararg.c | 2++
Atest/preprocess-macro-vararg.pp | 1+
3 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/pp.c b/pp.c @@ -13,6 +13,7 @@ struct macroparam { enum { PARAMTOK = 1<<0, /* the parameter is used normally */ PARAMSTR = 1<<1, /* the parameter is used with the '#' operator */ + PARAMVAR = 1<<2, /* the parameter is __VA_ARGS__ */ } flags; }; @@ -74,7 +75,7 @@ macroequal(struct macro *m1, struct macro *m2) if (m1->nparam != m2->nparam) return false; for (p1 = m1->param, p2 = m2->param; p1 < m1->param + m1->nparam; ++p1, ++p2) { - if (strcmp(p1->name, p2->name) != 0) + if (strcmp(p1->name, p2->name) != 0 || p1->flags != p2->flags) return false; } } @@ -125,6 +126,12 @@ macrodone(struct macro *m) --macrodepth; } +static bool +macrovarargs(struct macro *m) +{ + return m->kind == MACROFUNC && m->nparam > 0 && m->param[m->nparam - 1].flags & PARAMVAR; +} + static struct token * framenext(struct frame *f) { @@ -213,14 +220,22 @@ define(void) if (t->kind == TLPAREN && !t->space) { m->kind = MACROFUNC; /* read macro parameter names */ - while (scan(&tok), tok.kind == TIDENT) { + while (scan(&tok), tok.kind != TRPAREN) { + if (params.len) { + if (p->flags & PARAMVAR) + tokencheck(&tok, TRPAREN, "after '...'"); + tokencheck(&tok, TCOMMA, "or ')' after macro parameter"); + scan(&tok); + } p = arrayadd(&params, sizeof(*p)); - p->name = tok.lit; p->flags = 0; - if (scan(&tok), tok.kind != TCOMMA) - break; + if (tok.kind == TELLIPSIS) { + p->name = "__VA_ARGS__"; + p->flags |= PARAMVAR; + } else { + p->name = tokencheck(&tok, TIDENT, "of macro parameter name or '...'"); + } } - tokencheck(&tok, TRPAREN, "after macro parameter list"); scan(t); /* first token in replacement list */ } else { m->kind = MACROOBJ; @@ -236,6 +251,8 @@ define(void) prev = t->kind; t = arrayadd(&repl, sizeof(*t)); scan(t); + if (t->kind == TIDENT && strcmp(t->lit, "__VA_ARGS__") == 0 && !macrovarargs(m)) + error(&t->loc, "__VA_ARGS__ can only be used in variadic function-like macros"); if (m->kind != MACROFUNC) continue; if (i != -1) @@ -440,7 +457,7 @@ expand(struct token *t) if (macrodepth <= depth) { /* adjust current macro depth, in case it got shallower */ depth = macrodepth; - if (paren == 0 && (t->kind == TCOMMA || t->kind == TRPAREN)) + if (paren == 0 && (t->kind == TRPAREN || t->kind == TCOMMA && !(p->flags & PARAMVAR))) break; switch (t->kind) { case TLPAREN: ++paren; break; diff --git a/test/preprocess-macro-vararg.c b/test/preprocess-macro-vararg.c @@ -0,0 +1,2 @@ +#define f(a, ...) __VA_ARGS__ + a, # __VA_ARGS__ +f(abc, 1, (2, 3), 4) diff --git a/test/preprocess-macro-vararg.pp b/test/preprocess-macro-vararg.pp @@ -0,0 +1 @@ +1, (2, 3), 4 + abc, "1, (2, 3), 4"