Add include guard optimization

This commit is contained in:
Rui Ueyama 2020-09-08 22:15:00 +09:00
parent f5977e1bff
commit 44776befd8
1 changed files with 53 additions and 0 deletions

View File

@ -777,6 +777,45 @@ static char *read_include_path(Token **rest, Token *tok) {
error_tok(tok, "expected a filename"); error_tok(tok, "expected a filename");
} }
// Detect the following "include guard" pattern.
//
// #ifndef FOO_H
// #define FOO_H
// ...
// #endif
static char *detect_include_guard(Token *tok) {
// Detect the first two lines.
if (!is_hash(tok) || !equal(tok->next, "ifndef"))
return NULL;
tok = tok->next->next;
if (tok->kind != TK_IDENT)
return NULL;
char *macro = strndup(tok->loc, tok->len);
tok = tok->next;
if (!is_hash(tok) || !equal(tok->next, "define") || !equal(tok->next->next, macro))
return NULL;
// Read until the end of the file.
while (tok->kind != TK_EOF) {
if (!is_hash(tok)) {
tok = tok->next;
continue;
}
if (equal(tok->next, "endif") && tok->next->next->kind == TK_EOF)
return macro;
if (equal(tok, "if") || equal(tok, "ifdef") || equal(tok, "ifndef"))
tok = skip_cond_incl(tok->next);
else
tok = tok->next;
}
return NULL;
}
// Read #line arguments // Read #line arguments
static void read_line_marker(Token **rest, Token *tok) { static void read_line_marker(Token **rest, Token *tok) {
Token *start = tok; Token *start = tok;
@ -820,9 +859,23 @@ static Token *preprocess2(Token *tok) {
if (equal(tok, "include")) { if (equal(tok, "include")) {
char *path = read_include_path(&tok, tok->next); char *path = read_include_path(&tok, tok->next);
// If we read the same file before, and if the file was guarded
// by the usual #ifndef ... #endif pattern, we may be able to
// skip the file without opening it.
static HashMap include_guards;
char *guard_name = hashmap_get(&include_guards, path);
if (guard_name && hashmap_get(&macros, guard_name))
continue;
Token *tok2 = tokenize_file(path); Token *tok2 = tokenize_file(path);
if (!tok2) if (!tok2)
error_tok(start, "%s: cannot open file: %s", path, strerror(errno)); error_tok(start, "%s: cannot open file: %s", path, strerror(errno));
guard_name = detect_include_guard(tok2);
if (guard_name)
hashmap_put(&include_guards, path, guard_name);
tok = append(tok2, tok); tok = append(tok2, tok);
continue; continue;
} }