mirror of https://github.com/rui314/chibicc.git
Add zero-arity funclike #define
This commit is contained in:
parent
1f80f581e5
commit
dec3b3fa02
|
@ -73,6 +73,7 @@ struct Token {
|
|||
File *file; // Source location
|
||||
int line_no; // Line number
|
||||
bool at_bol; // True if this token is at beginning of line
|
||||
bool has_space; // True if this token follows a space character
|
||||
Hideset *hideset; // For macro expansion
|
||||
};
|
||||
|
||||
|
|
4
main.c
4
main.c
|
@ -179,7 +179,9 @@ static void print_tokens(Token *tok) {
|
|||
for (; tok->kind != TK_EOF; tok = tok->next) {
|
||||
if (line > 1 && tok->at_bol)
|
||||
fprintf(out, "\n");
|
||||
fprintf(out, " %.*s", tok->len, tok->loc);
|
||||
if (tok->has_space && !tok->at_bol)
|
||||
fprintf(out, " ");
|
||||
fprintf(out, "%.*s", tok->len, tok->loc);
|
||||
line++;
|
||||
}
|
||||
fprintf(out, "\n");
|
||||
|
|
47
preprocess.c
47
preprocess.c
|
@ -27,6 +27,7 @@ typedef struct Macro Macro;
|
|||
struct Macro {
|
||||
Macro *next;
|
||||
char *name;
|
||||
bool is_objlike; // Object-like or function-like
|
||||
Token *body;
|
||||
bool deleted;
|
||||
};
|
||||
|
@ -215,15 +216,32 @@ static Macro *find_macro(Token *tok) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static Macro *add_macro(char *name, Token *body) {
|
||||
static Macro *add_macro(char *name, bool is_objlike, Token *body) {
|
||||
Macro *m = calloc(1, sizeof(Macro));
|
||||
m->next = macros;
|
||||
m->name = name;
|
||||
m->is_objlike = is_objlike;
|
||||
m->body = body;
|
||||
macros = m;
|
||||
return m;
|
||||
}
|
||||
|
||||
static void read_macro_definition(Token **rest, Token *tok) {
|
||||
if (tok->kind != TK_IDENT)
|
||||
error_tok(tok, "macro name must be an identifier");
|
||||
char *name = strndup(tok->loc, tok->len);
|
||||
tok = tok->next;
|
||||
|
||||
if (!tok->has_space && equal(tok, "(")) {
|
||||
// Function-like macro
|
||||
tok = skip(tok->next, ")");
|
||||
add_macro(name, false, copy_line(rest, tok));
|
||||
} else {
|
||||
// Object-like macro
|
||||
add_macro(name, true, copy_line(rest, tok));
|
||||
}
|
||||
}
|
||||
|
||||
// If tok is a macro, expand it and return true.
|
||||
// Otherwise, do nothing and return false.
|
||||
static bool expand_macro(Token **rest, Token *tok) {
|
||||
|
@ -234,9 +252,22 @@ static bool expand_macro(Token **rest, Token *tok) {
|
|||
if (!m)
|
||||
return false;
|
||||
|
||||
Hideset *hs = hideset_union(tok->hideset, new_hideset(m->name));
|
||||
Token *body = add_hideset(m->body, hs);
|
||||
*rest = append(body, tok->next);
|
||||
// Object-like macro application
|
||||
if (m->is_objlike) {
|
||||
Hideset *hs = hideset_union(tok->hideset, new_hideset(m->name));
|
||||
Token *body = add_hideset(m->body, hs);
|
||||
*rest = append(body, tok->next);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If a funclike macro token is not followed by an argument list,
|
||||
// treat it as a normal identifier.
|
||||
if (!equal(tok->next, "("))
|
||||
return false;
|
||||
|
||||
// Function-like macro application
|
||||
tok = skip(tok->next->next, ")");
|
||||
*rest = append(m->body, tok);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -282,11 +313,7 @@ static Token *preprocess2(Token *tok) {
|
|||
}
|
||||
|
||||
if (equal(tok, "define")) {
|
||||
tok = tok->next;
|
||||
if (tok->kind != TK_IDENT)
|
||||
error_tok(tok, "macro name must be an identifier");
|
||||
char *name = strndup(tok->loc, tok->len);
|
||||
add_macro(name, copy_line(&tok, tok->next));
|
||||
read_macro_definition(&tok, tok->next);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -297,7 +324,7 @@ static Token *preprocess2(Token *tok) {
|
|||
char *name = strndup(tok->loc, tok->len);
|
||||
tok = skip_line(tok->next);
|
||||
|
||||
Macro *m = add_macro(name, NULL);
|
||||
Macro *m = add_macro(name, true, NULL);
|
||||
m->deleted = true;
|
||||
continue;
|
||||
}
|
||||
|
|
10
test/macro.c
10
test/macro.c
|
@ -10,6 +10,8 @@ int memcmp(char *p, char *q, long n);
|
|||
|
||||
/* */ #
|
||||
|
||||
int ret3(void) { return 3; }
|
||||
|
||||
int main() {
|
||||
assert(5, include1, "include1");
|
||||
assert(7, include2, "include2");
|
||||
|
@ -194,6 +196,14 @@ int main() {
|
|||
#else
|
||||
#endif
|
||||
|
||||
#define M7() 1
|
||||
int M7 = 5;
|
||||
assert(1, M7(), "M7()");
|
||||
assert(5, M7, "M7");
|
||||
|
||||
#define M7 ()
|
||||
assert(3, ret3 M7, "ret3 M7");
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
12
tokenize.c
12
tokenize.c
|
@ -9,6 +9,9 @@ static File **input_files;
|
|||
// True if the current position is at the beginning of a line
|
||||
static bool at_bol;
|
||||
|
||||
// True if the current position follows a space character
|
||||
static bool has_space;
|
||||
|
||||
// Reports an error and exit.
|
||||
void error(char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
@ -101,7 +104,9 @@ static Token *new_token(TokenKind kind, char *start, char *end) {
|
|||
tok->len = end - start;
|
||||
tok->file = current_file;
|
||||
tok->at_bol = at_bol;
|
||||
at_bol = false;
|
||||
tok->has_space = has_space;
|
||||
|
||||
at_bol = has_space = false;
|
||||
return tok;
|
||||
}
|
||||
|
||||
|
@ -394,6 +399,7 @@ static Token *tokenize(File *file) {
|
|||
Token *cur = &head;
|
||||
|
||||
at_bol = true;
|
||||
has_space = false;
|
||||
|
||||
while (*p) {
|
||||
// Skip line comments.
|
||||
|
@ -401,6 +407,7 @@ static Token *tokenize(File *file) {
|
|||
p += 2;
|
||||
while (*p != '\n')
|
||||
p++;
|
||||
has_space = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -410,6 +417,7 @@ static Token *tokenize(File *file) {
|
|||
if (!q)
|
||||
error_at(p, "unclosed block comment");
|
||||
p = q + 2;
|
||||
has_space = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -417,12 +425,14 @@ static Token *tokenize(File *file) {
|
|||
if (*p == '\n') {
|
||||
p++;
|
||||
at_bol = true;
|
||||
has_space = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip whitespace characters.
|
||||
if (isspace(*p)) {
|
||||
p++;
|
||||
has_space = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue