mirror of https://github.com/rui314/chibicc
Add __VA_ARGS__
This commit is contained in:
parent
6f17071885
commit
dc01f94900
47
preprocess.c
47
preprocess.c
|
@ -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
|
||||
|
|
27
test/macro.c
27
test/macro.c
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue