(* 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.