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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
(* This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
program(parameters)
import
cstdio, cstdlib, cstring, common, command_line_interface,
lexer, ast, diagnostic, symbol, parser, name_analysis, type_check, tac, qbe
proc read_file_to_buffer(filename: ^Word8) -> []const Word8
var
file_handle: ^FILE
file_size: Int
buffer: ^Word8
bytes_read: Word
result: []const Word8
begin
file_handle := fopen(filename, "rb\0".ptr);
if file_handle = nil then
perror(filename);
exit(3)
end;
fseek(file_handle, 0, 2);
file_size := ftell(file_handle);
rewind(file_handle);
buffer := malloc#[Word8](cast(file_size: Word) + 1u);
bytes_read := fread#[Word8](buffer, 1u, cast(file_size: Word), file_handle);
(buffer + bytes_read)^ := cast(0: Word8);
fclose(file_handle);
result := buffer[1u to bytes_read]
return result
proc print_errors(error_list: ^ElnaList)
var
node: ^ElnaListNode
begin
node := error_list^.first;
while node <> nil do
elna_error_print(cast(node: ^ElnaError));
node := node^.next
end
return
proc compile_file(command_line: ^CommandLine) -> Int
var
source_text: []const Word8
lexer_cursor: ElnaLexerCursor
error_list: ElnaList
parser_node: ^ElnaTreeModuleDeclaration
tac_module: ^ElnaInstructionModule
out_file: ^FILE := stdout
token: ^ElnaLexerToken
return_code: Int := 0
begin
source_text := read_file_to_buffer(command_line^.input);
if command_line^.lex then
elna_lexer_initialize(@lexer_cursor, cast(source_text.ptr: ^Word8));
token := elna_lexer_read(@lexer_cursor);
while token^.kind <> ElnaLexerKind.eof do
token := elna_lexer_read(@lexer_cursor)
end
else
elna_list_initialize(@error_list);
elna_symbol_table_build();
elna_lexer_initialize(@lexer_cursor, cast(source_text.ptr: ^Word8));
parser_node := elna_parser_module_declaration(@lexer_cursor, @error_list);
if ~elna_list_empty(@error_list) then
print_errors(@error_list);
return_code := 1
elsif ~command_line^.parse then
elna_declaration_module_declaration(parser_node, @error_list);
if ~elna_list_empty(@error_list) then
print_errors(@error_list);
return_code := 1
else
elna_name_module_declaration(parser_node, @error_list);
if ~elna_list_empty(@error_list) then
print_errors(@error_list);
return_code := 1
else
elna_type_module_declaration(parser_node, @error_list);
if ~elna_list_empty(@error_list) then
print_errors(@error_list);
return_code := 1
else
tac_module := elna_tac_module_declaration(parser_node);
if command_line^.output <> nil then
out_file := fopen(command_line^.output, "wb\0".ptr);
if out_file = nil then
perror(command_line^.output);
return_code := 3
end
end;
if return_code = 0 then
elna_qbe_emit(tac_module, out_file);
if command_line^.output <> nil & out_file <> stdout then
fclose(out_file)
end
end
end
end
end
end
end
return return_code
proc initialize_global_state()
begin
stdin := fdopen(0, "r\0".ptr);
stdout := fdopen(1, "w\0".ptr);
stderr := fdopen(2, "w\0".ptr)
return
proc process(argc: Int; argv: ^^Word8) -> Int
var
command_line: ^CommandLine
return_code: Int := 0
begin
command_line := parse_command_line(argc, argv);
if command_line = nil then
return_code := 2
elsif command_line^.input = nil then
write_s("Fatal error: no input file provided.\n");
return_code := 2
else
return_code := compile_file(command_line)
end
return return_code
begin
initialize_global_state();
exit(process(cast(parameters.length: Int), parameters.ptr))
end.
|