mirror of https://github.com/rui314/chibicc.git
Add multi-arity funclike #define
This commit is contained in:
parent
dec3b3fa02
commit
b9ad3e43cf
117
preprocess.c
117
preprocess.c
|
@ -23,11 +23,25 @@
|
|||
|
||||
#include "chibicc.h"
|
||||
|
||||
typedef struct MacroParam MacroParam;
|
||||
struct MacroParam {
|
||||
MacroParam *next;
|
||||
char *name;
|
||||
};
|
||||
|
||||
typedef struct MacroArg MacroArg;
|
||||
struct MacroArg {
|
||||
MacroArg *next;
|
||||
char *name;
|
||||
Token *tok;
|
||||
};
|
||||
|
||||
typedef struct Macro Macro;
|
||||
struct Macro {
|
||||
Macro *next;
|
||||
char *name;
|
||||
bool is_objlike; // Object-like or function-like
|
||||
MacroParam *params;
|
||||
Token *body;
|
||||
bool deleted;
|
||||
};
|
||||
|
@ -226,6 +240,25 @@ static Macro *add_macro(char *name, bool is_objlike, Token *body) {
|
|||
return m;
|
||||
}
|
||||
|
||||
static MacroParam *read_macro_params(Token **rest, Token *tok) {
|
||||
MacroParam head = {};
|
||||
MacroParam *cur = &head;
|
||||
|
||||
while (!equal(tok, ")")) {
|
||||
if (cur != &head)
|
||||
tok = skip(tok, ",");
|
||||
|
||||
if (tok->kind != TK_IDENT)
|
||||
error_tok(tok, "expected an identifier");
|
||||
MacroParam *m = calloc(1, sizeof(MacroParam));
|
||||
m->name = strndup(tok->loc, tok->len);
|
||||
cur = cur->next = m;
|
||||
tok = tok->next;
|
||||
}
|
||||
*rest = tok->next;
|
||||
return head.next;
|
||||
}
|
||||
|
||||
static void read_macro_definition(Token **rest, Token *tok) {
|
||||
if (tok->kind != TK_IDENT)
|
||||
error_tok(tok, "macro name must be an identifier");
|
||||
|
@ -234,14 +267,90 @@ static void read_macro_definition(Token **rest, Token *tok) {
|
|||
|
||||
if (!tok->has_space && equal(tok, "(")) {
|
||||
// Function-like macro
|
||||
tok = skip(tok->next, ")");
|
||||
add_macro(name, false, copy_line(rest, tok));
|
||||
MacroParam *params = read_macro_params(&tok, tok->next);
|
||||
Macro *m = add_macro(name, false, copy_line(rest, tok));
|
||||
m->params = params;
|
||||
} else {
|
||||
// Object-like macro
|
||||
add_macro(name, true, copy_line(rest, tok));
|
||||
}
|
||||
}
|
||||
|
||||
static MacroArg *read_macro_arg_one(Token **rest, Token *tok) {
|
||||
Token head = {};
|
||||
Token *cur = &head;
|
||||
|
||||
while (!equal(tok, ",") && !equal(tok, ")")) {
|
||||
if (tok->kind == TK_EOF)
|
||||
error_tok(tok, "premature end of input");
|
||||
cur = cur->next = copy_token(tok);
|
||||
tok = tok->next;
|
||||
}
|
||||
|
||||
cur->next = new_eof(tok);
|
||||
|
||||
MacroArg *arg = calloc(1, sizeof(MacroArg));
|
||||
arg->tok = head.next;
|
||||
*rest = tok;
|
||||
return arg;
|
||||
}
|
||||
|
||||
static MacroArg *read_macro_args(Token **rest, Token *tok, MacroParam *params) {
|
||||
Token *start = tok;
|
||||
tok = tok->next->next;
|
||||
|
||||
MacroArg head = {};
|
||||
MacroArg *cur = &head;
|
||||
|
||||
MacroParam *pp = params;
|
||||
for (; pp; pp = pp->next) {
|
||||
if (cur != &head)
|
||||
tok = skip(tok, ",");
|
||||
cur = cur->next = read_macro_arg_one(&tok, tok);
|
||||
cur->name = pp->name;
|
||||
}
|
||||
|
||||
if (pp)
|
||||
error_tok(start, "too many arguments");
|
||||
*rest = skip(tok, ")");
|
||||
return head.next;
|
||||
}
|
||||
|
||||
static MacroArg *find_arg(MacroArg *args, Token *tok) {
|
||||
for (MacroArg *ap = args; ap; ap = ap->next)
|
||||
if (tok->len == strlen(ap->name) && !strncmp(tok->loc, ap->name, tok->len))
|
||||
return ap;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Replace func-like macro parameters with given arguments.
|
||||
static Token *subst(Token *tok, MacroArg *args) {
|
||||
Token head = {};
|
||||
Token *cur = &head;
|
||||
|
||||
while (tok->kind != TK_EOF) {
|
||||
MacroArg *arg = find_arg(args, tok);
|
||||
|
||||
// Handle a macro token. Macro arguments are completely macro-expanded
|
||||
// before they are substituted into a macro body.
|
||||
if (arg) {
|
||||
Token *t = preprocess2(arg->tok);
|
||||
for (; t->kind != TK_EOF; t = t->next)
|
||||
cur = cur->next = copy_token(t);
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle a non-macro token.
|
||||
cur = cur->next = copy_token(tok);
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
cur->next = tok;
|
||||
return head.next;
|
||||
}
|
||||
|
||||
// If tok is a macro, expand it and return true.
|
||||
// Otherwise, do nothing and return false.
|
||||
static bool expand_macro(Token **rest, Token *tok) {
|
||||
|
@ -266,8 +375,8 @@ static bool expand_macro(Token **rest, Token *tok) {
|
|||
return false;
|
||||
|
||||
// Function-like macro application
|
||||
tok = skip(tok->next->next, ")");
|
||||
*rest = append(m->body, tok);
|
||||
MacroArg *args = read_macro_args(&tok, tok, m->params);
|
||||
*rest = append(subst(m->body, args), tok);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -204,6 +204,15 @@ int main() {
|
|||
#define M7 ()
|
||||
assert(3, ret3 M7, "ret3 M7");
|
||||
|
||||
#define M8(x,y) x+y
|
||||
assert(7, M8(3, 4), "M8(3, 4)");
|
||||
|
||||
#define M8(x,y) x*y
|
||||
assert(24, M8(3+4, 4+5), "M8(3+4, 4+5)");
|
||||
|
||||
#define M8(x,y) (x)*(y)
|
||||
assert(63, M8(3+4, 4+5), "M8(3+4, 4+5)");
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue