mirror of https://github.com/rui314/chibicc
[GNU] Support GCC-style variadic macro
This commit is contained in:
parent
74ec9f6f39
commit
007e526ec5
31
preprocess.c
31
preprocess.c
|
@ -34,6 +34,7 @@ typedef struct MacroArg MacroArg;
|
||||||
struct MacroArg {
|
struct MacroArg {
|
||||||
MacroArg *next;
|
MacroArg *next;
|
||||||
char *name;
|
char *name;
|
||||||
|
bool is_va_args;
|
||||||
Token *tok;
|
Token *tok;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,7 +46,7 @@ struct Macro {
|
||||||
char *name;
|
char *name;
|
||||||
bool is_objlike; // Object-like or function-like
|
bool is_objlike; // Object-like or function-like
|
||||||
MacroParam *params;
|
MacroParam *params;
|
||||||
bool is_variadic;
|
char *va_args_name;
|
||||||
Token *body;
|
Token *body;
|
||||||
bool deleted;
|
bool deleted;
|
||||||
macro_handler_fn *handler;
|
macro_handler_fn *handler;
|
||||||
|
@ -336,7 +337,7 @@ static Macro *add_macro(char *name, bool is_objlike, Token *body) {
|
||||||
return m;
|
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 head = {};
|
||||||
MacroParam *cur = &head;
|
MacroParam *cur = &head;
|
||||||
|
|
||||||
|
@ -345,13 +346,20 @@ static MacroParam *read_macro_params(Token **rest, Token *tok, bool *is_variadic
|
||||||
tok = skip(tok, ",");
|
tok = skip(tok, ",");
|
||||||
|
|
||||||
if (equal(tok, "...")) {
|
if (equal(tok, "...")) {
|
||||||
*is_variadic = true;
|
*va_args_name = "__VA_ARGS__";
|
||||||
*rest = skip(tok->next, ")");
|
*rest = skip(tok->next, ")");
|
||||||
return head.next;
|
return head.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok->kind != TK_IDENT)
|
if (tok->kind != TK_IDENT)
|
||||||
error_tok(tok, "expected an identifier");
|
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));
|
MacroParam *m = calloc(1, sizeof(MacroParam));
|
||||||
m->name = strndup(tok->loc, tok->len);
|
m->name = strndup(tok->loc, tok->len);
|
||||||
cur = cur->next = m;
|
cur = cur->next = m;
|
||||||
|
@ -370,12 +378,12 @@ static void read_macro_definition(Token **rest, Token *tok) {
|
||||||
|
|
||||||
if (!tok->has_space && equal(tok, "(")) {
|
if (!tok->has_space && equal(tok, "(")) {
|
||||||
// Function-like macro
|
// Function-like macro
|
||||||
bool is_variadic = false;
|
char *va_args_name = NULL;
|
||||||
MacroParam *params = read_macro_params(&tok, tok->next, &is_variadic);
|
MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name);
|
||||||
|
|
||||||
Macro *m = add_macro(name, false, copy_line(rest, tok));
|
Macro *m = add_macro(name, false, copy_line(rest, tok));
|
||||||
m->params = params;
|
m->params = params;
|
||||||
m->is_variadic = is_variadic;
|
m->va_args_name = va_args_name;
|
||||||
} else {
|
} else {
|
||||||
// Object-like macro
|
// Object-like macro
|
||||||
add_macro(name, true, copy_line(rest, tok));
|
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 *
|
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;
|
Token *start = tok;
|
||||||
tok = tok->next->next;
|
tok = tok->next->next;
|
||||||
|
|
||||||
|
@ -429,7 +437,7 @@ read_macro_args(Token **rest, Token *tok, MacroParam *params, bool is_variadic)
|
||||||
cur->name = pp->name;
|
cur->name = pp->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_variadic) {
|
if (va_args_name) {
|
||||||
MacroArg *arg;
|
MacroArg *arg;
|
||||||
if (equal(tok, ")")) {
|
if (equal(tok, ")")) {
|
||||||
arg = calloc(1, sizeof(MacroArg));
|
arg = calloc(1, sizeof(MacroArg));
|
||||||
|
@ -439,7 +447,8 @@ read_macro_args(Token **rest, Token *tok, MacroParam *params, bool is_variadic)
|
||||||
tok = skip(tok, ",");
|
tok = skip(tok, ",");
|
||||||
arg = read_macro_arg_one(&tok, tok, true);
|
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;
|
cur = cur->next = arg;
|
||||||
} else if (pp) {
|
} else if (pp) {
|
||||||
error_tok(start, "too many arguments");
|
error_tok(start, "too many arguments");
|
||||||
|
@ -531,7 +540,7 @@ static Token *subst(Token *tok, MacroArg *args) {
|
||||||
// __VA_ARGS__.
|
// __VA_ARGS__.
|
||||||
if (equal(tok, ",") && equal(tok->next, "##")) {
|
if (equal(tok, ",") && equal(tok->next, "##")) {
|
||||||
MacroArg *arg = find_arg(args, tok->next->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) {
|
if (arg->tok->kind == TK_EOF) {
|
||||||
tok = tok->next->next->next;
|
tok = tok->next->next->next;
|
||||||
} else {
|
} else {
|
||||||
|
@ -657,7 +666,7 @@ static bool expand_macro(Token **rest, Token *tok) {
|
||||||
|
|
||||||
// Function-like macro application
|
// Function-like macro application
|
||||||
Token *macro_token = tok;
|
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;
|
Token *rparen = tok;
|
||||||
|
|
||||||
// Tokens that consist a func-like macro invocation may have different
|
// Tokens that consist a func-like macro invocation may have different
|
||||||
|
|
19
test/macro.c
19
test/macro.c
|
@ -359,9 +359,28 @@ int main() {
|
||||||
#define M14(x, ...) add6(1,2,x,__VA_ARGS__,6)
|
#define M14(x, ...) add6(1,2,x,__VA_ARGS__,6)
|
||||||
ASSERT(21, M14(3,4,5));
|
ASSERT(21, M14(3,4,5));
|
||||||
|
|
||||||
|
#define M14(args...) 3
|
||||||
|
ASSERT(3, M14());
|
||||||
|
|
||||||
#define M14(x, ...) x
|
#define M14(x, ...) x
|
||||||
ASSERT(5, M14(5));
|
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
|
#define CONCAT(x,y) x##y
|
||||||
ASSERT(5, ({ int f0zz=5; CONCAT(f,0zz); }));
|
ASSERT(5, ({ int f0zz=5; CONCAT(f,0zz); }));
|
||||||
ASSERT(5, ({ CONCAT(4,.57) + 0.5; }));
|
ASSERT(5, ({ CONCAT(4,.57) + 0.5; }));
|
||||||
|
|
Loading…
Reference in New Issue