mirror of https://github.com/rui314/chibicc
75 lines
1.6 KiB
C
75 lines
1.6 KiB
C
#include "chibicc.h"
|
|
|
|
static bool is_hash(Token *tok) {
|
|
return tok->at_bol && equal(tok, "#");
|
|
}
|
|
|
|
static Token *copy_token(Token *tok) {
|
|
Token *t = calloc(1, sizeof(Token));
|
|
*t = *tok;
|
|
t->next = NULL;
|
|
return t;
|
|
}
|
|
|
|
// Append tok2 to the end of tok1.
|
|
static Token *append(Token *tok1, Token *tok2) {
|
|
if (!tok1 || tok1->kind == TK_EOF)
|
|
return tok2;
|
|
|
|
Token head = {};
|
|
Token *cur = &head;
|
|
|
|
for (; tok1 && tok1->kind != TK_EOF; tok1 = tok1->next)
|
|
cur = cur->next = copy_token(tok1);
|
|
cur->next = tok2;
|
|
return head.next;
|
|
}
|
|
|
|
// Visit all tokens in `tok` while evaluating preprocessing
|
|
// macros and directives.
|
|
static Token *preprocess2(Token *tok) {
|
|
Token head = {};
|
|
Token *cur = &head;
|
|
|
|
while (tok->kind != TK_EOF) {
|
|
// Pass through if it is not a "#".
|
|
if (!is_hash(tok)) {
|
|
cur = cur->next = tok;
|
|
tok = tok->next;
|
|
continue;
|
|
}
|
|
|
|
tok = tok->next;
|
|
|
|
if (equal(tok, "include")) {
|
|
tok = tok->next;
|
|
|
|
if (tok->kind != TK_STR)
|
|
error_tok(tok, "expected a filename");
|
|
|
|
char *path = format("%s/%s", dirname(strdup(tok->file->name)), tok->str);
|
|
Token *tok2 = tokenize_file(path);
|
|
if (!tok2)
|
|
error_tok(tok, "%s", strerror(errno));
|
|
tok = append(tok2, tok->next);
|
|
continue;
|
|
}
|
|
|
|
// `#`-only line is legal. It's called a null directive.
|
|
if (tok->at_bol)
|
|
continue;
|
|
|
|
error_tok(tok, "invalid preprocessor directive");
|
|
}
|
|
|
|
cur->next = tok;
|
|
return head.next;
|
|
}
|
|
|
|
// Entry point function of the preprocessor.
|
|
Token *preprocess(Token *tok) {
|
|
tok = preprocess2(tok);
|
|
convert_keywords(tok);
|
|
return tok;
|
|
}
|