Add #line

This commit is contained in:
Rui Ueyama 2020-07-22 19:45:03 +09:00
parent 37998be0c1
commit c61c0d0025
4 changed files with 56 additions and 2 deletions

View File

@ -59,6 +59,10 @@ typedef struct {
char *name;
int file_no;
char *contents;
// For #line directive
char *display_name;
int line_delta;
} File;
// Token type
@ -74,7 +78,9 @@ struct Token {
char *str; // String literal contents including terminating '\0'
File *file; // Source location
char *filename; // Filename
int line_no; // Line number
int line_delta; // 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

View File

@ -705,6 +705,24 @@ static Token *include_file(Token *tok, char *path, Token *filename_tok) {
return append(tok2, tok);
}
// Read #line arguments
static void read_line_marker(Token **rest, Token *tok) {
Token *start = tok;
tok = preprocess(copy_line(rest, tok));
if (tok->kind != TK_NUM || tok->ty->kind != TY_INT)
error_tok(tok, "invalid line marker");
start->file->line_delta = tok->val - start->line_no;
tok = tok->next;
if (tok->kind == TK_EOF)
return;
if (tok->kind != TK_STR)
error_tok(tok, "filename expected");
start->file->display_name = tok->str;
}
// Visit all tokens in `tok` while evaluating preprocessing
// macros and directives.
static Token *preprocess2(Token *tok) {
@ -718,6 +736,8 @@ static Token *preprocess2(Token *tok) {
// Pass through if it is not a "#".
if (!is_hash(tok)) {
tok->line_delta = tok->file->line_delta;
tok->filename = tok->file->display_name;
cur = cur->next = tok;
tok = tok->next;
continue;
@ -814,6 +834,11 @@ static Token *preprocess2(Token *tok) {
continue;
}
if (equal(tok, "line")) {
read_line_marker(&tok, tok->next);
continue;
}
if (equal(tok, "error"))
error_tok(tok, "error");
@ -847,13 +872,14 @@ static Macro *add_builtin(char *name, macro_handler_fn *fn) {
static Token *file_macro(Token *tmpl) {
while (tmpl->origin)
tmpl = tmpl->origin;
return new_str_token(tmpl->file->name, tmpl);
return new_str_token(tmpl->file->display_name, tmpl);
}
static Token *line_macro(Token *tmpl) {
while (tmpl->origin)
tmpl = tmpl->origin;
return new_num_token(tmpl->line_no, tmpl);
int i = tmpl->line_no + tmpl->file->line_delta;
return new_num_token(i, tmpl);
}
// __COUNTER__ is expanded to serial values starting from 0.
@ -1022,5 +1048,8 @@ Token *preprocess(Token *tok) {
error_tok(cond_incl->tok, "unterminated conditional directive");
convert_pp_tokens(tok);
join_adjacent_string_literals(tok);
for (Token *t = tok; t; t = t->next)
t->line_no += t->line_delta;
return tok;
}

17
test/line.c Normal file
View File

@ -0,0 +1,17 @@
#include "test.h"
int main() {
#line 500 "foo"
ASSERT(501, __LINE__);
ASSERT(0, strcmp(__FILE__, "foo"));
#line 800 "bar"
ASSERT(801, __LINE__);
ASSERT(0, strcmp(__FILE__, "bar"));
#line 1
ASSERT(2, __LINE__);
printf("OK\n");
return 0;
}

View File

@ -103,6 +103,7 @@ static Token *new_token(TokenKind kind, char *start, char *end) {
tok->loc = start;
tok->len = end - start;
tok->file = current_file;
tok->filename = current_file->display_name;
tok->at_bol = at_bol;
tok->has_space = has_space;
@ -674,6 +675,7 @@ File **get_input_files(void) {
File *new_file(char *name, int file_no, char *contents) {
File *file = calloc(1, sizeof(File));
file->name = name;
file->display_name = name;
file->file_no = file_no;
file->contents = contents;
return file;