Add __FILE__ and __LINE__

This commit is contained in:
Rui Ueyama 2020-08-30 18:57:54 +09:00
parent 5f5a8507ff
commit 6f17071885
4 changed files with 50 additions and 0 deletions

View File

@ -75,6 +75,7 @@ struct Token {
bool at_bol; // True if this token is at beginning of line bool at_bol; // True if this token is at beginning of line
bool has_space; // True if this token follows a space character bool has_space; // True if this token follows a space character
Hideset *hideset; // For macro expansion Hideset *hideset; // For macro expansion
Token *origin; // If this is expanded from a macro, the original token
}; };
void error(char *fmt, ...); void error(char *fmt, ...);

View File

@ -37,6 +37,8 @@ struct MacroArg {
Token *tok; Token *tok;
}; };
typedef Token *macro_handler_fn(Token *);
typedef struct Macro Macro; typedef struct Macro Macro;
struct Macro { struct Macro {
Macro *next; Macro *next;
@ -45,6 +47,7 @@ struct Macro {
MacroParam *params; MacroParam *params;
Token *body; Token *body;
bool deleted; bool deleted;
macro_handler_fn *handler;
}; };
// `#if` can be nested, so we use a stack to manage nested `#if`s. // `#if` can be nested, so we use a stack to manage nested `#if`s.
@ -560,10 +563,19 @@ static bool expand_macro(Token **rest, Token *tok) {
if (!m) if (!m)
return false; return false;
// Built-in dynamic macro application such as __LINE__
if (m->handler) {
*rest = m->handler(tok);
(*rest)->next = tok->next;
return true;
}
// Object-like macro application // Object-like macro application
if (m->is_objlike) { if (m->is_objlike) {
Hideset *hs = hideset_union(tok->hideset, new_hideset(m->name)); Hideset *hs = hideset_union(tok->hideset, new_hideset(m->name));
Token *body = add_hideset(m->body, hs); Token *body = add_hideset(m->body, hs);
for (Token *t = body; t->kind != TK_EOF; t = t->next)
t->origin = tok;
*rest = append(body, tok->next); *rest = append(body, tok->next);
(*rest)->at_bol = tok->at_bol; (*rest)->at_bol = tok->at_bol;
(*rest)->has_space = tok->has_space; (*rest)->has_space = tok->has_space;
@ -590,6 +602,8 @@ static bool expand_macro(Token **rest, Token *tok) {
Token *body = subst(m->body, args); Token *body = subst(m->body, args);
body = add_hideset(body, hs); body = add_hideset(body, hs);
for (Token *t = body; t->kind != TK_EOF; t = t->next)
t->origin = macro_token;
*rest = append(body, tok->next); *rest = append(body, tok->next);
(*rest)->at_bol = macro_token->at_bol; (*rest)->at_bol = macro_token->at_bol;
(*rest)->has_space = macro_token->has_space; (*rest)->has_space = macro_token->has_space;
@ -788,6 +802,24 @@ static void define_macro(char *name, char *buf) {
add_macro(name, true, tok); add_macro(name, true, tok);
} }
static Macro *add_builtin(char *name, macro_handler_fn *fn) {
Macro *m = add_macro(name, true, NULL);
m->handler = fn;
return m;
}
static Token *file_macro(Token *tmpl) {
while (tmpl->origin)
tmpl = tmpl->origin;
return new_str_token(tmpl->file->name, tmpl);
}
static Token *line_macro(Token *tmpl) {
while (tmpl->origin)
tmpl = tmpl->origin;
return new_num_token(tmpl->line_no, tmpl);
}
static void init_macros(void) { static void init_macros(void) {
// Define predefined macros // Define predefined macros
define_macro("_LP64", "1"); define_macro("_LP64", "1");
@ -831,6 +863,9 @@ static void init_macros(void) {
define_macro("__x86_64__", "1"); define_macro("__x86_64__", "1");
define_macro("linux", "1"); define_macro("linux", "1");
define_macro("unix", "1"); define_macro("unix", "1");
add_builtin("__FILE__", file_macro);
add_builtin("__LINE__", line_macro);
} }
// Entry point function of the preprocessor. // Entry point function of the preprocessor.

View File

@ -1,3 +1,6 @@
#include "include2.h" #include "include2.h"
char *include1_filename = __FILE__;
int include1_line = __LINE__;
int include1 = 5; int include1 = 5;

View File

@ -1,6 +1,11 @@
#include "test.h" #include "test.h"
#include "include1.h" #include "include1.h"
char *main_filename1 = __FILE__;
int main_line1 = __LINE__;
#define LINE() __LINE__
int main_line2 = LINE();
# #
/* */ # /* */ #
@ -324,6 +329,12 @@ int main() {
ASSERT(1, __STDC__); ASSERT(1, __STDC__);
ASSERT(0, strcmp(main_filename1, "test/macro.c"));
ASSERT(5, main_line1);
ASSERT(7, main_line2);
ASSERT(0, strcmp(include1_filename, "test/include1.h"));
ASSERT(4, include1_line);
printf("OK\n"); printf("OK\n");
return 0; return 0;
} }