diff --git a/preprocess.c b/preprocess.c index 20d5c0c..befbe5c 100644 --- a/preprocess.c +++ b/preprocess.c @@ -34,6 +34,7 @@ typedef struct MacroArg MacroArg; struct MacroArg { MacroArg *next; char *name; + bool is_va_args; Token *tok; }; @@ -45,7 +46,7 @@ struct Macro { char *name; bool is_objlike; // Object-like or function-like MacroParam *params; - bool is_variadic; + char *va_args_name; Token *body; bool deleted; macro_handler_fn *handler; @@ -336,7 +337,7 @@ static Macro *add_macro(char *name, bool is_objlike, Token *body) { return m; } -static MacroParam *read_macro_params(Token **rest, Token *tok, bool *is_variadic) { +static MacroParam *read_macro_params(Token **rest, Token *tok, char **va_args_name) { MacroParam head = {}; MacroParam *cur = &head; @@ -345,13 +346,20 @@ static MacroParam *read_macro_params(Token **rest, Token *tok, bool *is_variadic tok = skip(tok, ","); if (equal(tok, "...")) { - *is_variadic = true; + *va_args_name = "__VA_ARGS__"; *rest = skip(tok->next, ")"); return head.next; } if (tok->kind != TK_IDENT) error_tok(tok, "expected an identifier"); + + if (equal(tok->next, "...")) { + *va_args_name = strndup(tok->loc, tok->len); + *rest = skip(tok->next->next, ")"); + return head.next; + } + MacroParam *m = calloc(1, sizeof(MacroParam)); m->name = strndup(tok->loc, tok->len); cur = cur->next = m; @@ -370,12 +378,12 @@ static void read_macro_definition(Token **rest, Token *tok) { if (!tok->has_space && equal(tok, "(")) { // Function-like macro - bool is_variadic = false; - MacroParam *params = read_macro_params(&tok, tok->next, &is_variadic); + char *va_args_name = NULL; + MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name); Macro *m = add_macro(name, false, copy_line(rest, tok)); m->params = params; - m->is_variadic = is_variadic; + m->va_args_name = va_args_name; } else { // Object-like macro add_macro(name, true, copy_line(rest, tok)); @@ -414,7 +422,7 @@ static MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) { } static MacroArg * -read_macro_args(Token **rest, Token *tok, MacroParam *params, bool is_variadic) { +read_macro_args(Token **rest, Token *tok, MacroParam *params, char *va_args_name) { Token *start = tok; tok = tok->next->next; @@ -429,7 +437,7 @@ read_macro_args(Token **rest, Token *tok, MacroParam *params, bool is_variadic) cur->name = pp->name; } - if (is_variadic) { + if (va_args_name) { MacroArg *arg; if (equal(tok, ")")) { arg = calloc(1, sizeof(MacroArg)); @@ -439,7 +447,8 @@ read_macro_args(Token **rest, Token *tok, MacroParam *params, bool is_variadic) tok = skip(tok, ","); arg = read_macro_arg_one(&tok, tok, true); } - arg->name = "__VA_ARGS__"; + arg->name = va_args_name;; + arg->is_va_args = true; cur = cur->next = arg; } else if (pp) { error_tok(start, "too many arguments"); @@ -531,7 +540,7 @@ static Token *subst(Token *tok, MacroArg *args) { // __VA_ARGS__. if (equal(tok, ",") && equal(tok->next, "##")) { MacroArg *arg = find_arg(args, tok->next->next); - if (arg && !strcmp(arg->name, "__VA_ARGS__")) { + if (arg && arg->is_va_args) { if (arg->tok->kind == TK_EOF) { tok = tok->next->next->next; } else { @@ -657,7 +666,7 @@ static bool expand_macro(Token **rest, Token *tok) { // Function-like macro application Token *macro_token = tok; - MacroArg *args = read_macro_args(&tok, tok, m->params, m->is_variadic); + MacroArg *args = read_macro_args(&tok, tok, m->params, m->va_args_name); Token *rparen = tok; // Tokens that consist a func-like macro invocation may have different diff --git a/test/macro.c b/test/macro.c index 7f8b926..cbcfc2d 100644 --- a/test/macro.c +++ b/test/macro.c @@ -359,9 +359,28 @@ int main() { #define M14(x, ...) add6(1,2,x,__VA_ARGS__,6) ASSERT(21, M14(3,4,5)); +#define M14(args...) 3 + ASSERT(3, M14()); + #define M14(x, ...) x ASSERT(5, M14(5)); +#define M14(args...) args + ASSERT(2, M14() 2); + ASSERT(5, M14(5)); + +#define M14(args...) add2(args) + ASSERT(8, M14(2, 6)); + +#define M14(args...) add6(1,2,args,6) + ASSERT(21, M14(3,4,5)); + +#define M14(x, args...) add6(1,2,x,args,6) + ASSERT(21, M14(3,4,5)); + +#define M14(x, args...) x + ASSERT(5, M14(5)); + #define CONCAT(x,y) x##y ASSERT(5, ({ int f0zz=5; CONCAT(f,0zz); })); ASSERT(5, ({ CONCAT(4,.57) + 0.5; }));