aboutsummaryrefslogtreecommitdiff
path: root/source/tac.elna
diff options
context:
space:
mode:
Diffstat (limited to 'source/tac.elna')
-rw-r--r--source/tac.elna1074
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.