1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
#include "io.h"
#include "common.h"
#include "json.h"
void sourcelocation_build_json(JsonBuilder* builder, SourceLocation* loc) {
jsonbuilder_object_start(builder);
jsonbuilder_object_member_start(builder, "filename");
jsonbuilder_string(builder, loc->filename);
jsonbuilder_object_member_end(builder);
jsonbuilder_object_member_start(builder, "line");
jsonbuilder_integer(builder, loc->line);
jsonbuilder_object_member_end(builder);
jsonbuilder_object_end(builder);
}
InFile* infile_open(const char* filename) {
FILE* in = fopen(filename, "rb");
if (!in) {
return NULL;
}
size_t buf_size = 1024 * 10;
char* buf = calloc(buf_size, sizeof(char));
char* cur = buf;
char* tmp = calloc(1024, sizeof(char));
while (fgets(tmp, 1024, in)) {
size_t len = strlen(tmp);
size_t used_size = cur - buf;
if (buf_size <= used_size + len) {
size_t old_size = buf_size;
buf_size *= 2;
buf = realloc(buf, buf_size);
memset(buf + old_size, 0, buf_size - old_size);
cur = buf + used_size;
}
memcpy(cur, tmp, len);
cur += len;
}
fclose(in);
InFile* in_file = calloc(1, sizeof(InFile));
in_file->buf = buf;
in_file->loc.filename = filename;
in_file->loc.line = 1;
return in_file;
}
bool infile_eof(InFile* f) {
return f->buf[f->pos] == '\0';
}
char infile_peek_char(InFile* f) {
char c = f->buf[f->pos];
// Skip a pair of backslash and new-line.
if (c == '\\') {
char c2 = f->buf[f->pos + 1];
// C23: 5.1.1.2
// A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by
// a backslash character before any such splicing takes place.
if (c2 == '\0') {
fatal_error("%s:%d: <new-line> expected, but got <eof>", f->loc.filename, f->loc.line);
}
// TODO: crlf
if (c2 == '\r' || c2 == '\n') {
f->pos += 2;
++f->loc.line;
return infile_peek_char(f);
}
}
// Normalize new-line.
// TODO: crlf
if (c == '\r')
c = '\n';
return c;
}
char infile_next_char(InFile* f) {
char c = infile_peek_char(f);
++f->pos;
if (c == '\n')
++f->loc.line;
return c;
}
bool infile_consume_if(InFile* f, char expected) {
if (infile_peek_char(f) == expected) {
infile_next_char(f);
return true;
} else {
return false;
}
}
|