mirror of https://github.com/rui314/chibicc
[GNU] Support GCC-style variadic macro
This commit is contained in:
parent
1ceec75f4d
commit
2a38d6471a
31
preprocess.c
31
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;
|
||||
|
@ -349,7 +350,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;
|
||||
|
||||
|
@ -358,13 +359,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;
|
||||
|
@ -383,12 +391,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));
|
||||
|
@ -427,7 +435,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;
|
||||
|
||||
|
@ -442,7 +450,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));
|
||||
|
@ -452,7 +460,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");
|
||||
|
@ -545,7 +554,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 {
|
||||
|
@ -671,7 +680,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
|
||||
|
|
19
test/macro.c
19
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; }));
|
||||
|
|
Loading…
Reference in New Issue