diff options
Diffstat (limited to 'source/tac.elna')
| -rw-r--r-- | source/tac.elna | 1074 |
1 files changed, 1074 insertions, 0 deletions
diff --git a/source/tac.elna b/source/tac.elna new file mode 100644 index 0000000..7b05ab2 --- /dev/null +++ b/source/tac.elna @@ -0,0 +1,1074 @@ +(* This Source Code Form is subject to the terms of the Mozilla Public License, + v. 2.0. If a copy of the MPL was not distributed with this file, You can + obtain one at https://mozilla.org/MPL/2.0/. *) +module +import common, cstdlib, cstdio, cstring, lexer, ast, symbol, diagnostic + +type + ElnaTacOperator* = ( + get_address, + add, + load, + store, + proc_call, + copy, + copy_to_offset, + copy_from_offset, + subtract, + divide, + remainder, + multiply, + _xor, + _or, + and, + less_than, + greater_than, + less_or_equal, + greater_or_equal, + equal, + not_equal, + negate, + complement, + jump, + jump_if_zero, + jump_if_not_zero, + label, + _return, + add_ptr, + nop + ) + + ElnaTacKind* = (list, label, constant, variable, ignore) + + ElnaTacOperand* = record + kind: ElnaTacKind; + name: []const Word8; + constant: Word; + length: Word; + list_operands: ^ElnaTacOperand + end + + ElnaTacInstruction* = record(ElnaListNode) + operator: ElnaTacOperator; + operands: [4]ElnaTacOperand + end + + ElnaTacProcedure* = record + next: ^ElnaTacProcedure; + name: []const Word8; + body: ElnaList; + parameters: ^[]const Word8; + count: Word; + symbol_table: ^ElnaSymbolTable + end + + ElnaTacStaticVariable* = record + next: ^ElnaTacStaticVariable; + name: []const Word8; + size: Word + end + + ElnaTacStringConstant* = record + next: ^ElnaTacStringConstant; + name: []const Word8; + value: []const Word8 + end + + ElnaInstructionModule* = record + strings: ^ElnaTacStringConstant; + data: ^ElnaTacStaticVariable; + code: ^ElnaTacProcedure + end + + ElnaTacOperandType = (plain_object, dereferenced_pointer, sub_object) + + ElnaTacOperandResult = record + kind: ElnaTacOperandType; + offset: Word + end + +var + pseudo_counter: Word := 0u + label_counter: Word := 0u + string_counter: Word := 0u + module_strings_first: ^ElnaTacStringConstant := nil + module_strings_last: ^ElnaTacStringConstant := nil + +proc elna_tac_instruction_create*(operator: ElnaTacOperator) -> ^ElnaTacInstruction +var + result: ^ElnaTacInstruction +begin + result := malloc#[ElnaTacInstruction](#size(ElnaTacInstruction)); + result^.next := nil; + result^.operator := operator; + result^.operands[1].kind := ElnaTacKind.ignore; + result^.operands[2].kind := ElnaTacKind.ignore; + result^.operands[3].kind := ElnaTacKind.ignore; + result^.operands[4].kind := ElnaTacKind.ignore +return result + +proc elna_tac_instruction_set_operand*(this: ^ElnaTacInstruction; n: Word; + kind: ElnaTacKind; name: []const Word8; constant: Word; length: Word) +begin + this^.operands[n].kind := kind; + this^.operands[n].name := name; + this^.operands[n].constant := constant; + this^.operands[n].length := length; + this^.operands[n].list_operands := nil +return + +proc elna_tac_instruction_set_op*(this: ^ElnaTacInstruction; n: Word; op: ^ElnaTacOperand) +begin + this^.operands[n] := op^ +return + +proc elna_tac_instruction_set_const*(this: ^ElnaTacInstruction; n: Word; value: Word; length: Word) +begin + this^.operands[n].kind := ElnaTacKind.constant; + this^.operands[n].name := ""; + this^.operands[n].constant := value; + this^.operands[n].length := length; + this^.operands[n].list_operands := nil +return + +proc elna_tac_instruction_set_label*(this: ^ElnaTacInstruction; n: Word; label_name: []const Word8) +begin + this^.operands[n].kind := ElnaTacKind.label; + this^.operands[n].name := label_name; + this^.operands[n].constant := 0u; + this^.operands[n].length := label_name.length; + this^.operands[n].list_operands := nil +return + +proc elna_tac_make_variable*(operand: ^ElnaTacOperand; symbol_table: ^ElnaSymbolTable; variable_type: ^ElnaType) +var + buffer: ^Word8 + name_slice: []const Word8 + temporary_info: ^ElnaSymbolTemporaryInfo + len: Int +begin + pseudo_counter := pseudo_counter + 1u; + buffer := malloc#[Word8](16u); + len := sprintf(buffer, "t%u\0".ptr, pseudo_counter); + + name_slice := buffer[1u to cast(len: Word)]; + + operand^.kind := ElnaTacKind.variable; + operand^.name := name_slice; + operand^.constant := 0u; + operand^.length := name_slice.length; + operand^.list_operands := nil; + + temporary_info := elna_symbol_temporary_info_create(1u, variable_type); + elna_symbol_table_enter(symbol_table, name_slice, cast(temporary_info: ^ElnaSymbolInfo)) +return + +proc elna_tac_label*() -> []const Word8 +var + buffer: ^Word8 + result: []const Word8 + len: Int +begin + label_counter := label_counter + 1u; + buffer := malloc#[Word8](16u); + len := sprintf(buffer, "l%u\0".ptr, label_counter); + result := buffer[1u to cast(len: Word)] +return result + +proc elna_tac_integer_literal(integer_literal_node: ^ElnaTreeIntegerLiteral; operand: ^ElnaTacOperand) +begin + operand^.kind := ElnaTacKind.constant; + operand^.name := ""; + operand^.constant := integer_literal_node^.value; + operand^.length := word_type^.size; + operand^.list_operands := nil +return + +proc elna_tac_boolean_literal(boolean_literal_node: ^ElnaTreeBooleanLiteral; operand: ^ElnaTacOperand) +begin + operand^.kind := ElnaTacKind.constant; + operand^.name := ""; + if boolean_literal_node^.value then + operand^.constant := 1u + else + operand^.constant := 0u + end; + operand^.length := bool_type^.size; + operand^.list_operands := nil +return + +proc elna_tac_nil_literal(operand: ^ElnaTacOperand) +begin + operand^.kind := ElnaTacKind.constant; + operand^.name := ""; + operand^.constant := 0u; + operand^.length := 8u; + operand^.list_operands := nil +return + +proc elna_tac_character_literal(character_literal_node: ^ElnaTreeCharacterLiteral; operand: ^ElnaTacOperand) +begin + operand^.kind := ElnaTacKind.constant; + operand^.name := ""; + operand^.constant := cast(character_literal_node^.value: Word); + operand^.length := char_type^.size; + operand^.list_operands := nil +return + +proc elna_tac_variable_expression(variable_expression: ^ElnaTreeVariableExpression; operand: ^ElnaTacOperand) +begin + operand^.kind := ElnaTacKind.variable; + operand^.name := variable_expression^.name; + operand^.constant := 0u; + operand^.length := variable_expression^.name.length; + operand^.list_operands := nil +return + +proc elna_tac_trait_expression(trait_node: ^ElnaTreeTraitExpression; operand: ^ElnaTacOperand) +var + symbol_info: ^ElnaSymbolInfo + type_info: ^ElnaSymbolTypeInfo + parser_node: ^ElnaTreeNamedTypeExpression +begin + parser_node := cast(trait_node^.argument: ^ElnaTreeNamedTypeExpression); + symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_node^.name); + + operand^.kind := ElnaTacKind.constant; + operand^.name := ""; + operand^.length := 8u; + operand^.list_operands := nil; + if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.type_info then + type_info := cast(symbol_info: ^ElnaSymbolTypeInfo); + operand^.constant := type_info^._type^.size + else + operand^.constant := 0u + end +return + +proc elna_tac_string_literal(instructions: ^ElnaList; string_literal_node: ^ElnaTreeStringLiteral; + symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) +var + string_entry: ^ElnaTacStringConstant + label_buf: ^Word8 + label_slice: []const Word8 + label_len: Int + instruction: ^ElnaTacInstruction + address: ElnaTacOperand +begin + string_counter := string_counter + 1u; + label_buf := malloc#[Word8](16u); + label_len := sprintf(label_buf, "str_%u\0".ptr, string_counter); + label_slice := label_buf[1u to cast(label_len: Word)]; + + string_entry := malloc#[ElnaTacStringConstant](#size(ElnaTacStringConstant)); + string_entry^.next := nil; + string_entry^.name := label_slice; + string_entry^.value := string_literal_node^.value; + + if module_strings_first = nil then + module_strings_first := string_entry + else + module_strings_last^.next := string_entry + end; + module_strings_last := string_entry; + + elna_tac_make_variable(operand, symbol_table, cast(string_type: ^ElnaType)); + elna_tac_make_variable(@address, symbol_table, pointer_type); + + instruction := elna_tac_instruction_create(ElnaTacOperator.get_address); + elna_tac_instruction_set_operand(instruction, 1u, ElnaTacKind.variable, label_slice, 0u, label_slice.length); + elna_tac_instruction_set_op(instruction, 2u, @address); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)); + + instruction := elna_tac_instruction_create(ElnaTacOperator.copy_to_offset); + elna_tac_instruction_set_op(instruction, 1u, @address); + elna_tac_instruction_set_op(instruction, 2u, operand); + elna_tac_instruction_set_const(instruction, 3u, 0u, 8u); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)); + + instruction := elna_tac_instruction_create(ElnaTacOperator.copy_to_offset); + elna_tac_instruction_set_const(instruction, 1u, string_literal_node^.value.length, 8u); + elna_tac_instruction_set_op(instruction, 2u, operand); + elna_tac_instruction_set_const(instruction, 3u, 8u, 8u); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) +return + +proc elna_tac_copy_address(instructions: ^ElnaList; operand_result: ^ElnaTacOperandResult; from, dest: ^ElnaTacOperand) +var + instruction: ^ElnaTacInstruction +begin + if operand_result^.kind = ElnaTacOperandType.dereferenced_pointer then + dest^ := from^ + elsif operand_result^.kind = ElnaTacOperandType.sub_object then + instruction := elna_tac_instruction_create(ElnaTacOperator.get_address); + elna_tac_instruction_set_op(instruction, 1u, from); + elna_tac_instruction_set_op(instruction, 2u, dest); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)); + + instruction := elna_tac_instruction_create(ElnaTacOperator.add); + elna_tac_instruction_set_const(instruction, 1u, operand_result^.offset, 4u); + elna_tac_instruction_set_op(instruction, 2u, dest); + elna_tac_instruction_set_op(instruction, 3u, dest); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + else + instruction := elna_tac_instruction_create(ElnaTacOperator.get_address); + elna_tac_instruction_set_op(instruction, 1u, from); + elna_tac_instruction_set_op(instruction, 2u, dest); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + end +return + +proc elna_tac_simple_expression(instructions: ^ElnaList; parser_node: ^ElnaTreeExpression; + symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) +begin + case parser_node^.kind of + ElnaTreeKind.integer_literal: + elna_tac_integer_literal(cast(parser_node: ^ElnaTreeIntegerLiteral), operand) + | ElnaTreeKind.character_literal: + elna_tac_character_literal(cast(parser_node: ^ElnaTreeCharacterLiteral), operand) + | ElnaTreeKind.string_literal: + elna_tac_string_literal(instructions, cast(parser_node: ^ElnaTreeStringLiteral), symbol_table, operand) + | ElnaTreeKind.boolean_literal: + elna_tac_boolean_literal(cast(parser_node: ^ElnaTreeBooleanLiteral), operand) + | ElnaTreeKind.null: + elna_tac_nil_literal(operand) + | ElnaTreeKind.variable_expression: + elna_tac_variable_expression(cast(parser_node: ^ElnaTreeVariableExpression), operand) + | ElnaTreeKind.trait_expression: + elna_tac_trait_expression(cast(parser_node: ^ElnaTreeTraitExpression), operand) + | ElnaTreeKind._cast: + elna_tac_binary_expression(instructions, (cast(parser_node: ^ElnaTreeCastExpression))^.expression, symbol_table, operand) + else + end +return + +proc elna_tac_unary_expression(instructions: ^ElnaList; parser_node: ^ElnaTreeExpression; + symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) +var + operator: ElnaLexerKind + unary_operand: ^ElnaTreeExpression + unary_node: ^ElnaTreeUnaryExpression + operand_result: ElnaTacOperandResult + instruction: ^ElnaTacInstruction + base: ElnaTacOperand + has_unary: Bool := false +begin + if parser_node^.kind = ElnaTreeKind.unary_expression then + unary_node := cast(parser_node: ^ElnaTreeUnaryExpression); + operator := unary_node^.operator; + unary_operand := unary_node^.operand; + has_unary := true + else + unary_operand := parser_node + end; + elna_tac_designator(instructions, unary_operand, symbol_table, @operand_result, @base); + + if has_unary & operator = ElnaLexerKind.at then + elna_tac_make_variable(operand, symbol_table, word_type); + elna_tac_copy_address(instructions, @operand_result, @base, operand) + elsif has_unary & operator = ElnaLexerKind.minus then + elna_tac_make_variable(operand, symbol_table, parser_node^.type_decoration); + instruction := elna_tac_instruction_create(ElnaTacOperator.negate); + elna_tac_instruction_set_op(instruction, 1u, @base); + elna_tac_instruction_set_op(instruction, 2u, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + elsif has_unary & operator = ElnaLexerKind.not then + elna_tac_make_variable(operand, symbol_table, parser_node^.type_decoration); + instruction := elna_tac_instruction_create(ElnaTacOperator.complement); + elna_tac_instruction_set_op(instruction, 1u, @base); + elna_tac_instruction_set_op(instruction, 2u, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + elsif operand_result.kind = ElnaTacOperandType.dereferenced_pointer then + elna_tac_make_variable(operand, symbol_table, parser_node^.type_decoration); + instruction := elna_tac_instruction_create(ElnaTacOperator.load); + elna_tac_instruction_set_op(instruction, 1u, @base); + elna_tac_instruction_set_op(instruction, 2u, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + elsif operand_result.kind = ElnaTacOperandType.sub_object then + elna_tac_make_variable(operand, symbol_table, parser_node^.type_decoration); + instruction := elna_tac_instruction_create(ElnaTacOperator.copy_from_offset); + elna_tac_instruction_set_op(instruction, 1u, @base); + elna_tac_instruction_set_const(instruction, 2u, operand_result.offset, 4u); + elna_tac_instruction_set_op(instruction, 3u, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + else + operand^ := base + end +return + +proc elna_tac_add_pointer(parser_node: ^ElnaTreeExpression; lhs, rhs: ^ElnaTacOperand; + symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) -> ^ElnaTacInstruction +var + instruction: ^ElnaTacInstruction + pointer_type_node: ^ElnaTypePointer + elem_size: Word := 1u +begin + if parser_node^.type_decoration <> nil & parser_node^.type_decoration^.kind = ElnaTypeKind.pointer then + pointer_type_node := cast(parser_node^.type_decoration: ^ElnaTypePointer); + if pointer_type_node^.base <> nil then + elem_size := pointer_type_node^.base^.size + end + end; + instruction := elna_tac_instruction_create(ElnaTacOperator.add_ptr); + elna_tac_make_variable(operand, symbol_table, word_type); + elna_tac_instruction_set_op(instruction, 1u, lhs); + elna_tac_instruction_set_op(instruction, 2u, rhs); + elna_tac_instruction_set_const(instruction, 3u, elem_size, 4u); + elna_tac_instruction_set_op(instruction, 4u, operand) +return instruction + +proc elna_tac_binary_create(instructions: ^ElnaList; operator: ElnaTacOperator; + lhs, rhs: ^ElnaTacOperand; symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) +var + instruction: ^ElnaTacInstruction + lhs_symbol: ^ElnaSymbolInfo + temp_info: ^ElnaSymbolTemporaryInfo + variable_type: ^ElnaType := word_type +begin + if lhs^.kind = ElnaTacKind.variable then + lhs_symbol := elna_symbol_table_lookup(symbol_table, lhs^.name); + if lhs_symbol <> nil & lhs_symbol^.kind = ElnaSymbolInfoKind.temporary_info then + temp_info := cast(lhs_symbol: ^ElnaSymbolTemporaryInfo); + variable_type := temp_info^.variable_type + end + end; + elna_tac_make_variable(operand, symbol_table, variable_type); + + instruction := elna_tac_instruction_create(operator); + elna_tac_instruction_set_op(instruction, 1u, lhs); + elna_tac_instruction_set_op(instruction, 2u, rhs); + elna_tac_instruction_set_op(instruction, 3u, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) +return + +proc elna_tac_subtract_create(instructions: ^ElnaList; parser_node: ^ElnaTreeBinaryExpression; + lhs, rhs: ^ElnaTacOperand; symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) +var + instruction: ^ElnaTacInstruction + lhs_is_pointer: Bool := false + rhs_is_not_pointer: Bool := true +begin + if parser_node^.lhs^.type_decoration <> nil & parser_node^.lhs^.type_decoration^.kind = ElnaTypeKind.pointer then + lhs_is_pointer := true + end; + if parser_node^.rhs^.type_decoration <> nil & parser_node^.rhs^.type_decoration^.kind = ElnaTypeKind.pointer then + rhs_is_not_pointer := false + end; + + if lhs_is_pointer & rhs_is_not_pointer then + instruction := elna_tac_instruction_create(ElnaTacOperator.negate); + elna_tac_instruction_set_op(instruction, 1u, rhs); + elna_tac_instruction_set_op(instruction, 2u, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)); + + instruction := elna_tac_add_pointer(parser_node^.lhs, lhs, operand, symbol_table, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + else + elna_tac_binary_create(instructions, ElnaTacOperator.subtract, lhs, rhs, symbol_table, operand) + end +return + +proc elna_tac_binary_expression(instructions: ^ElnaList; parser_node: ^ElnaTreeExpression; + symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) +var + binary_node: ^ElnaTreeBinaryExpression + instruction: ^ElnaTacInstruction + lhs: ElnaTacOperand + rhs: ElnaTacOperand +begin + if parser_node^.kind <> ElnaTreeKind.binary_expression then + elna_tac_unary_expression(instructions, parser_node, symbol_table, operand) + else + binary_node := cast(parser_node: ^ElnaTreeBinaryExpression); + elna_tac_unary_expression(instructions, binary_node^.lhs, symbol_table, @lhs); + elna_tac_unary_expression(instructions, binary_node^.rhs, symbol_table, @rhs); + + case binary_node^.operator of + ElnaLexerKind.plus: + if binary_node^.lhs^.type_decoration <> nil & binary_node^.lhs^.type_decoration^.kind = ElnaTypeKind.pointer then + instruction := elna_tac_add_pointer(binary_node^.lhs, @lhs, @rhs, symbol_table, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + elsif binary_node^.rhs^.type_decoration <> nil & binary_node^.rhs^.type_decoration^.kind = ElnaTypeKind.pointer then + instruction := elna_tac_add_pointer(binary_node^.rhs, @rhs, @lhs, symbol_table, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + else + elna_tac_binary_create(instructions, ElnaTacOperator.add, @lhs, @rhs, symbol_table, operand) + end + | ElnaLexerKind.minus: + elna_tac_subtract_create(instructions, binary_node, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.multiplication: + elna_tac_binary_create(instructions, ElnaTacOperator.multiply, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.division: + elna_tac_binary_create(instructions, ElnaTacOperator.divide, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.remainder: + elna_tac_binary_create(instructions, ElnaTacOperator.remainder, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.and: + elna_tac_binary_create(instructions, ElnaTacOperator.and, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind._or: + elna_tac_binary_create(instructions, ElnaTacOperator._or, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind._xor: + elna_tac_binary_create(instructions, ElnaTacOperator._xor, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.equals: + elna_tac_binary_create(instructions, ElnaTacOperator.equal, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.not_equal: + elna_tac_binary_create(instructions, ElnaTacOperator.not_equal, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.less_than: + elna_tac_binary_create(instructions, ElnaTacOperator.less_than, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.greater_than: + elna_tac_binary_create(instructions, ElnaTacOperator.greater_than, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.less_equal: + elna_tac_binary_create(instructions, ElnaTacOperator.less_or_equal, @lhs, @rhs, symbol_table, operand) + | ElnaLexerKind.greater_equal: + elna_tac_binary_create(instructions, ElnaTacOperator.greater_or_equal, @lhs, @rhs, symbol_table, operand) + else + end + end +return + +proc elna_tac_call(instructions: ^ElnaList; parsed_call: ^ElnaTreeCall; symbol_table: ^ElnaSymbolTable; + operand: ^ElnaTacOperand) +var + parsed_expression: ^ElnaTreeVariableExpression + arguments_operand: ^ElnaTacOperand + call_instruction: ^ElnaTacInstruction + argument_entry: ^ElnaTreeExpressionList + symbol_info: ^ElnaSymbolInfo + procedure_info: ^ElnaSymbolProcedureInfo + i: Word := 0u +begin + parsed_expression := parsed_call^.callee; + arguments_operand := malloc#[ElnaTacOperand](parsed_call^.count * #size(ElnaTacOperand)); + symbol_info := elna_symbol_table_lookup(symbol_table, parsed_expression^.name); + + call_instruction := elna_tac_instruction_create(ElnaTacOperator.proc_call); + elna_tac_instruction_set_label(call_instruction, 1u, parsed_expression^.name); + + call_instruction^.operands[2].kind := ElnaTacKind.list; + call_instruction^.operands[2].list_operands := arguments_operand; + call_instruction^.operands[2].length := parsed_call^.count; + + if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then + procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo); + if procedure_info^.procedure_type^.return_type = nil then + call_instruction^.operands[3].kind := ElnaTacKind.ignore + else + elna_tac_make_variable(operand, symbol_table, procedure_info^.procedure_type^.return_type); + elna_tac_instruction_set_op(call_instruction, 3u, operand) + end + else + call_instruction^.operands[3].kind := ElnaTacKind.ignore + end; + + argument_entry := parsed_call^.arguments; + while argument_entry <> nil & i < parsed_call^.count do + elna_tac_binary_expression(instructions, argument_entry^.expression, symbol_table, arguments_operand + i); + argument_entry := argument_entry^.next; + i := i + 1u + end; + elna_list_append(instructions, cast(call_instruction: ^ElnaListNode)) +return + +proc elna_tac_goto_statement(instructions: ^ElnaList; parser_node: ^ElnaTreeGotoStatement) +var + instruction: ^ElnaTacInstruction +begin + instruction := elna_tac_instruction_create(ElnaTacOperator.jump); + elna_tac_instruction_set_label(instruction, 1u, parser_node^.label); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) +return + +proc elna_tac_label_declaration(instructions: ^ElnaList; parser_node: ^ElnaTreeLabelDeclaration) +var + result: ^ElnaTacInstruction +begin + result := elna_tac_instruction_create(ElnaTacOperator.label); + elna_tac_instruction_set_label(result, 1u, parser_node^.label); + elna_list_append(instructions, cast(result: ^ElnaListNode)) +return + +proc elna_tac_enumeration_value(field_access_expression: ^ElnaTreeFieldAccessExpression; operand: ^ElnaTacOperand) +var + enumeration_type: ^ElnaTypeEnumeration + members: ^[]const Word8 + members_length: Word + symbol_info: ^ElnaSymbolInfo + type_info: ^ElnaSymbolTypeInfo + counter: Word := 1u + found: Bool := false + aggregate_tree: ^ElnaTreeVariableExpression +begin + aggregate_tree := cast(field_access_expression^.aggregate: ^ElnaTreeVariableExpression); + symbol_info := elna_symbol_table_lookup(symbol_table_global, aggregate_tree^.name); + + if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.type_info then + type_info := cast(symbol_info: ^ElnaSymbolTypeInfo); + if type_info^._type^.kind = ElnaTypeKind.enumeration then + enumeration_type := cast(type_info^._type: ^ElnaTypeEnumeration); + members := enumeration_type^.members; + members_length := enumeration_type^.length; + + while members_length > 0u & ~found do + if members^ = field_access_expression^.field then + found := true; + operand^.kind := ElnaTacKind.constant; + operand^.constant := counter; + operand^.length := 4u; + operand^.name := ""; + operand^.list_operands := nil + else + members_length := members_length - 1u; + members := members + 1u; + counter := counter + 1u + end + end + end + end +return + +proc elna_tac_dereference_expression(instructions: ^ElnaList; dereference_expression: ^ElnaTreeDereferenceExpression; + symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) +var + load_instruction: ^ElnaTacInstruction + operand_result: ElnaTacOperandResult + intermediate: ElnaTacOperand +begin + elna_tac_designator(instructions, dereference_expression^.pointer, symbol_table, @operand_result, operand); + + if operand_result.kind = ElnaTacOperandType.dereferenced_pointer then + intermediate := operand^; + elna_tac_make_variable(operand, symbol_table, word_type); + + load_instruction := elna_tac_instruction_create(ElnaTacOperator.load); + elna_tac_instruction_set_op(load_instruction, 1u, @intermediate); + elna_tac_instruction_set_op(load_instruction, 2u, operand); + elna_list_append(instructions, cast(load_instruction: ^ElnaListNode)) + elsif operand_result.kind = ElnaTacOperandType.sub_object then + intermediate := operand^; + elna_tac_make_variable(operand, symbol_table, word_type); + + load_instruction := elna_tac_instruction_create(ElnaTacOperator.copy_from_offset); + elna_tac_instruction_set_op(load_instruction, 1u, @intermediate); + elna_tac_instruction_set_const(load_instruction, 2u, operand_result.offset, 4u); + elna_tac_instruction_set_op(load_instruction, 3u, operand); + elna_list_append(instructions, cast(load_instruction: ^ElnaListNode)) + end +return + +proc elna_tac_field_access_expression(instructions: ^ElnaList; field_access_expression: ^ElnaTreeFieldAccessExpression; + symbol_table: ^ElnaSymbolTable; operand_result: ^ElnaTacOperandResult; operand: ^ElnaTacOperand) +var + field_type: ^ElnaType + instruction: ^ElnaTacInstruction + designator_base: ^ElnaTreeExpression + aggregate_type: ^ElnaTypeRecord + field_count: Word + current_field: ^ElnaTypeField + field_offset: Word := 0u + base: ElnaTacOperand + found: Bool := false +begin + designator_base := field_access_expression^.aggregate; + aggregate_type := cast(designator_base^.type_decoration: ^ElnaTypeRecord); + + elna_tac_designator(instructions, designator_base, symbol_table, operand_result, @base); + + if aggregate_type <> nil & aggregate_type^.kind = ElnaTypeKind._record then + field_count := aggregate_type^.length; + current_field := aggregate_type^.members; + + while field_count > 0u & ~found do + if current_field^.name = field_access_expression^.field then + found := true + else + field_type := current_field^.field_type; + field_count := field_count - 1u; + field_offset := field_offset + field_type^.size; + current_field := current_field + 1u + end + end + end; + + if operand_result^.kind = ElnaTacOperandType.dereferenced_pointer then + elna_tac_make_variable(operand, symbol_table, word_type); + + instruction := elna_tac_instruction_create(ElnaTacOperator.add); + elna_tac_instruction_set_op(instruction, 1u, @base); + elna_tac_instruction_set_const(instruction, 2u, field_offset, 4u); + elna_tac_instruction_set_op(instruction, 3u, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) + elsif operand_result^.kind = ElnaTacOperandType.sub_object then + operand^ := base; + operand_result^.offset := operand_result^.offset + field_offset + else + operand^ := base; + operand_result^.kind := ElnaTacOperandType.sub_object; + operand_result^.offset := field_offset + end +return + +proc elna_tac_array_access_expression(instructions: ^ElnaList; array_access_expression: ^ElnaTreeArrayAccessExpression; + symbol_table: ^ElnaSymbolTable; operand: ^ElnaTacOperand) +var + instruction: ^ElnaTacInstruction + operand_result: ElnaTacOperandResult + inter_operand: ElnaTacOperand + index_operand: ElnaTacOperand + aggregate_type: ^ElnaTypeArray + designator_base: ^ElnaTreeExpression + element_type: ^ElnaType + elem_size: Word := 1u +begin + designator_base := array_access_expression^.array; + if designator_base^.type_decoration <> nil & designator_base^.type_decoration^.kind = ElnaTypeKind.array then + aggregate_type := cast(designator_base^.type_decoration: ^ElnaTypeArray); + element_type := aggregate_type^.base; + if element_type <> nil then + elem_size := element_type^.size + end + end; + + elna_tac_binary_expression(instructions, array_access_expression^.index, symbol_table, @inter_operand); + elna_tac_make_variable(@index_operand, symbol_table, word_type); + + (* In Elna arrays are 1-based, subtract 1 for 0-based index *) + instruction := elna_tac_instruction_create(ElnaTacOperator.subtract); + elna_tac_instruction_set_op(instruction, 1u, @inter_operand); + elna_tac_instruction_set_const(instruction, 2u, 1u, 4u); + elna_tac_instruction_set_op(instruction, 3u, @index_operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)); + + elna_tac_designator(instructions, array_access_expression^.array, + symbol_table, @operand_result, @inter_operand); + elna_tac_make_variable(operand, symbol_table, word_type); + elna_tac_copy_address(instructions, @operand_result, @inter_operand, operand); + + instruction := elna_tac_instruction_create(ElnaTacOperator.add_ptr); + elna_tac_instruction_set_op(instruction, 1u, operand); + elna_tac_instruction_set_op(instruction, 2u, @index_operand); + elna_tac_instruction_set_const(instruction, 3u, elem_size, 4u); + elna_tac_instruction_set_op(instruction, 4u, operand); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) +return + +proc elna_tac_designator(instructions: ^ElnaList; parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; + operand_result: ^ElnaTacOperandResult; operand: ^ElnaTacOperand) +var + field_access_expression: ^ElnaTreeFieldAccessExpression + designator_base: ^ElnaTreeExpression +begin + operand_result^.kind := ElnaTacOperandType.plain_object; + operand_result^.offset := 0u; + + case parser_node^.kind of + ElnaTreeKind.dereference_expression: + elna_tac_dereference_expression(instructions, cast(parser_node: ^ElnaTreeDereferenceExpression), symbol_table, operand); + operand_result^.kind := ElnaTacOperandType.dereferenced_pointer + | ElnaTreeKind.field_access_expression: + field_access_expression := cast(parser_node: ^ElnaTreeFieldAccessExpression); + designator_base := field_access_expression^.aggregate; + + if designator_base^.type_decoration = nil then + elna_tac_enumeration_value(field_access_expression, operand) + else + elna_tac_field_access_expression(instructions, field_access_expression, symbol_table, operand_result, operand) + end + | ElnaTreeKind.array_access_expression: + elna_tac_array_access_expression(instructions, cast(parser_node: ^ElnaTreeArrayAccessExpression), symbol_table, operand); + operand_result^.kind := ElnaTacOperandType.dereferenced_pointer + | ElnaTreeKind.call: + elna_tac_call(instructions, cast(parser_node: ^ElnaTreeCall), symbol_table, operand) + else + elna_tac_simple_expression(instructions, parser_node, symbol_table, operand) + end +return + +proc elna_tac_assign_statement(instructions: ^ElnaList; parser_tree: ^ElnaTreeAssignStatement; symbol_table: ^ElnaSymbolTable) +var + operand_result: ElnaTacOperandResult + instruction: ^ElnaTacInstruction + assignment_operand: ElnaTacOperand + assignee: ElnaTacOperand +begin + elna_tac_designator(instructions, parser_tree^.assignee, symbol_table, @operand_result, @assignee); + elna_tac_binary_expression(instructions, parser_tree^.assignment, symbol_table, @assignment_operand); + + if operand_result.kind = ElnaTacOperandType.dereferenced_pointer then + instruction := elna_tac_instruction_create(ElnaTacOperator.store); + elna_tac_instruction_set_op(instruction, 1u, @assignment_operand); + elna_tac_instruction_set_op(instruction, 2u, @assignee) + elsif operand_result.kind = ElnaTacOperandType.sub_object then + instruction := elna_tac_instruction_create(ElnaTacOperator.copy_to_offset); + elna_tac_instruction_set_op(instruction, 1u, @assignment_operand); + elna_tac_instruction_set_op(instruction, 2u, @assignee); + elna_tac_instruction_set_const(instruction, 3u, operand_result.offset, 4u) + else + instruction := elna_tac_instruction_create(ElnaTacOperator.copy); + elna_tac_instruction_set_op(instruction, 1u, @assignment_operand); + elna_tac_instruction_set_op(instruction, 2u, @assignee) + end; + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) +return + +proc elna_tac_return_statement(instructions: ^ElnaList; parser_node: ^ElnaTreeReturnStatement; symbol_table: ^ElnaSymbolTable) +var + instruction: ^ElnaTacInstruction + operand: ElnaTacOperand +begin + instruction := elna_tac_instruction_create(ElnaTacOperator._return); + if parser_node^.returned <> nil then + elna_tac_binary_expression(instructions, parser_node^.returned, symbol_table, @operand); + elna_tac_instruction_set_op(instruction, 1u, @operand) + else + instruction^.operands[1].kind := ElnaTacKind.ignore + end; + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) +return + +proc elna_tac_conditional_statements(instructions: ^ElnaList; parser_node: ^ElnaTreeConditionalStatements; + after_end_label: []const Word8; symbol_table: ^ElnaSymbolTable) +var + condition_label: []const Word8 + instruction: ^ElnaTacInstruction + operand: ElnaTacOperand +begin + elna_tac_binary_expression(instructions, parser_node^.condition, symbol_table, @operand); + condition_label := elna_tac_label(); + + instruction := elna_tac_instruction_create(ElnaTacOperator.jump_if_zero); + elna_tac_instruction_set_op(instruction, 1u, @operand); + elna_tac_instruction_set_label(instruction, 2u, condition_label); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)); + + elna_tac_statements(instructions, parser_node^.statements, symbol_table); + + instruction := elna_tac_instruction_create(ElnaTacOperator.jump); + elna_tac_instruction_set_label(instruction, 1u, after_end_label); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)); + + instruction := elna_tac_instruction_create(ElnaTacOperator.label); + elna_tac_instruction_set_label(instruction, 1u, condition_label); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) +return + +proc elna_tac_if_statement(instructions: ^ElnaList; parser_node: ^ElnaTreeIfStatement; symbol_table: ^ElnaSymbolTable) +var + current_node: ^ElnaTreeConditionalStatements + after_end_label: []const Word8 + instruction: ^ElnaTacInstruction +begin + after_end_label := elna_tac_label(); + current_node := parser_node^.conditionals; + + while current_node <> nil do + elna_tac_conditional_statements(instructions, current_node, after_end_label, symbol_table); + current_node := current_node^.next + end; + + if parser_node^._else <> nil then + elna_tac_statements(instructions, parser_node^._else, symbol_table) + end; + + instruction := elna_tac_instruction_create(ElnaTacOperator.label); + elna_tac_instruction_set_label(instruction, 1u, after_end_label); + elna_list_append(instructions, cast(instruction: ^ElnaListNode)) +return + +proc elna_tac_statement(instructions: ^ElnaList; parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable) +var + operand: ElnaTacOperand + call_statement: ^ElnaTreeCallStatement +begin + case parser_node^.kind of + ElnaTreeKind.goto_statement: + elna_tac_goto_statement(instructions, cast(parser_node: ^ElnaTreeGotoStatement)) + | ElnaTreeKind.if_statement: + elna_tac_if_statement(instructions, cast(parser_node: ^ElnaTreeIfStatement), symbol_table) + | ElnaTreeKind.return_statement: + elna_tac_return_statement(instructions, cast(parser_node: ^ElnaTreeReturnStatement), symbol_table) + | ElnaTreeKind.label_declaration: + elna_tac_label_declaration(instructions, cast(parser_node: ^ElnaTreeLabelDeclaration)) + | ElnaTreeKind.call_statement: + call_statement := cast(parser_node: ^ElnaTreeCallStatement); + elna_tac_call(instructions, call_statement^.call, symbol_table, @operand) + | ElnaTreeKind.assign_statement: + elna_tac_assign_statement(instructions, cast(parser_node: ^ElnaTreeAssignStatement), symbol_table) + else + end +return + +proc elna_tac_statements(instructions: ^ElnaList; current_statement: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable) +var + current: ^ElnaTreeStatement +begin + current := current_statement; + while current <> nil do + elna_tac_statement(instructions, current, symbol_table); + current := current^.next + end +return + +proc elna_tac_parameters(ast_list: ^ElnaTreeDeclaration; parameter_count: ^Word) -> ^[]const Word8 +var + ast_parameter: ^ElnaTreeDeclaration + parameter_list: ^[]const Word8 + count: Word := 0u + i: Word := 0u +begin + ast_parameter := ast_list; + while ast_parameter <> nil do + count := count + 1u; + ast_parameter := ast_parameter^.next + end; + parameter_count^ := count; + + parameter_list := malloc#[[]const Word8](count * #size([]const Word8)); + ast_parameter := ast_list; + while i < count do + (parameter_list + i)^ := ast_parameter^.name; + i := i + 1u; + ast_parameter := ast_parameter^.next + end +return parameter_list + +proc elna_tac_procedure_declaration(parser_node: ^ElnaTreeProcedureDeclaration) -> ^ElnaTacProcedure +var + symbol_info: ^ElnaSymbolInfo + procedure_info: ^ElnaSymbolProcedureInfo + result: ^ElnaTacProcedure + parameter_count: Word := 0u +begin + result := malloc#[ElnaTacProcedure](#size(ElnaTacProcedure)); + result^.next := nil; + elna_list_initialize(@result^.body); + result^.name := parser_node^.name; + + symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_node^.name); + if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then + procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo); + result^.symbol_table := procedure_info^.symbol_table + else + result^.symbol_table := symbol_table_global + end; + + result^.parameters := elna_tac_parameters(parser_node^.parameters, @parameter_count); + result^.count := parameter_count; + pseudo_counter := 0u; + + elna_tac_statements(@result^.body, parser_node^.body, result^.symbol_table) +return result + +proc elna_tac_procedures(parser_node: ^ElnaTreeProcedureDeclaration) -> ^ElnaTacProcedure +var + result: ^ElnaTacProcedure + current_procedure: ^ElnaTacProcedure := nil + first_procedure: ^ElnaTacProcedure := nil + current_node: ^ElnaTreeProcedureDeclaration +begin + current_node := parser_node; + while current_node <> nil do + if ~current_node^.is_extern then + result := elna_tac_procedure_declaration(current_node); + if first_procedure = nil then + first_procedure := result + else + current_procedure^.next := result + end; + current_procedure := result + end; + current_node := cast(current_node^.next: ^ElnaTreeProcedureDeclaration) + end +return first_procedure + +proc elna_tac_variable_declaration(parser_tree: ^ElnaTreeVariableDeclaration) -> ^ElnaTacStaticVariable +var + result: ^ElnaTacStaticVariable + symbol_info: ^ElnaSymbolInfo + temp_info: ^ElnaSymbolTemporaryInfo +begin + result := malloc#[ElnaTacStaticVariable](#size(ElnaTacStaticVariable)); + result^.next := nil; + result^.name := parser_tree^.name; + result^.size := 4u; + + symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_tree^.name); + if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.temporary_info then + temp_info := cast(symbol_info: ^ElnaSymbolTemporaryInfo); + if temp_info^.variable_type <> nil then + result^.size := temp_info^.variable_type^.size + end + end +return result + +proc elna_tac_var_part(parser_node: ^ElnaTreeDeclaration) -> ^ElnaTacStaticVariable +var + node: ^ElnaTacStaticVariable + current_variable: ^ElnaTacStaticVariable := nil + first_variable: ^ElnaTacStaticVariable := nil + current_node: ^ElnaTreeDeclaration +begin + current_node := parser_node; + while current_node <> nil do + node := elna_tac_variable_declaration(cast(current_node: ^ElnaTreeVariableDeclaration)); + if first_variable = nil then + first_variable := node + else + current_variable^.next := node + end; + current_variable := node; + current_node := current_node^.next + end +return first_variable + +proc elna_tac_program_body(parser_node: ^ElnaTreeStatement) -> ^ElnaTacProcedure +var + result: ^ElnaTacProcedure + symbol_info: ^ElnaSymbolInfo + procedure_info: ^ElnaSymbolProcedureInfo +begin + result := malloc#[ElnaTacProcedure](#size(ElnaTacProcedure)); + result^.next := nil; + elna_list_initialize(@result^.body); + result^.name := "main"; + + symbol_info := elna_symbol_table_lookup(symbol_table_global, result^.name); + if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then + procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo); + result^.symbol_table := procedure_info^.symbol_table + else + result^.symbol_table := symbol_table_global + end; + + result^.parameters := nil; + result^.count := 0u; + pseudo_counter := 0u; + + elna_tac_statements(@result^.body, parser_node, result^.symbol_table) +return result + +proc elna_tac_module_declaration*(parser_node: ^ElnaTreeModuleDeclaration) -> ^ElnaInstructionModule +var + result: ^ElnaInstructionModule + last_proc: ^ElnaTacProcedure + body_proc: ^ElnaTacProcedure +begin + result := malloc#[ElnaInstructionModule](#size(ElnaInstructionModule)); + result^.strings := module_strings_first; + result^.data := elna_tac_var_part(parser_node^.globals); + result^.code := elna_tac_procedures(parser_node^.procedures); + + if parser_node^.body <> nil then + body_proc := elna_tac_program_body(parser_node^.body); + if result^.code = nil then + result^.code := body_proc + else + last_proc := result^.code; + while last_proc^.next <> nil do + last_proc := last_proc^.next + end; + last_proc^.next := body_proc + end + end; + result^.strings := module_strings_first +return result + +end. |
