Add __VA_ARGS__

This commit is contained in:
Rui Ueyama 2020-04-02 06:55:07 +09:00
parent 6f17071885
commit dc01f94900
2 changed files with 66 additions and 8 deletions

View File

@ -45,6 +45,7 @@ struct Macro {
char *name;
bool is_objlike; // Object-like or function-like
MacroParam *params;
bool is_variadic;
Token *body;
bool deleted;
macro_handler_fn *handler;
@ -332,7 +333,7 @@ static Macro *add_macro(char *name, bool is_objlike, Token *body) {
return m;
}
static MacroParam *read_macro_params(Token **rest, Token *tok) {
static MacroParam *read_macro_params(Token **rest, Token *tok, bool *is_variadic) {
MacroParam head = {};
MacroParam *cur = &head;
@ -340,6 +341,12 @@ static MacroParam *read_macro_params(Token **rest, Token *tok) {
if (cur != &head)
tok = skip(tok, ",");
if (equal(tok, "...")) {
*is_variadic = true;
*rest = skip(tok->next, ")");
return head.next;
}
if (tok->kind != TK_IDENT)
error_tok(tok, "expected an identifier");
MacroParam *m = calloc(1, sizeof(MacroParam));
@ -347,6 +354,7 @@ static MacroParam *read_macro_params(Token **rest, Token *tok) {
cur = cur->next = m;
tok = tok->next;
}
*rest = tok->next;
return head.next;
}
@ -359,21 +367,29 @@ static void read_macro_definition(Token **rest, Token *tok) {
if (!tok->has_space && equal(tok, "(")) {
// Function-like macro
MacroParam *params = read_macro_params(&tok, tok->next);
bool is_variadic = false;
MacroParam *params = read_macro_params(&tok, tok->next, &is_variadic);
Macro *m = add_macro(name, false, copy_line(rest, tok));
m->params = params;
m->is_variadic = is_variadic;
} else {
// Object-like macro
add_macro(name, true, copy_line(rest, tok));
}
}
static MacroArg *read_macro_arg_one(Token **rest, Token *tok) {
static MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) {
Token head = {};
Token *cur = &head;
int level = 0;
while (level > 0 || (!equal(tok, ",") && !equal(tok, ")"))) {
for (;;) {
if (level == 0 && equal(tok, ")"))
break;
if (level == 0 && !read_rest && equal(tok, ","))
break;
if (tok->kind == TK_EOF)
error_tok(tok, "premature end of input");
@ -394,7 +410,8 @@ static MacroArg *read_macro_arg_one(Token **rest, Token *tok) {
return arg;
}
static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params) {
static MacroArg *
read_macro_args(Token **rest, Token *tok, MacroParam *params, bool is_variadic) {
Token *start = tok;
tok = tok->next->next;
@ -405,12 +422,26 @@ static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params) {
for (; pp; pp = pp->next) {
if (cur != &head)
tok = skip(tok, ",");
cur = cur->next = read_macro_arg_one(&tok, tok);
cur = cur->next = read_macro_arg_one(&tok, tok, false);
cur->name = pp->name;
}
if (pp)
if (is_variadic) {
MacroArg *arg;
if (equal(tok, ")")) {
arg = calloc(1, sizeof(MacroArg));
arg->tok = new_eof(tok);
} else {
if (pp != params)
tok = skip(tok, ",");
arg = read_macro_arg_one(&tok, tok, true);
}
arg->name = "__VA_ARGS__";
cur = cur->next = arg;
} else if (pp) {
error_tok(start, "too many arguments");
}
skip(tok, ")");
*rest = tok;
return head.next;
@ -589,7 +620,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);
MacroArg *args = read_macro_args(&tok, tok, m->params, m->is_variadic);
Token *rparen = tok;
// Tokens that consist a func-like macro invocation may have different

View File

@ -13,6 +13,14 @@ int main_line2 = LINE();
int ret3(void) { return 3; }
int dbl(int x) { return x*x; }
int add2(int x, int y) {
return x + y;
}
int add6(int a, int b, int c, int d, int e, int f) {
return a + b + c + d + e + f;
}
int main() {
ASSERT(5, include1);
ASSERT(7, include2);
@ -335,6 +343,25 @@ int main() {
ASSERT(0, strcmp(include1_filename, "test/include1.h"));
ASSERT(4, include1_line);
#define M14(...) 3
ASSERT(3, M14());
#define M14(...) __VA_ARGS__
ASSERT(2, M14() 2);
ASSERT(5, M14(5));
#define M14(...) add2(__VA_ARGS__)
ASSERT(8, M14(2, 6));
#define M14(...) add6(1,2,__VA_ARGS__,6)
ASSERT(21, M14(3,4,5));
#define M14(x, ...) add6(1,2,x,__VA_ARGS__,6)
ASSERT(21, M14(3,4,5));
#define M14(x, ...) x
ASSERT(5, M14(5));
printf("OK\n");
return 0;
}