aboutsummaryrefslogtreecommitdiff
path: root/source/main.elna
diff options
context:
space:
mode:
Diffstat (limited to 'source/main.elna')
-rw-r--r--source/main.elna912
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.