diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-10-04 00:51:52 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-10-04 00:51:52 +0200 |
| commit | 8a6ed3a4ddf9c4e16bb4ddc3b8c5094bb937598b (patch) | |
| tree | 18198be391a5fd4b10421c1850f1046b3c2e12c4 /source/main.elna | |
| parent | e4ce7f658741a7428597da4872435a1b0bae944c (diff) | |
| download | elna-8a6ed3a4ddf9c4e16bb4ddc3b8c5094bb937598b.tar.gz | |
Update the old compiler with the new syntax
Diffstat (limited to 'source/main.elna')
| -rw-r--r-- | source/main.elna | 912 |
1 files changed, 119 insertions, 793 deletions
diff --git a/source/main.elna b/source/main.elna index 26853c3..6049362 100644 --- a/source/main.elna +++ b/source/main.elna @@ -4,813 +4,139 @@ program(parameters) import - cstdio, cstdlib, cstring, cctype, common, command_line_interface, lexer - -type - SourceFile* = record - buffer: [1024]Word8; - handle: ^FILE; - size: Word; - index: Word - end - StringBuffer* = record - data: ^Word8; - size: Word; - capacity: Word - end - SourceCode#[T] = record - position: ElnaLocation; - - input: ^T; - empty: proc(stream: ^T) -> Bool; - advance: proc(stream: ^T); - head: proc(stream: ^T) -> Word8 - end - Tokenizer* = record - length: Word; - data: ^^ElnaLexerToken - end - -(* - Standard procedures. -*) -proc string_dup(origin: []const Word8) -> []const Word8 -var - copy: ^Word8 -begin - copy := malloc#[Word8](origin.length); - strncpy(copy, origin.ptr, origin.length) -return copy[1 to origin.length] - -proc string_buffer_new() -> StringBuffer -var - result: StringBuffer -begin - result.capacity := 64u; - result.data := malloc#[Word8](result.capacity); - result.size := 0u -return result - -proc string_buffer_push(buffer: ^StringBuffer; char: Word8) -begin - if buffer^.size >= buffer^.capacity then - buffer^.capacity := buffer^.capacity + 1024u; - buffer^.data := realloc(buffer^.data, buffer^.capacity) - end; - cast(buffer^.data + buffer^.size: ^Word8)^ := cast(char: Word8); - buffer^.size := buffer^.size + 1u -return - -proc string_buffer_pop(buffer: ^StringBuffer; count: Word) -begin - buffer^.size := buffer^.size - count -return - -proc string_buffer_clear(buffer: ^StringBuffer) -> []const Word8 -var - result: []const Word8 -begin - result := cast(buffer^.data: ^Word8)[1 to buffer^.size]; - buffer^.size := 0u + 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 -(* - Source code stream procedures. -*) - -proc read_source(filename: ^Word8) -> ^SourceFile -var - result: ^SourceFile - file_handle: ^FILE -begin - file_handle := fopen(filename, "rb\0".ptr); - - if file_handle <> nil then - result := malloc#[SourceFile](#size(SourceFile)); - result^.handle := file_handle; - result^.size := 0u; - result^.index := 1u - end -return result - -proc source_file_empty(source_input: ^SourceFile) -> Bool - if source_input^.index > source_input^.size then - source_input^.size := fread(source_input^.buffer.ptr, 1u, 1024u, source_input^.handle); - source_input^.index := 1u - end -return source_input^.size = 0u - -proc source_file_head(source_input: ^SourceFile) -> Word8 -return source_input^.buffer[source_input^.index] - -proc source_file_advance(source_input: ^SourceFile) - source_input^.index := source_input^.index + 1u -return - -proc source_code_empty#[T](source_code: ^SourceCode#[T]) -> Bool -return source_code^.empty(source_code^.input) - -proc source_code_head#[T](source_code: SourceCode#[T]) -> Word8 -return source_code.head(source_code.input) - -proc source_code_advance#[T](source_code: ^SourceCode#[T]) -begin - source_code^.advance(source_code^.input); - source_code^.position.column := source_code^.position.column -return - -proc source_code_break#[T](source_code: ^SourceCode#[T]) -begin - source_code^.position.line := source_code^.position.line + 1u; - source_code^.position.column := 0u -return - -proc source_code_expect#[T](source_code: ^SourceCode#[T]; expected: Word8) -> Bool -return ~source_code_empty(source_code) & source_code_head(source_code^) = expected - -(* - Token procedures. -*) - -proc lexer_escape(escape: Word8; result: ^Word8) -> Bool -var - successful: Bool -begin - case escape of - 'n': - result^ := '\n'; - successful := true - | 't': - result^ := '\t'; - successful := true - | 'f': - result^ := '\f'; - successful := true - | 'r': - result^ := '\r'; - successful := true - | 'v': - result^ := '\v'; - successful := true - | '\\': - result^ := '\\'; - successful := true - | '\'': - result^ := '\''; - successful := true - | '"': - result^ := '"'; - successful := true - | '0': - result^ := '\0'; - successful := true - else - successful := false - end -return successful - -(* Skip spaces. *) -proc lexer_spaces#[T](source_code: ^SourceCode#[T]) -var - current: Word8 -begin - while ~source_code_empty(source_code) & isspace(cast(source_code_head(source_code^): Int)) <> 0 do - current := source_code_head(source_code^); - - if current = '\n' then - source_code_break(source_code) - end; - source_code_advance(source_code) - end -return - -(* Checker whether the character is allowed in an identificator. *) -proc lexer_is_ident(char: Word8) -> Bool -return isalnum(cast(char: Int)) <> 0 or char = '_' - -proc lexer_identifier#[T](source_code: ^SourceCode#[T]; token_content: ^StringBuffer) -var - content_length: Word -begin - while ~source_code_empty(source_code) & lexer_is_ident(source_code_head(source_code^)) do - string_buffer_push(token_content, source_code_head(source_code^)); - source_code_advance(source_code) - end -return - -proc lexer_comment#[T](source_code: ^SourceCode#[T]; token_content: ^StringBuffer) -> Bool -var - trailing: Word -begin - trailing := 0u; - - while ~source_code_empty(source_code) & trailing < 2u do - if source_code_head(source_code^) = '*' then - string_buffer_push(token_content, '*'); - trailing := 1u - elsif source_code_head(source_code^) = ')' & trailing = 1u then - string_buffer_pop(token_content, 1u); - trailing := 2u - else - string_buffer_push(token_content, source_code_head(source_code^)); - trailing := 0u - end; - source_code_advance(source_code) - end -return trailing = 2u - -proc lexer_character#[T](source_code: ^SourceCode#[T]; token_content: ^Word8) -> Bool -var - successful: Bool -begin - successful := ~source_code_empty(source_code); - - if successful then - if source_code_head(source_code^) = '\\' then - source_code_advance(source_code); - - successful := ~source_code_empty(source_code) & lexer_escape(source_code_head(source_code^), token_content) - else - token_content^ := source_code_head(source_code^); - successful := true - end - end; - if successful then - source_code_advance(source_code) - end -return successful - -proc lexer_string#[T](source_code: ^SourceCode#[T]; token_content: ^StringBuffer) -> Bool +proc print_errors(error_list: ^ElnaList) var - token_end, constructed_string: ^Word8 - token_length: Word - is_valid: Bool := true - next_char: Word8 -begin - while is_valid & ~source_code_empty(source_code) & source_code_head(source_code^) <> '"' do - is_valid := lexer_character(source_code, @next_char); - - if is_valid then - string_buffer_push(token_content, next_char) - end - end; - - if is_valid & source_code_expect(source_code, '"') then - source_code_advance(source_code) - else - is_valid := false - end -return is_valid - -proc lexer_number#[T](source_code: ^SourceCode#[T]; token_content: ^Int) + node: ^ElnaListNode begin - token_content^ := 0; - - while ~source_code_empty(source_code) & isdigit(cast(source_code_head(source_code^): Int)) <> 0 do - token_content^ := token_content^ * 10 + (cast(source_code_head(source_code^): Int) - cast('0': Int)); - - source_code_advance(source_code) - end + node := error_list^.first; + while node <> nil do + elna_error_print(cast(node: ^ElnaError)); + node := node^.next + end return -(* Categorize an identifier. *) -proc lexer_categorize(token_content: []const Word8) -> ^ElnaLexerToken -var - current_token: ^ElnaLexerToken -begin - if token_content = "if" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._if - elsif token_content = "then" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._then - elsif token_content = "else" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._else - elsif token_content = "elsif" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._elsif - elsif token_content = "while" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._while - elsif token_content = "do" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._do - elsif token_content = "proc" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._proc - elsif token_content = "begin" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._begin - elsif token_content = "end" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._end - elsif token_content = "extern" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._extern - elsif token_content = "const" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._const - elsif token_content = "var" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._var - elsif token_content = "case" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._case - elsif token_content = "of" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._of - elsif token_content = "type" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._type - elsif token_content = "record" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._record - elsif token_content = "true" then - current_token := malloc#[ElnaLexerBooleanToken](#size(ElnaLexerBooleanToken)); - current_token^.kind := ElnaLexerKind.boolean; - cast(current_token: ^ElnaLexerBooleanToken)^.value := true - elsif token_content = "false" then - current_token := malloc#[ElnaLexerBooleanToken](#size(ElnaLexerBooleanToken)); - current_token^.kind := ElnaLexerKind.boolean; - cast(current_token: ^ElnaLexerBooleanToken)^.value := false - elsif token_content = "nil" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.null - elsif token_content = "or" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._or - elsif token_content = "return" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._return - elsif token_content = "cast" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._cast - elsif token_content = "defer" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._defer - elsif token_content = "import" then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind._import - else - current_token := malloc#[ElnaLexerStringToken](#size(ElnaLexerStringToken)); - current_token^.kind := ElnaLexerKind.identifier; - cast(current_token: ^ElnaLexerStringToken)^.value := string_dup(token_content) - end -return current_token - -proc lexer_add_token(lexer: ^Tokenizer; token: ^ElnaLexerToken) -var - new_length: Word -begin - new_length := lexer^.length + 1u; - lexer^.data := realloc#[^ElnaLexerToken](lexer^.data, new_length * #size(^ElnaLexerToken)); - (lexer^.data + lexer^.length)^ := token; - lexer^.length := new_length -return - -(* Read the next token from the input. *) -proc lexer_next#[T](source_code: SourceCode#[T]; token_buffer: ^StringBuffer) -> ^ElnaLexerToken -var - current_token: ^ElnaLexerToken := nil - first_char: Word8 -begin - first_char := source_code_head(source_code); - - if isalpha(cast(first_char: Int)) <> 0 or first_char = '_' then - lexer_identifier(@source_code, token_buffer); - current_token := lexer_categorize(string_buffer_clear(token_buffer)) - elsif first_char = '#' then - source_code_advance(@source_code); - lexer_identifier(@source_code, token_buffer); - - current_token := malloc#[ElnaLexerStringToken](#size(ElnaLexerStringToken)); - current_token^.kind := ElnaLexerKind.trait; - cast(current_token: ^ElnaLexerStringToken)^.value := string_dup(string_buffer_clear(token_buffer)) - elsif isdigit(cast(first_char: Int)) <> 0 then - current_token := malloc#[ElnaLexerIntegerToken](#size(ElnaLexerIntegerToken)); - lexer_number(@source_code, @cast(current_token: ^ElnaLexerIntegerToken)^.value); - - if source_code_expect(@source_code, 'u') then - current_token^.kind := ElnaLexerKind.word; - source_code_advance(@source_code) - else - current_token^.kind := ElnaLexerKind.integer - end - elsif first_char = '(' then - source_code_advance(@source_code); - - if source_code_empty(@source_code) then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.left_paren - elsif source_code_head(source_code) = '*' then - source_code_advance(@source_code); - - if lexer_comment(@source_code, token_buffer) then - current_token := malloc#[ElnaLexerStringToken](#size(ElnaLexerStringToken)); - cast(current_token: ^ElnaLexerStringToken)^.value := string_dup(string_buffer_clear(token_buffer)); - current_token^.kind := ElnaLexerKind.comment - end - else - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.left_paren - end - elsif first_char = ')' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.right_paren; - source_code_advance(@source_code) - elsif first_char = '{' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.left_brace; - source_code_advance(@source_code) - elsif first_char = '}' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.right_brace; - source_code_advance(@source_code) - elsif first_char = '\'' then - source_code_advance(@source_code); - - if lexer_character(@source_code, @first_char) & source_code_expect(@source_code, '\'') then - current_token := malloc#[ElnaLexerCharacterToken](#size(ElnaLexerCharacterToken)); - current_token^.kind := ElnaLexerKind.character; - cast(current_token: ^ElnaLexerCharacterToken)^.value := first_char; - source_code_advance(@source_code) - end - elsif first_char = '"' then - source_code_advance(@source_code); - - if lexer_string(@source_code, token_buffer) then - current_token := malloc#[ElnaLexerStringToken](#size(ElnaLexerStringToken)); - current_token^.kind := ElnaLexerKind.string; - cast(current_token: ^ElnaLexerStringToken)^.value := string_dup(string_buffer_clear(token_buffer)) - end - elsif first_char = '[' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.left_square; - source_code_advance(@source_code) - elsif first_char = ']' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.right_square; - source_code_advance(@source_code) - elsif first_char = '>' then - source_code_advance(@source_code); - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - - if source_code_empty(@source_code) then - current_token^.kind := ElnaLexerKind.greater_than - elsif source_code_head(source_code) = '=' then - current_token^.kind := ElnaLexerKind.greater_equal; - source_code_advance(@source_code) - elsif source_code_head(source_code) = '>' then - current_token^.kind := ElnaLexerKind.shift_right; - source_code_advance(@source_code) - else - current_token^.kind := ElnaLexerKind.greater_than - end - elsif first_char = '<' then - source_code_advance(@source_code); - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - - if source_code_empty(@source_code) then - current_token^.kind := ElnaLexerKind.less_than - elsif source_code_head(source_code) = '=' then - current_token^.kind := ElnaLexerKind.less_equal; - source_code_advance(@source_code) - elsif source_code_head(source_code) = '<' then - current_token^.kind := ElnaLexerKind.shift_left; - source_code_advance(@source_code) - elsif source_code_head(source_code) = '>' then - current_token^.kind := ElnaLexerKind.not_equal; - source_code_advance(@source_code) - else - current_token^.kind := ElnaLexerKind.less_than - end - elsif first_char = '=' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.equals; - source_code_advance(@source_code) - elsif first_char = ';' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.semicolon; - source_code_advance(@source_code) - elsif first_char = '.' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.dot; - source_code_advance(@source_code) - elsif first_char = ',' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.comma; - source_code_advance(@source_code) - elsif first_char = '+' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.plus; - source_code_advance(@source_code) - elsif first_char = '-' then - source_code_advance(@source_code); - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - - if source_code_empty(@source_code) then - current_token^.kind := ElnaLexerKind.minus - elsif source_code_head(source_code) = '>' then - current_token^.kind := ElnaLexerKind.arrow; - source_code_advance(@source_code) - else - current_token^.kind := ElnaLexerKind.minus - end - elsif first_char = '*' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.multiplication; - source_code_advance(@source_code) - elsif first_char = '/' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.division; - source_code_advance(@source_code) - elsif first_char = '%' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.remainder; - source_code_advance(@source_code) - elsif first_char = ':' then - source_code_advance(@source_code); - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - - if source_code_empty(@source_code) then - current_token^.kind := ElnaLexerKind.colon - elsif source_code_head(source_code) = '=' then - current_token^.kind := ElnaLexerKind.assignment; - source_code_advance(@source_code) - else - current_token^.kind := ElnaLexerKind.colon - end - elsif first_char = '^' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.hat; - source_code_advance(@source_code) - elsif first_char = '@' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.at; - source_code_advance(@source_code) - elsif first_char = '!' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.exclamation; - source_code_advance(@source_code) - elsif first_char = '&' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.and; - source_code_advance(@source_code) - elsif first_char = '~' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.not; - source_code_advance(@source_code) - elsif first_char = '|' then - current_token := malloc#[ElnaLexerToken](#size(ElnaLexerToken)); - current_token^.kind := ElnaLexerKind.pipe; - source_code_advance(@source_code) - end -return current_token - -(* Split the source text into tokens. *) -proc lexer_text#[T](source_code: SourceCode#[T]) -> Tokenizer -var - current_token: ^ElnaLexerToken - token_buffer: StringBuffer - lexer: Tokenizer -begin - lexer := Tokenizer{ length: 0u, data: nil }; - token_buffer := string_buffer_new(); - - lexer_spaces(@source_code); - - while ~source_code_empty(@source_code) do - current_token := lexer_next(source_code, @token_buffer); - - if current_token <> nil then - lexer_add_token(@lexer, current_token); - lexer_spaces(@source_code) - else - write_s("Lexical analysis error on \""); - write_c(source_code_head(source_code)); - write_s("\".\n") - end - end -return lexer - -(* - Parser. -*) - -proc parse(tokens: ^^ElnaLexerToken; tokens_size: Word) -var - current_token: ^ElnaLexerToken - i: Word := 0u -begin - while i < tokens_size do - current_token := (tokens + i)^; - - case current_token^.kind of - ElnaLexerKind._if: - write_s("IF") - | ElnaLexerKind._then: - write_s("THEN") - | ElnaLexerKind._else: - write_s("ELSE") - | ElnaLexerKind._elsif: - write_s("ELSIF") - | ElnaLexerKind._while: - write_s("WHILE") - | ElnaLexerKind._do: - write_s("DO") - | ElnaLexerKind._proc: - write_s("PROC") - | ElnaLexerKind._begin: - write_s("BEGIN") - | ElnaLexerKind._end: - write_s("END") - | ElnaLexerKind._extern: - write_s("EXTERN") - | ElnaLexerKind._const: - write_s("CONST") - | ElnaLexerKind._var: - write_s("VAR") - | ElnaLexerKind._case: - write_s("CASE") - | ElnaLexerKind._of: - write_s("OF") - | ElnaLexerKind._type: - write_s("TYPE") - | ElnaLexerKind._record: - write_s("RECORD") - | ElnaLexerKind.pipe: - write_s("|") - | ElnaLexerKind.boolean: - write_s("BOOLEAN<"); - write_b(cast(current_token: ^ElnaLexerBooleanToken)^.value); - write_c('>') - | ElnaLexerKind.null: - write_s("NIL") - | ElnaLexerKind.and: - write_s("&") - | ElnaLexerKind._or: - write_s("OR") - | ElnaLexerKind.not: - write_s("~") - | ElnaLexerKind._return: - write_s("RETURN") - | ElnaLexerKind._cast: - write_s("CAST") - | ElnaLexerKind.shift_left: - write_s("<<") - | ElnaLexerKind.shift_right: - write_s(">>") - | ElnaLexerKind.identifier: - write_c('<'); - write_s(cast(current_token: ^ElnaLexerStringToken)^.value); - write_c('>') - | ElnaLexerKind.trait: - write_c('#'); - write_s(cast(current_token: ^ElnaLexerStringToken)^.value) - | ElnaLexerKind.left_paren: - write_s("(") - | ElnaLexerKind.right_paren: - write_s(")") - | ElnaLexerKind.left_square: - write_s("[") - | ElnaLexerKind.right_square: - write_s("]") - | ElnaLexerKind.greater_equal: - write_s(">=") - | ElnaLexerKind.less_equal: - write_s("<=") - | ElnaLexerKind.greater_than: - write_s(">") - | ElnaLexerKind.less_than: - write_s("<") - | ElnaLexerKind.equals: - write_s("=") - | ElnaLexerKind.not_equal: - write_s("<>") - | ElnaLexerKind.semicolon: - write_c(';') - | ElnaLexerKind.dot: - write_c('.') - | ElnaLexerKind.comma: - write_c(',') - | ElnaLexerKind.plus: - write_c('+') - | ElnaLexerKind.minus: - write_c('-') - | ElnaLexerKind.multiplication: - write_c('*') - | ElnaLexerKind.division: - write_c('/') - | ElnaLexerKind.remainder: - write_c('%') - | ElnaLexerKind.assignment: - write_s(":=") - | ElnaLexerKind.colon: - write_c(':') - | ElnaLexerKind.hat: - write_c('^') - | ElnaLexerKind.at: - write_c('@') - | ElnaLexerKind.comment: - write_s("(* COMMENT *)") - | ElnaLexerKind.integer: - write_c('<'); - write_i(cast(current_token: ^ElnaLexerIntegerToken)^.value); - write_c('>') - | ElnaLexerKind.word: - write_c('<'); - write_i(cast(current_token: ^ElnaLexerIntegerToken)^.value); - write_s("u>") - | ElnaLexerKind.character: - write_c('<'); - write_i(cast(cast(current_token: ^ElnaLexerCharacterToken)^.value: Int)); - write_s("c>") - | ElnaLexerKind.string: - write_s("\"...\"") - | ElnaLexerKind._defer: - write_s("DEFER") - | ElnaLexerKind.exclamation: - write_c('!') - | ElnaLexerKind.arrow: - write_s("->") - | ElnaLexerKind._import: - write_s("IMPORT") - else - write_s("UNKNOWN<"); - write_i(cast(current_token^.kind: Int)); - write_c('>') - end; - write_c(' '); - - i := i + 1u - end; - write_c('\n') -return - -(* - Compilation entry. -*) - -proc compile_in_stages#[T](command_line: ^CommandLine; source_code: SourceCode#[T]) -> Int -var - return_code: Int := 0 - lexer: Tokenizer -begin - if command_line^.lex or command_line^.parse then - lexer := lexer_text(source_code) - end; - if command_line^.parse then - parse(lexer.data, lexer.length) - end -return return_code - -proc process(argc: Int; argv: ^^Word8) -> Int -var - tokens: ^ElnaLexerToken - tokens_size: Word - source_code: SourceCode#[SourceFile] - command_line: ^CommandLine - return_code: Int := 0 - source_file: ^SourceFile -begin - command_line := parse_command_line(argc, argv); - if command_line = nil then - return_code := 2 - end; - - if return_code = 0 then - source_file := read_source(command_line^.input); - - if source_file = nil then - perror(command_line^.input); - return_code := 3 - end - end; - - if return_code = 0 then - defer - fclose(source_file^.handle) - end; - - source_code.position := ElnaLocation{line: 1u, column: 1u}; - source_code.input := source_file; - source_code.empty := source_file_empty; - source_code.head := source_file_head; - source_code.advance := source_file_advance; - - return_code := compile_in_stages(command_line, source_code) - end +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(); + initialize_global_state(); - exit(process(cast(parameters.length: Int), parameters.ptr)) + exit(process(cast(parameters.length: Int), parameters.ptr)) end. |
