diff --git a/Rakefile b/Rakefile index db9b0fa..4b0f566 100644 --- a/Rakefile +++ b/Rakefile @@ -37,18 +37,36 @@ end desc 'Convert previous stage language into the current stage language' task :convert do File.open('boot/stage23/cl.elna', 'w') do |current_stage| - seen_var = false + seen_proc = false File.readlines('boot/stage22/cl.elna').each do |line| - if line.start_with? 'var' - seen_var = true - current_stage << "var\n" - elsif line.start_with? 'begin' - seen_var = false - current_stage << "begin\n" - elsif seen_var && line.end_with?(";\n") - current_stage << line[0..-3] - current_stage << "\n" + if line.start_with? 'proc' + seen_proc = true + current_stage << line + elsif seen_proc && line.start_with?('begin') + seen_proc = false + current_stage << line + elsif !seen_proc && line.start_with?('begin') + current_stage << <<~CODE + proc g(location: ElnaLocation) + begin + \tprintf("# %i %i\\n\\0", location.line, location.column) + end + + proc f() + var + \tlocation: ElnaLocation + begin + \tlocation.line := 2; + \tlocation.column := 3; + \tg(location) + end + + CODE + current_stage << line + current_stage << <<~CODE + \tf(); + CODE else current_stage << line end diff --git a/boot/stage22/cl.elna b/boot/stage22/cl.elna index 80f1520..bcf4c23 100644 --- a/boot/stage22/cl.elna +++ b/boot/stage22/cl.elna @@ -7,6 +7,8 @@ program; (* Stage 22 compiler. *) +(* - Support 2 word procedure arguments. *) + type ElnaListNode = record next: Word @@ -55,7 +57,7 @@ type kind: ElnaTypeKind; size: Word; alignment: Word; - members: Word; + members: ^ElnaTypeField; length: Word end ElnaTypePointer = record @@ -689,6 +691,7 @@ var word_type: ^ElnaType char_type: ^ElnaType bool_type: ^ElnaType + string_type: ^ElnaTypeRecord source_code: Word compiler_strings_position: ^Char @@ -879,21 +882,57 @@ end * Loads or moves the value from a TAC operand into the given register. *) proc elna_rtl_hardware_value(instructions: ^ElnaList, operand: ^ElnaTacOperand, - into: ElnaRtlRegister, variable_map: ^ElnaSymbolTable) + into: ElnaRtlRegister, variable_map: ^ElnaSymbolTable) -> Word var instruction: ^ElnaRtlInstruction + pseudo_symbol: ^ElnaRtlObjectInfo + target_operand: ElnaRtlOperand + long_word_type: ^ElnaRtlType + registers_used: Word begin + registers_used := 1; + if operand^.kind = ElnaTacKind.constant then instruction := elna_rtl_instruction_create(ElnaRtlOperator.li); elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, into, 0, 0); elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.immediate, operand^.value, 0, 0); elna_list_append(instructions, instruction) elsif operand^.kind = ElnaTacKind.variable then - instruction := elna_rtl_instruction_create(ElnaRtlOperator.mv); - elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, into, 0, 0); - elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.pseudo, operand^.value, operand^.length, 0); - elna_list_append(instructions, instruction) - end + pseudo_symbol := elna_symbol_table_lookup(variable_map, operand^.value, operand^.length); + long_word_type := elna_rtl_constant_type(4); + + if pseudo_symbol^.rtl_type^.kind = ElnaRtlTypeKind.byte_array then + target_operand.kind := ElnaRtlKind.register; + target_operand.value := ElnaRtlRegister.t0; + target_operand.length := 0; + target_operand.offset := 0; + + instruction := elna_rtl_variable_address(variable_map, pseudo_symbol, operand, @target_operand); + elna_list_append(instructions, instruction); + + instruction := elna_rtl_instruction_create(ElnaRtlOperator.lw); + elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, into, 0, 0); + elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.memory, target_operand.value, target_operand.length, 0); + instruction^.types[1] := long_word_type; + elna_list_append(instructions, instruction); + + instruction := elna_rtl_instruction_create(ElnaRtlOperator.lw); + elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, into + 1, 0, 0); + elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.memory, target_operand.value, target_operand.length, 4); + instruction^.types[1] := long_word_type; + elna_list_append(instructions, instruction); + + registers_used := 2 + else + instruction := elna_rtl_instruction_create(ElnaRtlOperator.mv); + elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, into, 0, 0); + elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.pseudo, operand^.value, operand^.length, 0); + instruction^.types[1] := long_word_type; + + elna_list_append(instructions, instruction) + end + end; + return registers_used end proc elna_rtl_operand_value(instructions: ^ElnaList, tac_operand: ^ElnaTacOperand, variable_map: ^ElnaSymbolTable, @@ -1038,13 +1077,11 @@ begin elna_list_append(instructions, xor_instruction) end -proc elna_rtl_operand_address(variable_map: ^ElnaSymbolTable, +proc elna_rtl_variable_address(variable_map: ^ElnaSymbolTable, pseudo_symbol: ^ElnaRtlObjectInfo, addressable: ^ElnaTacOperand, target_operand: ^ElnaRtlOperand) -> ^ElnaRtlInstruction var - pseudo_symbol: ^ElnaRtlObjectInfo instruction: ^ElnaRtlInstruction begin - pseudo_symbol := elna_symbol_table_lookup(variable_map, addressable^.value, addressable^.length); instruction := elna_rtl_instruction_create(ElnaRtlOperator.la); elna_rtl_instruction_set_operand(instruction, 1, target_operand^.kind, @@ -1067,6 +1104,17 @@ begin return instruction end +proc elna_rtl_operand_address(variable_map: ^ElnaSymbolTable, + addressable: ^ElnaTacOperand, target_operand: ^ElnaRtlOperand) -> ^ElnaRtlInstruction +var + pseudo_symbol: ^ElnaRtlObjectInfo + instruction: ^ElnaRtlInstruction +begin + pseudo_symbol := elna_symbol_table_lookup(variable_map, addressable^.value, addressable^.length); + + return elna_rtl_variable_address(variable_map, pseudo_symbol, addressable, target_operand) +end + proc elna_rtl_get_address(instructions: ^ElnaList, tac_instruction: ^ElnaTacInstruction, variable_map: ^ElnaSymbolTable) var instruction: ^ElnaRtlInstruction @@ -1116,6 +1164,7 @@ var current_argument: ^ElnaTacOperand instruction: ^ElnaRtlInstruction current_register: Word + registers_used: Word begin current_register := 0; current_argument := tac_instruction^.operands[2].value; @@ -1126,9 +1175,9 @@ begin if argument_count > 0 then argument_count := argument_count - 1; - elna_rtl_hardware_value(instructions, current_argument, ElnaRtlRegister.a0 + current_register, variable_map); + registers_used := elna_rtl_hardware_value(instructions, current_argument, ElnaRtlRegister.a0 + current_register, variable_map); current_argument := current_argument + 1; - current_register := current_register + 1; + current_register := current_register + registers_used; goto elna_rtl_call_loop end; @@ -1328,7 +1377,7 @@ end proc elna_rtl_memcpy(instructions: ^ElnaList, byte_array: ^ElnaRtlTypeByteArray) var - instruction: ElnaRtlInstruction + instruction: ^ElnaRtlInstruction begin instruction := elna_rtl_instruction_create(ElnaRtlOperator.li); elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.a2, 0, 0); @@ -1685,8 +1734,7 @@ begin variable_map); instruction^.operator := ElnaRtlOperator.lw; (* Because it is an address. *) - instruction^.types[1] := malloc(#size(ElnaRtlTypeWord)); - instruction^.types[1]^.kind := ElnaRtlTypeKind.long_word; + instruction^.types[1] := elna_rtl_constant_type(4); elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t1, 0, 0); elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.memory, @@ -1715,8 +1763,7 @@ begin instruction^.operator := ElnaRtlOperator.lw; (* Because it is an address. *) - instruction^.types[1] := malloc(#size(ElnaRtlTypeWord)); - instruction^.types[1]^.kind := ElnaRtlTypeKind.long_word; + instruction^.types[1] := elna_rtl_constant_type(4); elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t0, 0, 0); elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.memory, @@ -1980,7 +2027,7 @@ begin instruction^.operands[1].kind, instruction^.operands[1].value, instruction^.operands[2].kind, instruction^.operands[2].length, instruction^.operands[2].value) else - printf("\n# copy %i (%i %.*s) (%i %.*s)\n\0", instruction^.operands[3].kind, + printf("\n# copy (%i %.*s) (%i %.*s)\n\0", instruction^.operands[1].kind, instruction^.operands[1].length, instruction^.operands[1].value, instruction^.operands[2].kind, instruction^.operands[2].length, instruction^.operands[2].value) end; @@ -2075,7 +2122,7 @@ begin (* Write procedure label, _procedure_name: *) printf("%.*s:\n\0", procedure^.length, procedure^.name); - elna_riscv_instructions(procedure^.body); + elna_riscv_instructions(procedure^.body.first); printf("\tret\n\0"); fflush(nil); @@ -3127,7 +3174,7 @@ begin end end -proc elna_tac_designator(instructions: ^ElnaList, parser_node: ^ElnaTreeExpression, symbol_table: ElnaSymbolTable, +proc elna_tac_designator(instructions: ^ElnaList, parser_node: ^ElnaTreeExpression, symbol_table: ^ElnaSymbolTable, operand_result: ^ElnaTacOperandResult, operand: ^ElnaTacOperand) var field_access_expression: ^ElnaTreeFieldAccessExpression @@ -3502,7 +3549,7 @@ begin end end -proc elna_tac_if_statement(instructions: ElnaList, parser_node: ^ElnaTreeIfStatement, symbol_table: ^ElnaSymbolTable) +proc elna_tac_if_statement(instructions: ^ElnaList, parser_node: ^ElnaTreeIfStatement, symbol_table: ^ElnaSymbolTable) var current_node: ^ElnaTreeConditionalStatements after_end_label: Word @@ -3529,7 +3576,7 @@ begin elna_tac_label(instructions, after_end_label, 0) end -proc elna_tac_statement(instructions: ElnaList, parser_node: ^ElnaTreeNode, symbol_table: ^ElnaSymbolTable) +proc elna_tac_statement(instructions: ^ElnaList, parser_node: ^ElnaTreeNode, symbol_table: ^ElnaSymbolTable) var operand: ElnaTacOperand begin @@ -4070,28 +4117,63 @@ begin return result end -proc elna_rtl_parameters(instructions: ^ElnaList, parameters: Word, count: Word) -> ^ElnaRtlInstruction +proc elna_rtl_parameters(instructions: ^ElnaList, parameters: Word, count: Word, + variable_map: ^ElnaSymbolTable) -> ^ElnaRtlInstruction var result: ^ElnaRtlInstruction instruction: ^ElnaRtlInstruction parameter_index: Word - parameter_name: Word - name_length: Word + pseudo_symbol: ^ElnaRtlObjectInfo + current_register: Word + target_operand: ElnaRtlOperand + source_operand: ElnaTacOperand + long_word_type: ^ElnaRtlType begin result := nil; parameter_index := 0; + current_register := ElnaRtlRegister.a0; .elna_rtl_parameters_loop; if parameter_index < count then - parameter_name := parameters^; + source_operand.kind := ElnaTacKind.variable; + source_operand.value := parameters^; parameters := parameters + 4; - name_length := parameters^; + source_operand.length := parameters^; parameters := parameters + 4; - instruction := elna_rtl_instruction_create(ElnaRtlOperator.mv); - elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.pseudo, parameter_name, name_length, 0); - elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.register, 11 + parameter_index, 0, 0); - elna_list_append(instructions, instruction); + pseudo_symbol := elna_symbol_table_lookup(variable_map, source_operand.value, source_operand.length); + long_word_type := elna_rtl_constant_type(4); + + if pseudo_symbol^.rtl_type^.kind = ElnaRtlTypeKind.byte_array then + target_operand.kind := ElnaRtlKind.register; + target_operand.value := ElnaRtlRegister.t0; + target_operand.length := 0; + target_operand.offset := 0; + instruction := elna_rtl_variable_address(variable_map, pseudo_symbol, @source_operand, @target_operand); + elna_list_append(instructions, instruction); + + instruction := elna_rtl_instruction_create(ElnaRtlOperator.sw); + elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, current_register, 0, 0); + elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.memory, target_operand.value, target_operand.length, 0); + instruction^.types[1] := long_word_type; + elna_list_append(instructions, instruction); + + instruction := elna_rtl_instruction_create(ElnaRtlOperator.sw); + elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, current_register + 1, 0, 0); + elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.memory, target_operand.value, target_operand.length, 4); + instruction^.types[1] := long_word_type; + elna_list_append(instructions, instruction); + + current_register := current_register + 2 + else + instruction := elna_rtl_instruction_create(ElnaRtlOperator.mv); + elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.pseudo, source_operand.value, source_operand.length, 0); + elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.register, current_register, 0, 0); + instruction^.types[1] := long_word_type; + elna_list_append(instructions, instruction); + + current_register := current_register + 1 + end; parameter_index := parameter_index + 1; goto elna_rtl_parameters_loop @@ -4185,8 +4267,6 @@ begin result^.length := tac_declaration^.length; pseudo_counter := 0; - elna_rtl_parameters(@result^.body, tac_declaration^.parameters, tac_declaration^.count); - result^.variable_map := elna_symbol_table_create(variable_map_global); count := tac_declaration^.symbol_table^.count; current_entry := tac_declaration^.symbol_table^.symbols; @@ -4213,6 +4293,7 @@ begin .elna_rtl_procedure_declaration_end; + elna_rtl_parameters(@result^.body, tac_declaration^.parameters, tac_declaration^.count, result^.variable_map); elna_rtl_instructions(@result^.body, tac_declaration^.body.first, result^.variable_map); return result @@ -5269,16 +5350,42 @@ begin symbol_table^.count := symbol_table^.count + 1 end +proc elna_symbol_string_build() +var + current_field: ^ElnaTypeField + char_pointer: ^ElnaTypePointer +begin + string_type := malloc(#size(ElnaTypeRecord)); + string_type^.kind := ElnaTypeKind._record; + string_type^.size := 8; + string_type^.alignment := 4; + string_type^.members := malloc(2 * #size(ElnaTypeField)); + + char_pointer := malloc(#size(ElnaTypePointer)); + char_pointer^.kind := ElnaTypeKind.pointer; + char_pointer^.size := 4; + char_pointer^.alignment := 4; + char_pointer^.base := char_type; + + current_field := string_type^.members; + current_field^.name := "ptr"; + current_field^.length := 3; + current_field^.field_type := char_pointer; + + current_field := current_field + 1; + current_field^.name := "length"; + current_field^.length := 6; + current_field^.field_type := word_type; +end + (* Build global symbol table with predefined symbols. *) proc elna_symbol_table_build() var current_info: ^ElnaSymbolTypeInfo current_type: ^ElnaType - global_pointer: ^Word begin symbol_table_global := elna_symbol_table_create(nil); - (* Enter built-in symbols. *) word_type := malloc(#size(ElnaType)); word_type^.kind := ElnaTypeKind.primitive; word_type^.size := 4; @@ -5305,7 +5412,11 @@ begin char_type^.size := 1; char_type^.alignment := 1; current_info := type_info_create(char_type); - elna_symbol_table_enter(symbol_table_global, "Char", 4, current_info) + elna_symbol_table_enter(symbol_table_global, "Char", 4, current_info); + + elna_symbol_string_build(); + current_info := type_info_create(string_type); + elna_symbol_table_enter(symbol_table_global, "String", 6, current_info) end proc elna_lexer_classifications1()