Support named local variables and parameters

This commit is contained in:
2025-09-18 13:01:00 +02:00
parent c5f2986120
commit 1e97b660bf
2 changed files with 2238 additions and 33 deletions

View File

@@ -4,6 +4,9 @@
(* Stage 12 compiler. *) (* 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 const
symbol_builtin_name_int := "Int"; symbol_builtin_name_int := "Int";
symbol_builtin_name_word := "Word"; symbol_builtin_name_word := "Word";
@@ -26,6 +29,7 @@ const
(* INFO_TYPE = 1 *) (* INFO_TYPE = 1 *)
(* INFO_PARAMETER = 2 *) (* INFO_PARAMETER = 2 *)
(* INFO_TEMPORARY = 3 *)
(* Type info has the type it belongs to. *) (* Type info has the type it belongs to. *)
symbol_type_info_int := S(1, @symbol_builtin_type_int); symbol_type_info_int := S(1, @symbol_builtin_type_int);
@@ -722,11 +726,25 @@ end;
proc _compile_designator(); proc _compile_designator();
begin 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 if _load_byte(source_code_position) = 'v' then
_compile_local_designator(); _compile_local_designator();
else goto .compile_designator_end;
_compile_global_designator();
end; end;
_compile_global_designator();
.compile_designator_end:
end; end;
proc _compile_assignment(); proc _compile_assignment();
@@ -834,15 +852,15 @@ begin
_compile_call(); _compile_call();
goto .compile_statement_semicolon; goto .compile_statement_semicolon;
end; end;
if v0 = 'g' then if _memcmp(source_code_position, "goto ", 5) = 0 then
_compile_goto(); _compile_goto();
goto .compile_statement_semicolon; goto .compile_statement_semicolon;
end; end;
if v0 = 'i' then if _memcmp(source_code_position, "if ", 3) = 0 then
_compile_if(); _compile_if();
goto .compile_statement_semicolon; goto .compile_statement_semicolon;
end; end;
if v0 = 'r' then if _memcmp(source_code_position, "return ", 7) = 0 then
_compile_return_statement(); _compile_return_statement();
_write_c('\n'); _write_c('\n');
@@ -891,6 +909,15 @@ begin
_write_c(v84); _write_c(v84);
end; 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(); proc _read_type_expression();
begin begin
v0 := _read_token(); v0 := _read_token();
@@ -900,13 +927,58 @@ end;
(* Parameters: *) (* Parameters: *)
(* a0 - Parameter index. *) (* a0 - Parameter index. *)
proc _create_parameter_info(v88: Word); proc _parameter_info_create(v88: Word);
begin 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) *) (* Calculate the stack offset: 88 - (4 * parameter_counter) *)
v0 := v88 * 4; v0 := v88 * 4;
v0 := 88 + -v0; 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; end;
(* Parameters: *) (* Parameters: *)
@@ -915,6 +987,7 @@ end;
proc _read_procedure_parameter(v88: Word); proc _read_procedure_parameter(v88: Word);
begin begin
(* Read the parameter name. *) (* Read the parameter name. *)
v8 := source_code_position;
v0 := _read_token(); v0 := _read_token();
_advance_token(v0); _advance_token(v0);
@@ -927,8 +1000,10 @@ begin
_write_i(v88); _write_i(v88);
_write_z(", \0"); _write_z(", \0");
(* Calculate the stack offset: 88 - (4 * parameter_counter) *) v4 := _parameter_info_create(v88);
v4 := _create_parameter_info(v88); _symbol_table_enter(@symbol_table_local, v8, v0, v4);
v4 := _parameter_info_get_offset(v4);
_write_i(v4); _write_i(v4);
_write_z("(sp)\n\0"); _write_z("(sp)\n\0");
@@ -954,10 +1029,52 @@ begin
_advance_token(1); _advance_token(1);
end; 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(); proc _compile_procedure();
begin begin
(* Skip "proc ". *) (* Skip "proc ". *)
_advance_token(5); _advance_token(5);
(* Clear local symbol table. *)
_store_word(0, @symbol_table_local);
(* Save the procedure name length. *) (* Save the procedure name length. *)
v0 := _read_token(); 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"); _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(); _read_procedure_parameters();
(* Skip semicolon and newline. *)
_advance_token(2);
_read_procedure_temporaries();
(* Skip semicolon, "begin" and newline. *) (* Skip semicolon, "begin" and newline. *)
_advance_token(8); _advance_token(6);
_compile_procedure_body(); _compile_procedure_body();
@@ -989,15 +1110,6 @@ begin
_advance_token(5); _advance_token(5);
end; 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. *) (* Prints and skips a line. *)
proc _skip_comment(); proc _skip_comment();
begin begin
@@ -1277,37 +1389,93 @@ begin
_syscall(0, 0, 0, 0, 0, 0, 93); _syscall(0, 0, 0, 0, 0, 0, 93);
end; 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. *) (* Inserts a symbol into the table. *)
(* Parameters: *) (* Parameters: *)
(* a0 - Symbol pointer. *) (* a0 - Symbol table. *)
(* a1 - Symbol name length. *) (* a1 - Symbol name pointer. *)
(* a2 - Symbol name pointer. *) (* a2 - Symbol name length. *)
(* a3 - Symbol table. *) (* a3 - Symbol pointer. *)
proc _symbol_table_enter(v88: Word, v84: Word, v80: Word, v76: Word); proc _symbol_table_enter(v88: Word, v84: Word, v80: Word, v76: Word);
begin begin
(* The first word in the symbol table is its length, get it. *) (* 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. *) (* Calculate the offset for the new symbol. *)
v4 := v0 * 4; v4 := v0 * 12;
v4 := v4 + 4; 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. *) (* Increment the symbol table length. *)
v0 := v0 + 1; v0 := v0 + 1;
_store_word(v0, v76); _store_word(v0, v88);
end; end;
proc _symbol_table_build(); proc _symbol_table_build();
begin begin
_symbol_table_enter(@symbol_type_info_int, 3, symbol_builtin_name_int, @symbol_table_global); (* Set the table length to 0. *)
_symbol_table_enter(@symbol_type_info_word, 4, symbol_builtin_name_word, @symbol_table_global); _store_word(0, @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); (* Enter built-in symbols. *)
_symbol_table_enter(@symbol_type_info_bool, 4, symbol_builtin_name_bool, @symbol_table_global); _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; end;

2037
boot/stage13.elna Normal file

File diff suppressed because it is too large Load Diff