diff options
Diffstat (limited to 'source/tac.elna')
| -rw-r--r-- | source/tac.elna | 1074 |
1 files changed, 0 insertions, 1074 deletions
diff --git a/source/tac.elna b/source/tac.elna deleted file mode 100644 index 3d65e42..0000000 --- a/source/tac.elna +++ /dev/null @@ -1,1074 +0,0 @@ -(* 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, sys.posix.cstdlib, sys.posix.cstdio, sys.posix.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. |
