Add zero-arity funclike #define

This commit is contained in:
Rui Ueyama 2020-08-18 10:45:03 +09:00
parent 1f80f581e5
commit dec3b3fa02
5 changed files with 62 additions and 12 deletions

View File

@ -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
View File

@ -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");

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}