summaryrefslogtreecommitdiff
path: root/boot/stage12.elna
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2025-09-18 13:01:00 +0200
committerEugen Wissner <belka@caraus.de>2025-09-18 13:01:00 +0200
commit1e97b660bf54da4a6df5f28363447d33b6058884 (patch)
treecc70dd9a1e5c82d5b733c7364aa011e8d15dcbff /boot/stage12.elna
parentc5f29861202836593b2d337c0bf800fe5b30c2e6 (diff)
downloadelna-1e97b660bf54da4a6df5f28363447d33b6058884.tar.gz
Support named local variables and parameters
Diffstat (limited to 'boot/stage12.elna')
-rw-r--r--boot/stage12.elna234
1 files changed, 201 insertions, 33 deletions
diff --git a/boot/stage12.elna b/boot/stage12.elna
index 98751bb..68f5592 100644
--- a/boot/stage12.elna
+++ b/boot/stage12.elna
@@ -4,6 +4,9 @@
(* Stage 12 compiler. *)
+(* - Local variables and parameters are saved in a local symbol table. *)
+(* - Local variables and parameters can be referenced by their name in the symbol table. *)
+
const
symbol_builtin_name_int := "Int";
symbol_builtin_name_word := "Word";
@@ -26,6 +29,7 @@ const
(* INFO_TYPE = 1 *)
(* INFO_PARAMETER = 2 *)
+ (* INFO_TEMPORARY = 3 *)
(* Type info has the type it belongs to. *)
symbol_type_info_int := S(1, @symbol_builtin_type_int);
@@ -722,11 +726,25 @@ end;
proc _compile_designator();
begin
+ v0 := _read_token();
+ v4 := _symbol_table_lookup(@symbol_table_local, source_code_position, v0);
+
+ if v4 <> 0 then
+ _write_z("\taddi t0, sp, \0");
+ v8 := _parameter_info_get_offset(v4);
+ _write_i(v8);
+ _write_c('\n');
+ _advance_token(v0);
+
+ goto .compile_designator_end;
+ end;
if _load_byte(source_code_position) = 'v' then
_compile_local_designator();
- else
- _compile_global_designator();
+ goto .compile_designator_end;
end;
+ _compile_global_designator();
+
+.compile_designator_end:
end;
proc _compile_assignment();
@@ -834,15 +852,15 @@ begin
_compile_call();
goto .compile_statement_semicolon;
end;
- if v0 = 'g' then
+ if _memcmp(source_code_position, "goto ", 5) = 0 then
_compile_goto();
goto .compile_statement_semicolon;
end;
- if v0 = 'i' then
+ if _memcmp(source_code_position, "if ", 3) = 0 then
_compile_if();
goto .compile_statement_semicolon;
end;
- if v0 = 'r' then
+ if _memcmp(source_code_position, "return ", 7) = 0 then
_compile_return_statement();
_write_c('\n');
@@ -891,6 +909,15 @@ begin
_write_c(v84);
end;
+proc _skip_spaces();
+begin
+ v0 := _load_byte(source_code_position);
+ if v0 = '\t' then
+ _advance_token(1);
+ _skip_spaces();
+ end;
+end;
+
proc _read_type_expression();
begin
v0 := _read_token();
@@ -900,13 +927,58 @@ end;
(* Parameters: *)
(* a0 - Parameter index. *)
-proc _create_parameter_info(v88: Word);
+proc _parameter_info_create(v88: Word);
begin
+ v8 := memory_free_pointer;
+ v4 := v8;
+ (* 2 is INFO_PARAMETER *)
+ _store_word(2, v4);
+
+ v4 := v4 + 4;
+
(* Calculate the stack offset: 88 - (4 * parameter_counter) *)
v0 := v88 * 4;
v0 := 88 + -v0;
+ _store_word(v0, v4);
- return v0
+ v4 := v4 + 4;
+ _store_word(v4, @memory_free_pointer);
+
+ return v8
+end;
+
+proc _parameter_info_get_offset(v88: Word);
+begin
+ v88 := v88 + 4;
+ return _load_word(v88)
+end;
+
+(* Parameters: *)
+
+(* a0 - Parameter index. *)
+proc _temporary_info_create(v88: Word);
+begin
+ v8 := memory_free_pointer;
+ v4 := v8;
+ (* 3 is INFO_TEMPORARY *)
+ _store_word(3, v4);
+
+ v4 := v4 + 4;
+
+ (* Calculate the stack offset: 4 * variable_counter. *)
+ v0 := v88 * 4;
+ _store_word(v0, v4);
+
+ v4 := v4 + 4;
+ _store_word(v4, @memory_free_pointer);
+
+ return v8
+end;
+
+proc _temporary_info_get_offset(v88: Word);
+begin
+ v88 := v88 + 4;
+ return _load_word(v88)
end;
(* Parameters: *)
@@ -915,6 +987,7 @@ end;
proc _read_procedure_parameter(v88: Word);
begin
(* Read the parameter name. *)
+ v8 := source_code_position;
v0 := _read_token();
_advance_token(v0);
@@ -927,8 +1000,10 @@ begin
_write_i(v88);
_write_z(", \0");
- (* Calculate the stack offset: 88 - (4 * parameter_counter) *)
- v4 := _create_parameter_info(v88);
+ v4 := _parameter_info_create(v88);
+ _symbol_table_enter(@symbol_table_local, v8, v0, v4);
+
+ v4 := _parameter_info_get_offset(v4);
_write_i(v4);
_write_z("(sp)\n\0");
@@ -954,10 +1029,52 @@ begin
_advance_token(1);
end;
+(* Parameters: *)
+(* a0 - Variable index. *)
+proc _read_procedure_temporary(v88: Word);
+begin
+ _skip_spaces();
+ v8 := source_code_position;
+
+ (* Read and skip variable name, colon and the space *)
+ v0 := _read_token();
+ _advance_token(v0 + 2);
+
+ _read_type_expression();
+
+ v4 := _temporary_info_create(v88);
+ _symbol_table_enter(@symbol_table_local, v8, v0, v4);
+
+ (* Skip semicolon and newline after the variable declaration *)
+ _advance_token(2);
+end;
+
+proc _read_procedure_temporaries();
+begin
+ if _memcmp(source_code_position, "var", 3) <> 0 then
+ goto .read_local_variables_end;
+ end;
+ _advance_token(4);
+ v0 := 0;
+
+.read_local_variables_loop:
+ if _memcmp(source_code_position, "begin", 5) = 0 then
+ goto .read_local_variables_end;
+ end;
+ _read_procedure_temporary(v0);
+
+ v0 := v0 + 1;
+ goto .read_local_variables_loop;
+
+.read_local_variables_end:
+end;
+
proc _compile_procedure();
begin
(* Skip "proc ". *)
_advance_token(5);
+ (* Clear local symbol table. *)
+ _store_word(0, @symbol_table_local);
(* Save the procedure name length. *)
v0 := _read_token();
@@ -977,8 +1094,12 @@ begin
_write_z("\taddi sp, sp, -128\n\tsw ra, 124(sp)\n\tsw s0, 120(sp)\n\taddi s0, sp, 128\n\0");
_read_procedure_parameters();
+ (* Skip semicolon and newline. *)
+ _advance_token(2);
+ _read_procedure_temporaries();
+
(* Skip semicolon, "begin" and newline. *)
- _advance_token(8);
+ _advance_token(6);
_compile_procedure_body();
@@ -989,15 +1110,6 @@ begin
_advance_token(5);
end;
-proc _skip_spaces();
-begin
- v0 := _load_byte(source_code_position);
- if v0 = '\t' then
- _advance_token(1);
- _skip_spaces();
- end;
-end;
-
(* Prints and skips a line. *)
proc _skip_comment();
begin
@@ -1277,37 +1389,93 @@ begin
_syscall(0, 0, 0, 0, 0, 0, 93);
end;
+(* Looks for a symbol in the given symbol table. *)
+
+(* Parameters: *)
+(* a0 - Symbol table. *)
+(* a1 - Symbol name pointer. *)
+(* a2 - Symbol name length. *)
+
+(* Returns the symbol pointer or 0 in a0. *)
+proc _symbol_table_lookup(v88: Word, v84: Word, v80: Word);
+begin
+ v0 := 0;
+
+ (* The first word in the symbol table is its length, get it. *)
+ v4 := _load_word(v88);
+
+ (* Go to the first symbol position. *)
+ v88 := v88 + 4;
+
+ .symbol_table_lookup_loop;
+ if v4 = 0 then
+ goto .symbol_table_lookup_end;
+ end;
+
+ (* Symbol name pointer and length. *)
+ v8 := _load_word(v88);
+ v12 := _load_word(v88 + 4);
+
+ (* If lengths don't match, exit and return nil. *)
+ if v80 <> v12 then
+ goto .symbol_table_lookup_repeat;
+ end;
+ (* If names don't match, exit and return nil. *)
+ if _memcmp(v84, v8, v80) <> 0 then
+ goto .symbol_table_lookup_repeat;
+ end;
+ (* Otherwise, the symbol is found. *)
+ v0 := _load_word(v88 + 8);
+ goto .symbol_table_lookup_end;
+
+ .symbol_table_lookup_repeat;
+ v88 := v88 + 12;
+ v4 := v4 + -1;
+ goto .symbol_table_lookup_loop;
+
+ .symbol_table_lookup_end;
+ return v0
+end;
+
(* Inserts a symbol into the table. *)
(* Parameters: *)
-(* a0 - Symbol pointer. *)
-(* a1 - Symbol name length. *)
-(* a2 - Symbol name pointer. *)
-(* a3 - Symbol table. *)
+(* a0 - Symbol table. *)
+(* a1 - Symbol name pointer. *)
+(* a2 - Symbol name length. *)
+(* a3 - Symbol pointer. *)
proc _symbol_table_enter(v88: Word, v84: Word, v80: Word, v76: Word);
begin
(* The first word in the symbol table is its length, get it. *)
- v0 := _load_word(v76);
+ v0 := _load_word(v88);
(* Calculate the offset for the new symbol. *)
- v4 := v0 * 4;
+ v4 := v0 * 12;
v4 := v4 + 4;
- v4 := v76 + 4;
+ v4 := v88 + v4;
- _memcpy(v4, @v80, 12);
+ _store_word(v84, v4);
+ v4 := v4 + 4;
+ _store_word(v80, v4);
+ v4 := v4 + 4;
+ _store_word(v76, v4);
(* Increment the symbol table length. *)
v0 := v0 + 1;
- _store_word(v0, v76);
+ _store_word(v0, v88);
end;
proc _symbol_table_build();
begin
- _symbol_table_enter(@symbol_type_info_int, 3, symbol_builtin_name_int, @symbol_table_global);
- _symbol_table_enter(@symbol_type_info_word, 4, symbol_builtin_name_word, @symbol_table_global);
- _symbol_table_enter(@symbol_type_info_pointer, 7, symbol_builtin_name_pointer, @symbol_table_global);
- _symbol_table_enter(@symbol_type_info_char, 4, symbol_builtin_name_char, @symbol_table_global);
- _symbol_table_enter(@symbol_type_info_bool, 4, symbol_builtin_name_bool, @symbol_table_global);
+ (* Set the table length to 0. *)
+ _store_word(0, @symbol_table_global);
+
+ (* Enter built-in symbols. *)
+ _symbol_table_enter(@symbol_table_global, symbol_builtin_name_int, 3, @symbol_type_info_int);
+ _symbol_table_enter(@symbol_table_global, symbol_builtin_name_word, 4, @symbol_type_info_word);
+ _symbol_table_enter(@symbol_table_global, symbol_builtin_name_pointer, 7, @symbol_type_info_pointer);
+ _symbol_table_enter(@symbol_table_global, symbol_builtin_name_char, 4, @symbol_type_info_char);
+ _symbol_table_enter(@symbol_table_global, symbol_builtin_name_bool, 4, @symbol_type_info_bool);
end;