...
1include 'std.stas'
2
3reserve debug_symbols 1
4reserve verbose_mode 1
5auto backend_type 1
6
7const StasBackend.fasm { 1 }
8const StasBackend.nasm { 2 }
9
10; (StasBackend -- str len)
11fn StasBackend.to_str 1 2 {
12 dup StasBackend.fasm = if {
13 "fasm"
14 } elif dup StasBackend.nasm = {
15 "nasm"
16 } else {
17 0 0 0 assert -> 'unreachable'
18 }
19 rot rot drop
20}
21
22include 'src/stringbuffer.stas' ; handling strings
23include 'src/tokens.stas' ; stas token definitions
24include 'src/util.stas' ; utility functions, error handling
25include 'src/scanner.stas' ; lexer/scanner, creates tokens
26include 'src/parserdefs.stas' ; stas parser definitions, very large file
27include 'src/eval.stas' ; constant evaluation
28include 'src/parser.stas' ; stas parser, creates IR instructions
29include 'src/write.stas' ; buffers + writing to files
30include 'src/dce.stas' ; dead code elimination compiler pass
31include 'src/x86.stas' ; stas codegen definitions and reg allocator
32include 'src/gen.stas' ; stas code generator, creates x86_64 asm
33
34fn usage 0 0 {
35 "stas 0.1.1 Copyright (C) 2022 l-m.dev\n\n" eputs
36 "USAGE: ./stas [OPTIONS] [FILE]\n\n" eputs
37
38 " -o <output> Specify '-o -' to dump assembly to stdout\n" eputs
39 " -g Debug info. Most effective with the `nasm` backend\n" eputs
40 " -b <backend> Assemblers `nasm` or `fasm` as compiler backend\n" eputs
41 " -r Execute file after compiling. Arguments after this\n" eputs
42 " switch will ignored and passed to the program\n" eputs
43 " -v, --verbose Activate verbose mode\n" eputs
44 " --dump-tok Dump token information after scanning stage\n" eputs
45 " --dump-ir Dump intermediate representation after parsing stage\n" eputs
46 " -h, --help Show this message\n\n" eputs
47}
48
49fn help_and_exit 0 0 {
50 usage
51 0 exit
52}
53
54fn usage_and_exit 0 0 {
55 usage
56 1 exit
57}
58
59fn usage_msg_and_exit 2 0 {
60 error.generic_fatal_noexit
61 usage_and_exit
62}
63
64fn parse_backend_type 2 0 {
65 over over "fasm" streq if {
66 StasBackend.fasm pop backend_type
67 } elif over over "nasm" streq {
68 StasBackend.nasm pop backend_type
69 } else {
70 "unknown backend" usage_msg_and_exit
71 }
72 drop drop
73}
74
75const sizeof(fasm_arg_buf) { sizeof(u64) 32 * }
76
77; (infile.str infile.len outfile.str outfile.len is_blocking)
78fn execute_backend 5 0 {
79 auto is_blocking 1 pop is_blocking
80 auto outfile 2 pop outfile
81 auto infile 2 pop infile
82
83 reserve arg_buf sizeof(fasm_arg_buf)
84
85 backend_type StasBackend.fasm = if {
86 arg_buf dup "fasm" drop w64
87 sizeof(u64) + dup infile drop w64
88 sizeof(u64) + dup outfile drop w64
89 sizeof(u64) + dup "-m" drop w64
90 sizeof(u64) + dup "1048576" drop w64
91 sizeof(u64) + NULL w64
92
93 "/usr/bin/fasm"
94 } elif backend_type StasBackend.nasm = {
95 arg_buf dup "nasm" drop w64
96 sizeof(u64) + dup infile drop w64
97 sizeof(u64) + dup "-o" drop w64
98 sizeof(u64) + dup outfile drop w64
99 sizeof(u64) + dup "-O0" drop w64
100 sizeof(u64) + dup "-felf64" drop w64
101
102 debug_symbols r8 if {
103 sizeof(u64) + dup "-Fdwarf" drop w64
104 sizeof(u64) + dup "-g" drop w64
105 }
106
107 sizeof(u64) + NULL w64
108 "/usr/bin/nasm"
109 }
110
111 verbose_mode r8 if {
112 log.msg.start
113 "`" eputs
114 arg_buf argp_print
115 "`\n" eputs
116 }
117
118 arg_buf is_blocking child_execve_and_shut_up
119}
120
121const ArgParseMode.none { 0 }
122const ArgParseMode.output { 1 }
123const ArgParseMode.backend { 2 }
124
125fn main 0 0 {
126 argc 1 = if {
127 usage_and_exit
128 }
129
130 reserve dump_ir 1
131 reserve dump_tok 1
132 reserve to_stdout 1
133
134 to_stdout 0 w8
135 dump_ir 0 w8
136 dump_tok 0 w8
137
138 auto run_exec_arg 1
139 0 pop run_exec_arg
140
141 UINT64_MAX pop fwrite_buffer.fd_loc
142 StasBackend.fasm pop backend_type
143
144 auto argparse_mode 1
145 auto argstr 2
146
147 auto out_file 2
148 auto in_file 2
149 NULL 0 pop out_file
150 NULL 0 pop in_file
151
152 ArgParseMode.none pop argparse_mode
153 debug_symbols false w8
154
155 1
156 while dup argc < {
157 dup args[] pop argstr
158
159 argstr "-o" streq if {
160 argparse_mode ArgParseMode.none != if {
161 usage_and_exit
162 }
163 ArgParseMode.output pop argparse_mode
164 } elif argstr "-b" streq {
165 argparse_mode ArgParseMode.none != if {
166 usage_and_exit
167 }
168 ArgParseMode.backend pop argparse_mode
169 } elif argstr "-g" streq {
170 argparse_mode ArgParseMode.none != if {
171 usage_and_exit
172 }
173 debug_symbols r8 if {
174 usage_and_exit
175 }
176 debug_symbols true w8
177 } elif argstr "--verbose" streq argstr "-v" streq | {
178 argparse_mode ArgParseMode.none != if {
179 usage_and_exit
180 }
181 verbose_mode r8 if {
182 usage_and_exit
183 }
184 verbose_mode true w8
185 } elif argstr "-r" streq {
186 argparse_mode ArgParseMode.none != if {
187 usage_and_exit
188 }
189 pop run_exec_arg
190 argc
191 } elif argstr "--help" streq argstr "-h" streq | {
192 help_and_exit
193 } elif argstr "--dump-ir" streq argstr "-h" streq | {
194 argparse_mode ArgParseMode.none != dump_ir r8 | dump_tok r8 | if {
195 usage_and_exit
196 }
197 dump_ir true w8
198 } elif argstr "--dump-tok" streq argstr "-h" streq | {
199 argparse_mode ArgParseMode.none != dump_ir r8 | dump_tok r8 | if {
200 usage_and_exit
201 }
202 dump_tok true w8
203 } else {
204 argparse_mode ArgParseMode.none = if {
205 in_file drop NULL != if {
206 usage_and_exit
207 }
208 argstr pop in_file
209 } elif argparse_mode ArgParseMode.output = {
210 out_file drop NULL != if {
211 usage_and_exit
212 }
213 argstr pop out_file
214 } elif argparse_mode ArgParseMode.backend = {
215 argstr parse_backend_type
216 } else {
217 0 assert
218 }
219 ArgParseMode.none pop argparse_mode
220 }
221 ++
222 }
223 drop
224
225 argparse_mode ArgParseMode.none != if {
226 argparse_mode ArgParseMode.output = if {
227 "supply output file" usage_msg_and_exit
228 } elif argparse_mode ArgParseMode.backend = {
229 "supply backend type" usage_msg_and_exit
230 }
231 }
232
233 in_file drop NULL = if {
234 "supply stas file" usage_msg_and_exit
235 }
236
237 out_file drop NULL = if {
238 debug_symbols r8 backend_type StasBackend.nasm = | if {
239 "a.o"
240 } else {
241 "a.out"
242 }
243 pop out_file
244 } else {
245 out_file "-" streq if {
246 to_stdout true w8
247 }
248 }
249
250 verbose_mode r8 if {
251 log.msg.start
252 "scanning file `" eputs in_file eputs "`\n" eputs
253 }
254
255 log.time.start
256 in_file stas.scan_file
257 "scanning took " log.time.end
258
259 dump_tok r8 if {
260 token_stream.dump
261 ret
262 }
263
264 verbose_mode r8 if {
265 log.msg.start
266 "parsing " eputs token_stream.len eputu " tokens\n" eputs
267 }
268 log.time.start
269 stas.parse
270 "parsing took " log.time.end
271 verbose_mode r8 if {
272 log.msg.start
273 functions.len eputu " functions, " eputs label_c ++ eputu " labels\n" eputs
274 log.msg.start
275 global_var_context.len eputu " global variables, " eputs toplevel_constants.len eputu " constants\n" eputs
276 }
277
278 dump_ir r8 if {
279 ir_stream.dump
280 ret
281 }
282
283 verbose_mode r8 if {
284 log.msg.start
285 "dce pass started\n" eputs
286 }
287 log.time.start
288 stas.dce
289 "dce took " log.time.end
290 verbose_mode r8 if {
291 log.msg.start
292 used_functions eputu " used functions, of which " eputs inlined_functions eputu " are eligible for inline\n" eputs
293 log.msg.start
294 slits.len eputu " string literals\n" eputs
295 }
296
297 auto out_file_asm_sv 1
298
299 to_stdout r8 ! if {
300 out_file new_string_view
301 dup ".tmp" push_string_view
302 dup pop out_file_asm_sv
303
304 string_view_to_str fd_new_file_for_writing
305 pop fwrite_buffer.fd_loc
306 } else {
307 stdout pop fwrite_buffer.fd_loc
308 }
309
310 verbose_mode r8 if {
311 log.msg.start
312 "generating code from " eputs ir_stream.len eputu " IR instructions\n" eputs
313 }
314 log.time.start
315 in_file stas.gen
316 "gen took " log.time.end
317
318 to_stdout r8 if {
319 ret
320 }
321 verbose_mode r8 if {
322 log.msg.start
323 "generated " eputs
324
325 fwrite_buffer.fd_loc fd_stat_size
326
327 dup 1024 / 0 > if {
328 eputu " KiBs of code\n" eputs
329 } else {
330 eputu " bytes of code\n" eputs
331 }
332 }
333
334 fwrite_buffer.fd_loc close 0 <s if {
335 "FATAL: Failed to close file descriptor\n" eputs
336 1 exit
337 }
338 verbose_mode r8 if {
339 log.msg.start
340 "wrote code to `" eputs out_file_asm_sv string_view_to_str eputs "`\n" eputs
341 }
342
343 verbose_mode r8 if {
344 log.msg.start
345 "executing assembler backend `" eputs backend_type StasBackend.to_str eputs "`\n" eputs
346 }
347
348 log.time.start
349 out_file_asm_sv string_view_to_str out_file run_exec_arg 0 != execute_backend
350 "backend took " log.time.end
351
352 verbose_mode r8 if {
353 log.msg.start
354 "created binary `" eputs out_file eputs "`\n" eputs
355 }
356
357 debug_symbols r8 backend_type StasBackend.nasm = | if {
358 ret
359 }
360
361 run_exec_arg 0 != if {
362 reserve null_p sizeof(u64)
363 null_p NULL w64
364
365 auto argp 1
366
367 {
368 string_buffer string_buffer.len + pop argp
369
370 out_file drop string_buffer.generic_append_u64
371
372 run_exec_arg 1 +
373 while dup argc < {
374 dup sizeof(u64) * argv + r64 string_buffer.generic_append_u64
375 ++
376 }
377 drop
378
379 NULL string_buffer.generic_append_u64
380 }
381
382 out_file drop
383 argp
384 null_p
385
386 verbose_mode r8 if {
387 log.msg.start
388
389 "exceve binary `" eputs
390
391 argp
392 argp_print
393
394 "`\n" eputs
395 }
396
397 execve 0 <s if {
398 "FATAL: Could not execve file\n" eputs
399 1 exit
400 }
401 }
402}
View as plain text