diff options
| author | Eugen Wissner <belka@caraus.de> | 2025-09-18 13:01:00 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2025-09-18 13:01:00 +0200 |
| commit | 1e97b660bf54da4a6df5f28363447d33b6058884 (patch) | |
| tree | cc70dd9a1e5c82d5b733c7364aa011e8d15dcbff /boot/stage12.elna | |
| parent | c5f29861202836593b2d337c0bf800fe5b30c2e6 (diff) | |
| download | elna-1e97b660bf54da4a6df5f28363447d33b6058884.tar.gz | |
Support named local variables and parameters
Diffstat (limited to 'boot/stage12.elna')
| -rw-r--r-- | boot/stage12.elna | 234 |
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; |
