diff --git a/boot/stage15.elna b/boot/stage15.elna index d317c5c..d3e157a 100644 --- a/boot/stage15.elna +++ b/boot/stage15.elna @@ -150,22 +150,19 @@ type type_declaration, module_declaration ); - InfoKind = (type_info, parameter_info, temporary_info); + InfoKind = (type_info, parameter_info, temporary_info, procedure_info); TypeKind = (primitive, enumeration); var - source_code: Array; - compiler_strings: Array; symbol_table_global: Array; - symbol_table_local: Array; + compiler_strings: Array; classification: Array; - (* To reserve memory just add the value of needed bytes to the memory_free_pointer variable. *) - memory: Array; - + source_code: Word; compiler_strings_position: Word; compiler_strings_length: Word; label_counter: Word; + symbol_table_store: Word; (* Points to a segment of free memory. *) memory_free_pointer: Word; @@ -245,6 +242,15 @@ proc _read_file(buffer: Word, size: Word); return _syscall(0, buffer, size, 0, 0, 0, 63) end; +(** + * MAP_ANONYMOUS is 32. + * PROT_READ | PORT_WRITE is (1 | 2). + * MAP_ANONYMOUS | MAP_PRIVATE is (32 | 2) + *) +proc _mmap(length: Word); + return _syscall(0, length, 1 or 2, 32 or 2, -1, 0, 222) +end; + (** * Writes to the standard output. * @@ -363,7 +369,6 @@ begin rhs := character <= 'Z'; return lhs & rhs - end; (** @@ -537,9 +542,10 @@ var integer_token: Word; integer_length: Word; result: Word; + literal_size: Word; begin - result := memory_free_pointer; - memory_free_pointer := memory_free_pointer + 12; + literal_size := _integer_literal_node_size(); + result := _allocate(literal_size); integer_token := _lexer_global_get_start(); integer_length := _lexer_global_get_end(); @@ -568,6 +574,10 @@ begin _write_c('\n') end; +proc _character_literal_node_size(); + return 12 +end; + proc _character_literal_node_get_value(this: Word); begin this := this + 4; @@ -597,9 +607,10 @@ var character: Word; character_length: Word; result: Word; + literal_size: Word; begin - result := memory_free_pointer; - memory_free_pointer := memory_free_pointer + 12; + literal_size := _character_literal_node_size(); + result := _allocate(literal_size); character := _lexer_global_get_start(); character_length := _lexer_global_get_end(); @@ -685,7 +696,7 @@ begin return result end; -proc _compile_variable_expression(variable_expression: Word); +proc _compile_variable_expression(variable_expression: Word, symbol_table: Word); var name: Word; name_token: Word; @@ -694,7 +705,7 @@ begin name := _variable_expression_get_name(variable_expression); name_token := _variable_expression_get_length(variable_expression); - lookup_result := _symbol_table_lookup(@symbol_table_local, name, name_token); + lookup_result := _symbol_table_lookup(symbol_table, name, name_token); if lookup_result <> 0 then _compile_local_designator(lookup_result) else @@ -841,7 +852,7 @@ begin return simple_expression end; -proc _compile_simple_expression(parser_node: Word); +proc _compile_simple_expression(parser_node: Word, symbol_table: Word); var is_address: Word; node_kind: Word; @@ -856,7 +867,7 @@ begin elsif node_kind = NodeKind.integer_literal then _compile_integer_literal(parser_node) else - _compile_variable_expression(parser_node); + _compile_variable_expression(parser_node, symbol_table); is_address := 1 end; return is_address @@ -926,7 +937,7 @@ begin return result end; -proc _compile_unary_expression(parser_node: Word); +proc _compile_unary_expression(parser_node: Word, symbol_table: Word); var current_character: Word; token_kind: Word; @@ -947,8 +958,8 @@ begin end; if operator = '@' then - _compile_designator(operand) - elsif _compile_designator(operand) then + _compile_designator(operand, symbol_table) + elsif _compile_designator(operand, symbol_table) then _write_z("\tlw t0, (t0) # Designator is an address.\n\0") end; if operator = '-' then @@ -1067,7 +1078,7 @@ begin return result end; -proc _compile_binary_expression(parser_node: Word); +proc _compile_binary_expression(parser_node: Word, symbol_table: Word); var token_kind: Word; expression_kind: Word; @@ -1076,17 +1087,17 @@ begin expression_kind := _node_get_kind(parser_node); if expression_kind <> NodeKind.binary_expression then - _compile_unary_expression(parser_node) + _compile_unary_expression(parser_node, symbol_table) else token_kind := _binary_expression_get_operator(parser_node); operand_node := _binary_expression_get_lhs(parser_node); - _compile_unary_expression(operand_node); + _compile_unary_expression(operand_node, symbol_table); (* Save the value of the left expression on the stack. *) _write_z("\tsw t0, 64(sp)\n\0"); operand_node := _binary_expression_get_rhs(parser_node); - _compile_unary_expression(operand_node); + _compile_unary_expression(operand_node, symbol_table); (* Load the left expression from the stack; *) _write_z("\tlw t1, 64(sp)\n\0"); @@ -1122,14 +1133,6 @@ begin end end; -proc _compile_expression(); -var - parser_node: Word; -begin - parser_node := _parse_binary_expression(); - _compile_binary_expression(parser_node) -end; - (* 4 bytes node kind + 4 byte pointer to variable expression + 4 * 7 for arguments. *) proc _call_size(); return 44 @@ -1206,7 +1209,7 @@ begin return result end; -proc _compile_call(parsed_call: Word); +proc _compile_call(parsed_call: Word, symbol_table: Word); var name_length: Word; name: Word; @@ -1225,7 +1228,7 @@ begin if parsed_expression = 0 then goto compile_call_finalize else - _compile_binary_expression(parsed_expression); + _compile_binary_expression(parsed_expression, symbol_table); (* Save the argument on the stack. *) _write_z("\tsw t0, \0"); @@ -1553,7 +1556,7 @@ begin return result end; -proc _compile_designator(parser_node: Word); +proc _compile_designator(parser_node: Word, symbol_table: Word); var name_token: Word; lookup_result: Word; @@ -1567,17 +1570,17 @@ begin if node_kind = NodeKind.dereference_expression then parser_node := _dereference_expression_get_pointer(parser_node); - _compile_simple_expression(parser_node); + _compile_simple_expression(parser_node, symbol_table); _write_z("\tlw t0, (t0)\n\0") elsif node_kind = NodeKind.field_access_expression then _compile_enumeration_value(parser_node); is_address := 0 elsif node_kind = NodeKind.call then - _compile_call(parser_node); + _compile_call(parser_node, symbol_table); _write_z("\tmv t0, a0\n\0"); is_address := 0 else - is_address := _compile_simple_expression(parser_node) + is_address := _compile_simple_expression(parser_node, symbol_table) end; return is_address end; @@ -1634,19 +1637,19 @@ begin return result end; -proc _compile_assignment_statement(parser_tree: Word); +proc _compile_assignment_statement(parser_tree: Word, symbol_table: Word); var current_expression: Word; begin current_expression := _assignment_statement_get_assignee(parser_tree); - _compile_designator(current_expression); + _compile_designator(current_expression, symbol_table); (* Save the assignee address on the stack. *) _write_z("\tsw t0, 60(sp)\n\0"); (* Compile the assignment. *) current_expression := _assignment_statement_get_assignment(parser_tree); - _compile_binary_expression(current_expression); + _compile_binary_expression(current_expression, symbol_table); _write_z("\tlw t1, 60(sp)\n\tsw t0, (t1)\n\0") end; @@ -1691,12 +1694,12 @@ begin return result end; -proc _compile_return_statement(parser_node: Word); +proc _compile_return_statement(parser_node: Word, symbol_table: Word); var return_expression: Word; begin return_expression := _return_statement_get_returned(parser_node); - _compile_binary_expression(return_expression); + _compile_binary_expression(return_expression, symbol_table); _write_z("\tmv a0, t0\n\0") end; @@ -1739,14 +1742,14 @@ begin return result end; -proc _compile_conditional_statements(parser_node: Word, after_end_label: Word); +proc _compile_conditional_statements(parser_node: Word, after_end_label: Word, symbol_table: Word); var condition_label: Word; current_node: Word; begin (* Compile condition. *) current_node := _conditional_statements_get_condition(parser_node); - _compile_binary_expression(current_node); + _compile_binary_expression(current_node, symbol_table); (* condition_label is the label in front of the next elsif condition or end. *) condition_label := label_counter; @@ -1757,7 +1760,7 @@ begin _write_c('\n'); current_node := _conditional_statements_get_statements(parser_node); - _compile_statements(current_node); + _compile_statements(current_node, symbol_table); _write_z("\tj \0"); _write_label(after_end_label); @@ -1937,7 +1940,7 @@ begin return first_statement end; -proc _compile_statements(parser_node: Word); +proc _compile_statements(parser_node: Word, symbol_table: Word); var current_statement: Word; begin @@ -1945,13 +1948,13 @@ begin .compile_statements_loop; if current_statement <> 0 then - _compile_statement(current_statement); + _compile_statement(current_statement, symbol_table); current_statement := _statement_get_next(current_statement); goto compile_statements_loop end end; -proc _compile_if_statement(parser_node: Word); +proc _compile_if_statement(parser_node: Word, symbol_table: Word); var current_node: Word; after_end_label: Word; @@ -1961,25 +1964,25 @@ begin label_counter := label_counter + 1; current_node := _if_statement_get_conditionals(parser_node); - _compile_conditional_statements(current_node, after_end_label); + _compile_conditional_statements(current_node, after_end_label, symbol_table); .compile_if_statement_loop; current_node := _conditional_statements_get_next(current_node); if current_node <> 0 then - _compile_conditional_statements(current_node, after_end_label); + _compile_conditional_statements(current_node, after_end_label, symbol_table); goto compile_if_statement_loop end; current_node := _if_statement_get_else(parser_node); if current_node <> 0 then - _compile_statements(current_node) + _compile_statements(current_node, symbol_table) end; _write_label(after_end_label); _write_z(":\n\0") end; -proc _compile_statement(parser_node: Word); +proc _compile_statement(parser_node: Word, symbol_table: Word); var statement_kind: Word; begin @@ -1988,15 +1991,15 @@ begin if statement_kind = NodeKind.goto_statement then _compile_goto_statement(parser_node) elsif statement_kind = NodeKind.if_statement then - _compile_if_statement(parser_node) + _compile_if_statement(parser_node, symbol_table) elsif statement_kind = NodeKind.return_statement then - _compile_return_statement(parser_node) + _compile_return_statement(parser_node, symbol_table) elsif statement_kind = NodeKind.label_declaration then _compile_label_declaration(parser_node) elsif statement_kind = NodeKind.call then - _compile_call(parser_node) + _compile_call(parser_node, symbol_table) elsif statement_kind = NodeKind.assignment_statement then - _compile_assignment_statement(parser_node) + _compile_assignment_statement(parser_node, symbol_table) end end; @@ -2123,9 +2126,11 @@ var member_count: Word; result: Word; type_expression_size: Word; + entry: Word; + previous_entry: Word; begin _lexer_skip_token(); - memory_start := memory_free_pointer; + memory_start := 0; member_count := 0; _lexer_read_token(@token_kind); @@ -2133,16 +2138,25 @@ begin goto parse_enumeration_type_expression_end end; .parse_enumeration_type_expression_loop; + entry := _allocate(12); member_count := member_count + 1; enumeration_name := _lexer_global_get_start(); name_length := _lexer_global_get_end() - enumeration_name; - memory_free_pointer^ := enumeration_name; - memory_free_pointer := memory_free_pointer + 4; + entry^ := enumeration_name; + entry := entry + 4; - memory_free_pointer^ := name_length; - memory_free_pointer := memory_free_pointer + 4; + entry^ := name_length; + entry := entry + 4; + + entry^ := 0; + if memory_start = 0 then + memory_start := entry - 8 + else + previous_entry^ := entry - 8 + end; + previous_entry := entry; (* Skip the identifier. *) _lexer_skip_token(); @@ -2184,6 +2198,9 @@ var result: Word; memory_start: Word; member_count: Word; + member_array_size: Word; + member_array_start: Word; + member_array_current: Word; begin (* The resulting structure is 16 bytes long. *) result := _allocate(16); @@ -2191,9 +2208,30 @@ begin memory_start := _enumeration_type_expression_get_members(parser_node); member_count := _enumeration_type_expression_get_length(parser_node); + (* Copy the list of enumeration members into an array of strings. *) + member_array_size := member_count * 8; + member_array_start := _allocate(member_array_size); + member_array_current := member_array_start; + + .read_type_enumeration_loop; + if member_count > 0 then + member_array_current^ := memory_start^; + member_array_current := member_array_current + 4; + memory_start := memory_start + 4; + + member_array_current^ := memory_start^; + member_array_current := member_array_current + 4; + memory_start := memory_start + 4; + + memory_start := memory_start^; + member_count := member_count - 1; + goto read_type_enumeration_loop + end; + member_count := _enumeration_type_expression_get_length(parser_node); + _type_set_kind(result, TypeKind.enumeration); _type_set_size(result, 4); - _enumeration_type_set_members(result, memory_start); + _enumeration_type_set_members(result, member_array_start); _enumeration_type_set_length(result, member_count); return _type_info_create(result) @@ -2273,7 +2311,7 @@ var current_word: Word; result: Word; begin - result := memory_free_pointer; + result := _allocate(8); current_word := result; current_word^ := InfoKind.parameter_info; @@ -2283,8 +2321,6 @@ begin offset := parameter_index * 4; current_word^ := 88 - offset; - memory_free_pointer := current_word + 4; - return result end; @@ -2299,15 +2335,13 @@ var result: Word; current_word: Word; begin - result := memory_free_pointer; + result := _allocate(8); current_word := result; current_word^ := InfoKind.type_info; current_word := current_word + 4; current_word^ := type_representation; - memory_free_pointer := current_word + 4; - return result end; @@ -2321,7 +2355,7 @@ var current_word: Word; result: Word; begin - result := memory_free_pointer; + result := _allocate(8); current_word := result; current_word^ := InfoKind.temporary_info; current_word := current_word + 4; @@ -2329,7 +2363,24 @@ begin (* Calculate the stack offset: 4 * variable_counter. *) current_word^ := temporary_index * 4; - memory_free_pointer := current_word + 4; + return result +end; + +(** + * Parameters: + * symbol_table - Local symbol table. + *) +proc _procedure_info_create(symbol_table: Word); +var + current_word: Word; + result: Word; +begin + result := _allocate(8); + current_word := result; + current_word^ := InfoKind.procedure_info; + current_word := current_word + 4; + + current_word^ := symbol_table; return result end; @@ -2338,7 +2389,7 @@ end; * Parameters: * parameter_index - Parameter index. *) -proc _read_procedure_parameter(parser_node: Word, parameter_index: Word); +proc _read_procedure_parameter(parser_node: Word, parameter_index: Word, symbol_table: Word); var name_length: Word; info: Word; @@ -2352,7 +2403,7 @@ begin _write_z(", \0"); info := _parameter_info_create(parameter_index); - _symbol_table_enter(@symbol_table_local, name_position, name_length, info); + _symbol_table_enter(symbol_table, name_position, name_length, info); info := _parameter_info_get_offset(info); _write_i(info); @@ -2364,7 +2415,7 @@ end; * Parameters: * variable_index - Variable index. *) -proc _read_procedure_temporary(parser_node: Word, variable_index: Word); +proc _read_procedure_temporary(parser_node: Word, variable_index: Word, symbol_table: Word); var name_length: Word; info: Word; @@ -2374,10 +2425,10 @@ begin name_length := _declaration_get_length(parser_node); info := _temporary_info_create(variable_index); - _symbol_table_enter(@symbol_table_local, name_position, name_length, info) + _symbol_table_enter(symbol_table, name_position, name_length, info) end; -proc _read_procedure_temporaries(parser_node: Word); +proc _read_procedure_temporaries(parser_node: Word, symbol_table: Word); var temporary_counter: Word; begin @@ -2387,7 +2438,7 @@ begin if parser_node = 0 then goto read_procedure_temporaries_end end; - _read_procedure_temporary(parser_node, temporary_counter); + _read_procedure_temporary(parser_node, temporary_counter, symbol_table); temporary_counter := temporary_counter + 1; parser_node := _declaration_get_next(parser_node); @@ -2558,9 +2609,11 @@ var name_length: Word; parameter_counter: Word; current_parameter: Word; + new_symbol_table: Word; + symbol_info: Word; begin - (* Clear local symbol table. *) - symbol_table_local := 0; + new_symbol_table := _symbol_table_create(); + symbol_info := _procedure_info_create(new_symbol_table); name_pointer := _declaration_get_name(parser_node); name_length := _declaration_get_length(parser_node); @@ -2584,7 +2637,7 @@ begin if current_parameter = 0 then goto compile_procedure_declaration_end end; - _read_procedure_parameter(current_parameter, parameter_counter); + _read_procedure_parameter(current_parameter, parameter_counter, new_symbol_table); parameter_counter := parameter_counter + 1; current_parameter := _declaration_get_next(current_parameter); @@ -2593,10 +2646,12 @@ begin .compile_procedure_declaration_end; current_parameter := _procedure_declaration_get_temporaries(parser_node); - _read_procedure_temporaries(current_parameter); + _read_procedure_temporaries(current_parameter, new_symbol_table); + + _symbol_table_enter(@symbol_table_global, name_pointer, name_length, symbol_info); current_parameter := _procedure_declaration_get_body(parser_node); - _compile_statements(current_parameter); + _compile_statements(current_parameter, new_symbol_table); (* Write the epilogue. *) _write_z("\tlw ra, 124(sp)\n\tlw s0, 120(sp)\n\taddi sp, sp, 128\n\tret\n\0") @@ -2851,8 +2906,8 @@ begin name_length := _named_type_expression_get_length(variable_type); if _lexer_compare_keyword("Array", 5, name, name_length) then - (* Else we assume this is a zeroed 409600 bytes big array. *) - _write_z(" .zero 409600\0") + (* Else we assume this is a zeroed 4096 bytes big array. *) + _write_z(" .zero 4096\0") else _write_z(" .word 0\n\0") end; @@ -2992,9 +3047,6 @@ var begin _write_z(".globl _start\n\n\0"); - current_part := _module_declaration_get_types(parser_node); - _read_type_part(current_part); - current_part := _module_declaration_get_globals(parser_node); _compile_var_part(current_part); @@ -3024,11 +3076,20 @@ begin _write_c('\n') end; +proc _read_module_declaration(parser_node: Word); +var + current_part: Word; +begin + current_part := _module_declaration_get_types(parser_node); + _read_type_part(current_part) +end; + proc _compile(); var parser_node: Word; begin parser_node := _parse_module_declaration(); + _read_module_declaration(parser_node); _compile_module_declaration(parser_node) end; @@ -3100,6 +3161,31 @@ begin return result end; +(** + * Create a new local symbol table in the symbol memory region after the last + * known symbol table. + *) +proc _symbol_table_create(); +var + new_symbol_table: Word; + table_length: Word; + current_table: Word; +begin + new_symbol_table := symbol_table_store; + + .symbol_table_create_loop; + table_length := new_symbol_table^; + + if table_length <> 0 then + table_length := table_length * 12; + table_length := table_length + 4; + new_symbol_table := new_symbol_table + table_length; + goto symbol_table_create_loop + end; + + return new_symbol_table +end; + (** * Inserts a symbol into the table. * @@ -3632,13 +3718,13 @@ end; (** * One time lexer initialization. *) -proc _lexer_initialize(); +proc _lexer_initialize(code_pointer: Word); begin _lexer_classifications(); _lexer_transitions(); - _lexer_global_set_start(@source_code); - _lexer_global_set_end(@source_code) + _lexer_global_set_start(code_pointer); + _lexer_global_set_end(code_pointer) end; proc _lexer_next_transition(); @@ -3922,7 +4008,9 @@ end; proc _initialize_global_state(); begin compiler_strings_position := @compiler_strings; - memory_free_pointer := @memory + memory_free_pointer := _mmap(495616); + source_code := _mmap(495616); + symbol_table_store := _mmap(495616) end; (* @@ -3934,11 +4022,11 @@ var offset: Word; begin _initialize_global_state(); - _lexer_initialize(); + _lexer_initialize(source_code); _symbol_table_build(); (* Read the source from the standard input. *) - offset := @source_code; + offset := source_code; .start_read; (* Second argument is buffer size. Modifying update the source_code definition. *)