Support named local variables and parameters
This commit is contained in:
@@ -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
2037
boot/stage13.elna
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user