diff options
| author | Eugen Wissner <belka@caraus.de> | 2025-11-08 11:07:39 +0100 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2025-11-08 11:07:39 +0100 |
| commit | d144cb21012c911135d5047059449195a89ea239 (patch) | |
| tree | db8d8a69092192c07b2ab2c76bfd51848e3884fd /boot/stage15.elna | |
| parent | 0b516345666b52d29bb10521b4d3c2c2420b3368 (diff) | |
| download | elna-d144cb21012c911135d5047059449195a89ea239.tar.gz | |
Move stages into subdirectories
Diffstat (limited to 'boot/stage15.elna')
| -rw-r--r-- | boot/stage15.elna | 5403 |
1 files changed, 0 insertions, 5403 deletions
diff --git a/boot/stage15.elna b/boot/stage15.elna deleted file mode 100644 index 987d655..0000000 --- a/boot/stage15.elna +++ /dev/null @@ -1,5403 +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/. - *) - -(* Stage 15 compiler. *) - -type - ElnaLexerAction = (none, accumulate, skip, single, eof, finalize, composite, key_id, integer, delimited); - - (** - * Classification table assigns each possible character to a group (class). All - * characters of the same group a handled equivalently. - * - * Transition = record - * action: TransitionAction; - * next_state: TransitionState - * end; - *) - ElnaLexerClass = ( - invalid, - digit, - alpha, - space, - colon, - equals, - left_paren, - right_paren, - asterisk, - backslash, - single, - hex, - zero, - x, - eof, - dot, - minus, - single_quote, - double_quote, - greater, - less, - other - ); - ElnaLexerState = ( - start, - colon, - identifier, - decimal, - leading_zero, - greater, - minus, - left_paren, - less, - dot, - comment, - closing_comment, - character, - character_escape, - string, - string_escape, - finish - ); - ElnaLexerKind = ( - identifier, - _const, - _var, - _proc, - _type, - _begin, - _end, - _if, - _then, - _else, - _elsif, - _while, - _do, - _extern, - _record, - _true, - _false, - null, - and, - _or, - _xor, - pipe, - not, - _return, - _module, - _program, - _import, - _cast, - _defer, - _case, - _of, - trait, - left_paren, - right_paren, - left_square, - right_square, - shift_left, - shift_right, - greater_equal, - less_equal, - greater_than, - less_than, - not_equal, - equals, - semicolon, - dot, - comma, - plus, - arrow, - minus, - multiplication, - division, - remainder, - assignment, - colon, - hat, - at, - comment, - string, - character, - integer, - word, - _goto, - eof - ); - NodeKind = ( - integer_literal, - string_literal, - character_literal, - variable_expression, - field_access_expression, - dereference_expression, - unary_expression, - binary_expression, - call, - goto_statement, - label_declaration, - return_statement, - assign_statement, - if_statement, - procedure_declaration, - variable_declaration, - enumeration_type_expression, - named_type_expression, - type_declaration, - module_declaration, - record_type_expression - ); - InfoKind = (type_info, parameter_info, temporary_info, procedure_info); - TypeKind = (primitive, enumeration, _record); - ElnaTacOperator = ( - load_immediate, - load_address, - add, - add_immediate, - load_word, - store_word, - jal, - move, - sub, - div, - rem, - mul, - _xor, - _or, - and, - seqz, - snez, - slt, - xor_immediate, - neg, - not, - jump, - beqz, - label, - start, - ret - ); - ElnaTacOperand = (register, immediate, symbol, offset); - ElnaTacRegister = ( - zero, - ra, - sp, - gp, - tp, - t0, - t1, - t2, - s0, - s1, - a0, - a1, - a2, - a3, - a4, - a5, - a6, - a7, - s2, - s3, - s4, - s5, - s6, - s7, - s8, - s9, - s10, - s11, - t3, - t4, - t5, - t6 - ); - -var - symbol_table_global: Array; - compiler_strings: Array; - classification: Array; - - source_code: Word; - compiler_strings_position: Word; - compiler_strings_length: Word; - label_counter: Word; - symbol_table_store: Word; - - (* Points to a segment of free memory. *) - memory_free_pointer: Word; - -(** - * Calculates and returns the string token length between quotes, including the - * escaping slash characters. - * - * Parameters: - * string - String token pointer. - * - * Returns the length in a0. - *) -proc _string_length(string: Word); -var - counter: Word; - current_byte: Word; -begin - (* Reset the counter. *) - counter := 0; - - .string_length_loop; - string := string + 1; - - current_byte := _load_byte(string); - if current_byte <> '"' then - counter := counter + 1; - goto string_length_loop - end; - - return counter -end; - -(** - * Adds a string to the global, read-only string storage. - * - * Parameters: - * string - String token. - * - * Returns the offset from the beginning of the storage to the new string in a0. - *) -proc _add_string(string: Word); -var - contents: Word; - result: Word; - current_byte: Word; -begin - contents := string + 1; - result := compiler_strings_length; - - .add_string_loop; - current_byte := _load_byte(contents); - if current_byte <> '"' then - _store_byte(current_byte, compiler_strings_position); - compiler_strings_position := compiler_strings_position + 1; - contents := contents + 1; - - if current_byte <> '\\' then - compiler_strings_length := compiler_strings_length + 1 - end; - goto add_string_loop - end; - - return result -end; - -(** - * Reads standard input into a buffer. - * - * Parameters: - * buffer - Buffer pointer. - * size - Buffer size. - * - * Returns the amount of bytes written in a0. - *) -proc _read_file(buffer: Word, size: Word); - return _syscall(0, buffer, size, 0, 0, 0, 63) -end; - -(** - * MAP_ANONYMOUS is 32. - * PROT_READ | PORT_WRITE is (1 | 2). - * MAP_ANONYMOUS | MAP_PRIVATE is (32 | 2) - *) -proc _mmap(length: Word); - return _syscall(0, length, 1 or 2, 32 or 2, -1, 0, 222) -end; - -(** - * Writes to the standard output. - * - * Parameters: - * buffer - Buffer. - * size - Buffer length. - *) -proc _write_s(buffer: Word, size: Word); -begin - _syscall(1, buffer, size, 0, 0, 0, 64) -end; - -(** - * Writes a number to a string buffer. - * - * Parameters: - * number - Whole number. - * output_buffer - Buffer pointer. - * - * Sets a0 to the length of the written number. - *) -proc _print_i(number: Word, output_buffer: Word); -var - local_buffer: Word; - is_negative: Word; - current_character: Word; - result: Word; -begin - local_buffer := @result + 11; - - if number >= 0 then - is_negative := 0 - else - number = -number; - is_negative := 1 - end; - - .print_i_digit10; - current_character := number % 10; - _store_byte(current_character + '0', local_buffer); - - number := number / 10; - local_buffer := local_buffer - 1; - - if number <> 0 then - goto print_i_digit10 - end; - if is_negative = 1 then - _store_byte('-', local_buffer); - local_buffer := local_buffer - 1 - end; - result := @result + 11; - result := result - local_buffer; - _memcpy(output_buffer, local_buffer + 1, result); - - return result -end; - -(** - * Writes a number to the standard output. - * - * Parameters: - * number - Whole number. - *) -proc _write_i(number: Word); -var - local_buffer: Word; - length: Word; -begin - length := _print_i(number, @local_buffer); - _write_s(@local_buffer, length) -end; - -(** - * Writes a character from a0 into the standard output. - * - * Parameters: - * character - Character to write. - *) -proc _write_c(character: Word); -begin - _write_s(@character, 1) -end; - -(** - * Write null terminated string. - * - * Parameters: - * string - String. - *) -proc _write_z(string: Word); -var - next_byte: Word; -begin - (* Check for 0 character. *) - next_byte := _load_byte(string); - - if next_byte <> 0 then - (* Print a character. *) - _write_c(next_byte); - - (* Advance the input string by one byte. *) - _write_z(string + 1) - end -end; - -(** - * Detects if a0 is an uppercase character. Sets a0 to 1 if so, otherwise to 0. - *) -proc _is_upper(character: Word); -var - lhs: Word; - rhs: Word; -begin - lhs := character >= 'A'; - rhs := character <= 'Z'; - - return lhs & rhs -end; - -(** - * Detects if a0 is an lowercase character. Sets a0 to 1 if so, otherwise to 0. - *) -proc _is_lower(character: Word); -var - lhs: Word; - rhs: Word; -begin - lhs := character >= 'a'; - rhs := character <= 'z'; - - return lhs & rhs -end; - -(** - * Detects if the passed character is a 7-bit alpha character or an underscore. - * - * Paramters: - * character - Tested character. - * - * Sets a0 to 1 if the character is an alpha character or underscore, sets it to 0 otherwise. - *) -proc _is_alpha(character: Word); -var - is_upper_result: Word; - is_lower_result: Word; - is_alpha_result: Word; - is_underscore: Word; -begin - is_upper_result := _is_upper(character); - is_lower_result := _is_lower(character); - is_underscore := character = '_'; - - is_alpha_result := is_lower_result or is_upper_result; - return is_alpha_result or is_underscore -end; - -(** - * Detects whether the passed character is a digit (a value between 0 and 9). - * - * Parameters: - * character - Exemined value. - * - * Sets a0 to 1 if it is a digit, to 0 otherwise. - *) -proc _is_digit(character: Word); -var - lhs: Word; - rhs: Word; -begin - lhs := character >= '0'; - rhs := character <= '9'; - - return lhs & rhs -end; - -proc _is_alnum(character: Word); -var - lhs: Word; - rhs: Word; -begin - lhs := _is_alpha(character); - rhs := _is_digit(character); - - return lhs or rhs -end; - -(** - * Parameters: - * lhs - First pointer. - * rhs - Second pointer. - * count - The length to compare. - * - * Returns 0 if memory regions are equal. - *) -proc _memcmp(lhs: Word, rhs: Word, count: Word); -var - lhs_byte: Word; - rhs_byte: Word; - result: Word; -begin - result := 0; - - .memcmp_loop; - if count <> 0 then - lhs_byte := _load_byte(lhs); - rhs_byte := _load_byte(rhs); - result := lhs_byte - rhs_byte; - - lhs := lhs + 1; - rhs := rhs + 1; - count := count - 1; - - if result = 0 then - goto memcmp_loop - end - end; - - return result -end; - -(** - * Copies memory. - * - * Parameters: - * destination - Destination. - * source - Source. - * count - Size. - * - * Returns the destination. - *) -proc _memcpy(destination: Word, source: Word, count: Word); -var - current_byte: Word; -begin - .memcpy_loop; - if count <> 0 then - current_byte := _load_byte(source); - _store_byte(current_byte, destination); - - destination := destination + 1; - source := source + 1; - count := count - 1; - goto memcpy_loop - end; - - return destination -end; - -proc _node_get_kind(this: Word); - return this^ -end; - -proc _elna_tac_instruction_size(); - return 44 -end; - -proc _elna_tac_instruction_get_kind(this: Word); - return this^ -end; - -proc _elna_tac_instruction_set_kind(this: Word, value: Word); -begin - this^ := value -end; - -proc _elna_tac_instruction_get_next(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _elna_tac_instruction_set_next(this: Word, value: Word); -begin - .elna_tac_instruction_set_next_loop; - this := this + 4; - if value <> 0 then - if this^ <> 0 then - this := this^; - goto elna_tac_instruction_set_next_loop - end - end; - this^ := value -end; - -proc _elna_tac_instruction_get_operand_type(this: Word, n: Word); -begin - n := n - 1; - n := n * 12; - this := this + 8; - this := this + n; - - return this^ -end; - -proc _elna_tac_instruction_get_operand_value(this: Word, n: Word); -begin - n := n - 1; - n := n * 12; - this := this + 8; - this := this + n; - - this := this + 4; - return this^ -end; - -proc _elna_tac_instruction_get_operand_length(this: Word, n: Word); -begin - n := n - 1; - n := n * 12; - this := this + 8; - this := this + n; - - this := this + 8; - return this^ -end; - -proc _elna_tac_instruction_set_operand(this: Word, n: Word, operand_type: Word, operand_value: Word, operand_length: Word); -begin - n := n - 1; - n := n * 12; - this := this + 8; - this := this + n; - - this^ := operand_type; - this := this + 4; - this^ := operand_value; - this := this + 4; - this^ := operand_length -end; - -proc _elna_tac_instruction_create(kind: Word); -var - result: Word; - instruction_size: Word; -begin - instruction_size := _elna_tac_instruction_size(); - result := _allocate(instruction_size); - - _elna_tac_instruction_set_kind(result, kind); - _elna_tac_instruction_set_next(result, 0); - - return result -end; - -proc _elna_tac_module_create(data: Word, code: Word); -var - result: Word; - current_word: Word; -begin - result := _allocate(8); - - current_word := result; - current_word^ := data; - current_word := current_word + 4; - current_word^ := code; - - return result -end; - -proc _elna_tac_module_get_data(this: Word); - return this^ -end; - -proc _elna_tac_module_get_code(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _elna_tac_declaration_size(); - return 16 -end; - -proc _elna_tac_declaration_get_next(this: Word); - return this^ -end; - -proc _elna_tac_declaration_set_next(this: Word, value: Word); -begin - this^ := value -end; - -proc _elna_tac_declaration_get_name(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _elna_tac_declaration_set_name(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _elna_tac_declaration_get_length(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _elna_tac_declaration_set_length(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _elna_tac_declaration_get_body(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _elna_tac_declaration_set_body(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _elna_tac_load_immediate(target_register: Word, source_immediate: Word, immediate_length: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.load_immediate); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, target_register, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.immediate, source_immediate, immediate_length); - - return result -end; - -proc _elna_tac_load_address(target_register: Word, source_symbol: Word, symbol_length: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.load_address); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, target_register, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.symbol, source_symbol, symbol_length); - - return result -end; - -proc _elna_tac_beqz(target_register: Word, source_symbol: Word, symbol_length: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.beqz); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, target_register, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.symbol, source_symbol, symbol_length); - - return result -end; - -proc _elna_tac_jump(source_symbol: Word, symbol_length: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.jump); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.symbol, source_symbol, symbol_length); - - return result -end; - -proc _elna_tac_add(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.add); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.register, rhs, 0); - - return result -end; - -proc _elna_tac_mul(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.mul); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.register, rhs, 0); - - return result -end; - -proc _elna_tac_sub(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.sub); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.register, rhs, 0); - - return result -end; - -proc _elna_tac_div(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.div); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.register, rhs, 0); - - return result -end; - -proc _elna_tac_rem(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.rem); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.register, rhs, 0); - - return result -end; - -proc _elna_tac_xor(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator._xor); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.register, rhs, 0); - - return result -end; - -proc _elna_tac_xor_immediate(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator._xor); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.immediate, rhs, 0); - - return result -end; - -proc _elna_tac_or(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator._or); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.register, rhs, 0); - - return result -end; - -proc _elna_tac_and(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.and); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.register, rhs, 0); - - return result -end; - -proc _elna_tac_add_immediate(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.add_immediate); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.immediate, rhs, 0); - - return result -end; - -proc _elna_tac_slt(destination: Word, lhs: Word, rhs: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.slt); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, lhs, 0); - _elna_tac_instruction_set_operand(result, 3, ElnaTacOperand.register, rhs, 0); - - return result -end; - -proc _elna_tac_jal(symbol: Word, length: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.jal); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.symbol, symbol, length); - - return result -end; - -proc _elna_tac_load_word(target: Word, register: Word, offset: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.load_word); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, target, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.offset, register, offset); - - return result -end; - -proc _elna_tac_store_word(target: Word, register: Word, offset: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.store_word); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, target, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.offset, register, offset); - - return result -end; - -proc _elna_tac_move(destination: Word, source: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.move); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, source, 0); - - return result -end; - -proc _elna_tac_seqz(destination: Word, source: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.seqz); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, source, 0); - - return result -end; - -proc _elna_tac_snez(destination: Word, source: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.snez); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, source, 0); - - return result -end; - -proc _elna_tac_neg(destination: Word, source: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.neg); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, source, 0); - - return result -end; - -proc _elna_tac_not(destination: Word, source: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.not); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.register, destination, 0); - _elna_tac_instruction_set_operand(result, 2, ElnaTacOperand.register, source, 0); - - return result -end; - -proc _elna_tac_label(counter: Word, length: Word); -var - result: Word; -begin - result := _elna_tac_instruction_create(ElnaTacOperator.label); - - _elna_tac_instruction_set_operand(result, 1, ElnaTacOperand.symbol, counter, length); - - return result -end; - -proc _elna_writer_instruction_name(instruction_kind: Word); -var - argument_count: Word; -begin - if instruction_kind = ElnaTacOperator.load_immediate then - argument_count := 2; - _write_s("\tli", 3) - elsif instruction_kind = ElnaTacOperator.load_address then - argument_count := 2; - _write_s("\tla", 3) - elsif instruction_kind = ElnaTacOperator.add then - argument_count := 3; - _write_s("\tadd", 4) - elsif instruction_kind = ElnaTacOperator.add_immediate then - argument_count := 3; - _write_s("\taddi", 5) - elsif instruction_kind = ElnaTacOperator.load_word then - argument_count := 2; - _write_s("\tlw", 3) - elsif instruction_kind = ElnaTacOperator.store_word then - argument_count := 2; - _write_s("\tsw", 3) - elsif instruction_kind = ElnaTacOperator.jal then - argument_count := 1; - _write_s("\tcall", 5) - elsif instruction_kind = ElnaTacOperator.move then - argument_count := 2; - _write_s("\tmv", 3) - elsif instruction_kind = ElnaTacOperator.sub then - argument_count := 3; - _write_s("\tsub", 4) - elsif instruction_kind = ElnaTacOperator.mul then - argument_count := 3; - _write_s("\tmul", 4) - elsif instruction_kind = ElnaTacOperator.div then - argument_count := 3; - _write_s("\tdiv", 4) - elsif instruction_kind = ElnaTacOperator.rem then - argument_count := 3; - _write_s("\trem", 4) - elsif instruction_kind = ElnaTacOperator._xor then - argument_count := 3; - _write_s("\txor", 4) - elsif instruction_kind = ElnaTacOperator.xor_immediate then - argument_count := 3; - _write_s("\txori", 5) - elsif instruction_kind = ElnaTacOperator._or then - argument_count := 3; - _write_s("\tor", 3) - elsif instruction_kind = ElnaTacOperator.and then - argument_count := 3; - _write_s("\tand", 4) - elsif instruction_kind = ElnaTacOperator.seqz then - argument_count := 2; - _write_s("\tseqz", 5) - elsif instruction_kind = ElnaTacOperator.snez then - argument_count := 2; - _write_s("\tsnez", 5) - elsif instruction_kind = ElnaTacOperator.slt then - argument_count := 3; - _write_s("\tslt", 4) - elsif instruction_kind = ElnaTacOperator.neg then - argument_count := 2; - _write_s("\tneg", 4) - elsif instruction_kind = ElnaTacOperator.not then - argument_count := 2; - _write_s("\tnot", 4) - elsif instruction_kind = ElnaTacOperator.jump then - argument_count := 1; - _write_s("\tj", 2) - elsif instruction_kind = ElnaTacOperator.beqz then - argument_count := 2; - _write_s("\tbeqz", 5) - elsif instruction_kind = ElnaTacOperator.start then - argument_count := 0; - _write_z("\taddi sp, sp, -128\n\tsw ra, 124(sp)\n\tsw s0, 120(sp)\n\taddi s0, sp, 128\0") - elsif instruction_kind = ElnaTacOperator.ret then - argument_count := 0; - _write_z("\tlw ra, 124(sp)\n\tlw s0, 120(sp)\n\taddi sp, sp, 128\0") - end; - return argument_count -end; - -proc _elna_writer_register(register: Word); -begin - _write_c('x'); - _write_i(register - 1) -end; - -proc _elna_writer_operand(instruction: Word, n: Word); -var - operand_value: Word; - operand_length: Word; - operand_type: Word; -begin - operand_type := _elna_tac_instruction_get_operand_type(instruction, n); - operand_value := _elna_tac_instruction_get_operand_value(instruction, n); - operand_length := _elna_tac_instruction_get_operand_length(instruction, n); - - _write_c(' '); - if operand_type = ElnaTacOperand.register then - _elna_writer_register(operand_value) - elsif operand_type = ElnaTacOperand.offset then - _write_i(operand_length); - _write_c('('); - _elna_writer_register(operand_value); - _write_c(')') - elsif operand_type = ElnaTacOperand.symbol then - if operand_length = 0 then - _write_label(operand_value, 0) - else - _write_s(operand_value, operand_length) - end - elsif operand_length = 0 then (* ElnaTacOperand.immediate *) - _write_i(operand_value) - else - _write_s(operand_value, operand_length) - end -end; - -proc _elna_writer_instruction(instruction: Word); -var - instruction_kind: Word; - argument_count: Word; - current_argument: Word; - operand_value: Word; - operand_length: Word; -begin - instruction_kind := _elna_tac_instruction_get_kind(instruction); - - if instruction_kind = ElnaTacOperator.label then - argument_count := 0; - operand_value := _elna_tac_instruction_get_operand_value(instruction, 1); - operand_length := _elna_tac_instruction_get_operand_length(instruction, 1); - _write_label(operand_value, operand_length); - _write_c(':') - else - argument_count := _elna_writer_instruction_name(instruction_kind) - end; - current_argument := 1; - - .elna_writer_instruction_loop; - if current_argument <= argument_count then - _elna_writer_operand(instruction, current_argument); - current_argument := current_argument + 1 - end; - if current_argument <= argument_count then - _write_c(','); - goto elna_writer_instruction_loop - end; - - _write_c('\n') -end; - -proc _elna_writer_instructions(instruction: Word); -begin - if instruction <> 0 then - _elna_writer_instruction(instruction); - instruction := _elna_tac_instruction_get_next(instruction); - _elna_writer_instructions(instruction) - end -end; - -proc _elna_writer_procedure(procedure: Word); -var - name_pointer: Word; - name_length: Word; - body_statements: Word; -begin - .elna_writer_procedure_loop; - name_pointer := _elna_tac_declaration_get_name(procedure); - name_length := _elna_tac_declaration_get_length(procedure); - body_statements := _elna_tac_declaration_get_body(procedure); - - (* Write .type _procedure_name, @function. *) - _write_z(".type \0"); - - _write_s(name_pointer, name_length); - _write_z(", @function\n\0"); - - (* Write procedure label, _procedure_name: *) - _write_s(name_pointer, name_length); - _write_z(":\n\0"); - - _elna_writer_instructions(body_statements); - _write_z("\tret\n\0"); - - procedure := _elna_tac_declaration_get_next(procedure); - if procedure <> 0 then - goto elna_writer_procedure_loop - end -end; - -proc _elna_writer_variable(variable: Word); -var - name: Word; - name_length: Word; - size: Word; -begin - .elna_writer_variable_loop; - if variable <> 0 then - name := _elna_tac_declaration_get_name(variable); - name_length := _elna_tac_declaration_get_length(variable); - size := _elna_tac_declaration_get_body(variable); - - _write_z(".type \0"); - _write_s(name, name_length); - _write_z(", @object\n\0"); - - _write_s(name, name_length); - _write_c(':'); - - _write_z(" .zero \0"); - _write_i(size); - - _write_c('\n'); - variable := _elna_tac_declaration_get_next(variable); - - goto elna_writer_variable_loop - end -end; - -proc _elna_writer_module(pair: Word); -var - compiler_strings_copy: Word; - compiler_strings_end: Word; - current_byte: Word; - current_part: Word; -begin - _write_z(".globl _start\n\n\0"); - _write_z(".section .data\n\0"); - - current_part := _elna_tac_module_get_data(pair); - _elna_writer_variable(current_part); - - _write_z(".section .text\n\n\0"); - _write_z(".type _syscall, @function\n_syscall:\n\tmv a7, a6\n\tecall\n\tret\n\n\0"); - _write_z(".type _load_byte, @function\n_load_byte:\n\tlb a0, (a0)\nret\n\n\0"); - _write_z(".type _store_byte, @function\n_store_byte:\n\tsb a0, (a1)\nret\n\n\0"); - - current_part := _elna_tac_module_get_code(pair); - _elna_writer_procedure(current_part); - - _write_z(".section .rodata\n.type strings, @object\nstrings: .ascii \0"); - _write_c('"'); - - compiler_strings_copy := @compiler_strings; - compiler_strings_end := compiler_strings_position; - - .elna_writer_module_loop; - if compiler_strings_copy < compiler_strings_end then - current_byte := _load_byte(compiler_strings_copy); - compiler_strings_copy := compiler_strings_copy + 1; - _write_c(current_byte); - - goto elna_writer_module_loop - end; - _write_c('"'); - _write_c('\n'); -end; - -proc _node_set_kind(this: Word, kind: Word); -begin - this^ := kind -end; - -proc _integer_literal_node_size(); - return 12 -end; - -proc _integer_literal_node_get_value(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _integer_literal_node_set_value(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _integer_literal_node_get_length(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _integer_literal_node_set_length(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _elna_parser_integer_literal(); -var - integer_token: Word; - integer_length: Word; - result: Word; - literal_size: Word; -begin - literal_size := _integer_literal_node_size(); - result := _allocate(literal_size); - - integer_token := _elna_lexer_global_get_start(); - integer_length := _elna_lexer_global_get_end(); - integer_length := integer_length - integer_token; - _elna_lexer_skip_token(); - - _node_set_kind(result, NodeKind.integer_literal); - _integer_literal_node_set_value(result, integer_token); - _integer_literal_node_set_length(result, integer_length); - - return result -end; - -proc _elna_tac_integer_literal(integer_literal_node: Word); -var - integer_token: Word; - integer_length: Word; - token_kind: Word; -begin - integer_token := _integer_literal_node_get_value(integer_literal_node); - integer_length := _integer_literal_node_get_length(integer_literal_node); - - return _elna_tac_load_immediate(ElnaTacRegister.t0, integer_token, integer_length) -end; - -proc _character_literal_node_size(); - return 12 -end; - -proc _character_literal_node_get_value(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _character_literal_node_set_value(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _character_literal_node_get_length(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _character_literal_node_set_length(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _elna_parser_character_literal(); -var - character: Word; - character_length: Word; - result: Word; - literal_size: Word; -begin - literal_size := _character_literal_node_size(); - result := _allocate(literal_size); - - character := _elna_lexer_global_get_start(); - character_length := _elna_lexer_global_get_end(); - character_length := character_length - character; - _elna_lexer_skip_token(); - - _node_set_kind(result, NodeKind.character_literal); - _integer_literal_node_set_value(result, character); - _integer_literal_node_set_length(result, character_length); - - return result -end; - -proc _elna_tac_character_literal(character_literal_node: Word); -var - character: Word; - character_length: Word; -begin - character := _character_literal_node_get_value(character_literal_node); - character_length := _character_literal_node_get_length(character_literal_node); - - return _elna_tac_load_immediate(ElnaTacRegister.t0, character, character_length) -end; - -proc _variable_expression_size(); - return 12 -end; - -proc _variable_expression_get_name(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _variable_expression_set_name(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _variable_expression_get_length(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _variable_expression_set_length(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _allocate(size: Word); -var - result: Word; -begin - result := memory_free_pointer; - memory_free_pointer := memory_free_pointer + size; - return result -end; - -proc _elna_parser_variable_expression(); -var - name: Word; - name_token: Word; - result: Word; - memory_size: Word; -begin - name := _elna_lexer_global_get_start(); - name_token := _elna_lexer_global_get_end(); - name_token := name_token - name; - _elna_lexer_skip_token(); - - memory_size := _variable_expression_size(); - result := _allocate(memory_size); - - _node_set_kind(result, NodeKind.variable_expression); - _variable_expression_set_name(result, name); - _variable_expression_set_length(result, name_token); - - return result -end; - -proc _elna_tac_variable_expression(variable_expression: Word, symbol_table: Word); -var - name: Word; - name_token: Word; - lookup_result: Word; - instruction: Word; -begin - name := _variable_expression_get_name(variable_expression); - name_token := _variable_expression_get_length(variable_expression); - - lookup_result := _symbol_table_lookup(symbol_table, name, name_token); - if lookup_result <> 0 then - instruction := _elna_tac_local_designator(lookup_result) - else - instruction := _elna_tac_global_designator(variable_expression) - end; - return instruction -end; - -proc _string_literal_node_size(); - return 12 -end; - -proc _string_literal_node_get_value(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _string_literal_node_set_value(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _string_literal_node_get_length(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _string_literal_node_set_length(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _elna_parser_string_literal(); -var - length: Word; - token_start: Word; - result: Word; - memory_size: Word; -begin - memory_size := _string_literal_node_size(); - result := _allocate(memory_size); - - token_start := _elna_lexer_global_get_start(); - length := _string_length(token_start); - _elna_lexer_skip_token(); - - _node_set_kind(result, NodeKind.string_literal); - _string_literal_node_set_value(result, token_start); - _string_literal_node_set_length(result, length); - - return result -end; - -proc _elna_tac_string_literal(string_literal_node: Word); -var - token_start: Word; - length: Word; - offset: Word; - instruction: Word; - first_instruction: Word; - next_instruction: Word; -begin - token_start := _string_literal_node_get_value(string_literal_node); - length := _string_literal_node_get_length(string_literal_node); - offset := _add_string(token_start); - - first_instruction := _elna_tac_load_address(ElnaTacRegister.t0, "strings", 7); - instruction := _elna_tac_load_immediate(ElnaTacRegister.t1, offset, 0); - _elna_tac_instruction_set_next(first_instruction, instruction); - next_instruction := _elna_tac_add(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(instruction, next_instruction); - - return first_instruction -end; - -proc _elna_parser_simple_expression(); -var - current_character: Word; - parser_node: Word; - token_kind: Word; -begin - parser_node := 0; - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind.character then - parser_node := _elna_parser_character_literal() - elsif token_kind = ElnaLexerKind.integer then - parser_node := _elna_parser_integer_literal() - elsif token_kind = ElnaLexerKind.string then - parser_node := _elna_parser_string_literal() - elsif token_kind = ElnaLexerKind.identifier then - parser_node := _elna_parser_variable_expression() - end; - return parser_node -end; - -proc _dereference_expression_size(); - return 8 -end; - -proc _dereference_expression_get_pointer(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _dereference_expression_set_pointer(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _elna_parser_dereference_expression(simple_expression: Word); -var - result: Word; - memory_size: Word; -begin - memory_size := _dereference_expression_size(); - result := _allocate(memory_size); - - _node_set_kind(result, NodeKind.dereference_expression); - _dereference_expression_set_pointer(result, simple_expression); - _elna_lexer_skip_token(); - - return result -end; - -proc _elna_parser_designator(); -var - simple_expression: Word; - token_kind: Word; -begin - simple_expression := _elna_parser_simple_expression(); - - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind.hat then - simple_expression := _elna_parser_dereference_expression(simple_expression) - elsif token_kind = ElnaLexerKind.dot then - simple_expression := _elna_parser_field_access_expression(simple_expression) - elsif token_kind = ElnaLexerKind.left_paren then - simple_expression := _elna_parser_call(simple_expression) - end; - return simple_expression -end; - -proc _elna_tac_simple_expression(parser_node: Word, symbol_table: Word, is_address: Word); -var - is_address: Word; - node_kind: Word; - instruction: Word; -begin - is_address^ := 0; - node_kind := _node_get_kind(parser_node); - - if node_kind = NodeKind.character_literal then - instruction := _elna_tac_character_literal(parser_node) - elsif node_kind = NodeKind.string_literal then - instruction := _elna_tac_string_literal(parser_node) - elsif node_kind = NodeKind.integer_literal then - instruction := _elna_tac_integer_literal(parser_node) - else - instruction := _elna_tac_variable_expression(parser_node, symbol_table); - is_address^ := 1 - end; - return instruction -end; - -proc _unary_expression_size(); - return 12 -end; - -proc _unary_expression_get_operand(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _unary_expression_set_operand(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _unary_expression_get_operator(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _unary_expression_set_operator(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _elna_parser_unary_expression(); -var - token_kind: Word; - result: Word; - memory_size: Word; - operand: Word; - operator: Word; -begin - _elna_lexer_read_token(@token_kind); - operator := 0; - - if token_kind = ElnaLexerKind.at then - operator := '@' - elsif token_kind = ElnaLexerKind.minus then - operator := '-' - elsif token_kind = ElnaLexerKind.not then - operator := '~' - end; - if operator <> 0 then - _elna_lexer_skip_token() - end; - result := _elna_parser_designator(); - - if operator <> 0 then - operand := result; - memory_size := _unary_expression_size(); - result := _allocate(memory_size); - - _node_set_kind(result, NodeKind.unary_expression); - _unary_expression_set_operand(result, operand); - _unary_expression_set_operator(result, operator) - end; - - return result -end; - -proc _elna_tac_unary_expression(parser_node: Word, symbol_table: Word); -var - current_character: Word; - token_kind: Word; - expression_kind: Word; - operator: Word; - operand: Word; - is_address: Word; - first_instruction: Word; - instruction: Word; -begin - operator := 0; - operand := 0; - - expression_kind := _node_get_kind(parser_node); - - if expression_kind = NodeKind.unary_expression then - operator := _unary_expression_get_operator(parser_node); - operand := _unary_expression_get_operand(parser_node) - else - operand := parser_node - end; - - if operator = '@' then - first_instruction := _elna_tac_designator(operand, symbol_table, @is_address) - else - first_instruction := _elna_tac_designator(operand, symbol_table, @is_address); - if is_address then - instruction := _elna_tac_load_word(ElnaTacRegister.t0, ElnaTacRegister.t0, 0); - _elna_tac_instruction_set_next(first_instruction, instruction) - end - end; - if operator = '-' then - instruction := _elna_tac_neg(ElnaTacRegister.t0, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(first_instruction, instruction) - elsif operator = '~' then - instruction := _elna_tac_not(ElnaTacRegister.t0, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(first_instruction, instruction) - end; - return first_instruction -end; - -proc _binary_expression_size(); - return 16 -end; - -proc _binary_expression_get_lhs(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _binary_expression_set_lhs(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _binary_expression_get_rhs(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _binary_expression_set_rhs(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _binary_expression_get_operator(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _binary_expression_set_operator(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _elna_parser_binary_expression(); -var - lhs_node: Word; - rhs_node: Word; - token_kind: Word; - memory_size: Word; - result: Word; -begin - lhs_node := _elna_parser_unary_expression(); - rhs_node := 0; - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind.plus then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.minus then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.multiplication then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.and then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind._or then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind._xor then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.equals then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.remainder then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.division then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.less_than then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.greater_than then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.less_equal then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.not_equal then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - elsif token_kind = ElnaLexerKind.greater_equal then - _elna_lexer_skip_token(); - rhs_node := _elna_parser_unary_expression() - end; - if rhs_node <> 0 then - memory_size := _binary_expression_size(); - result := _allocate(memory_size); - - _node_set_kind(result, NodeKind.binary_expression); - _binary_expression_set_lhs(result, lhs_node); - _binary_expression_set_rhs(result, rhs_node); - _binary_expression_set_operator(result, token_kind) - else - result := lhs_node - end; - return result -end; - -proc _elna_tac_binary_expression(parser_node: Word, symbol_table: Word); -var - token_kind: Word; - expression_kind: Word; - operand_node: Word; - first_instruction: Word; - instruction: Word; - current_instruction: Word; -begin - expression_kind := _node_get_kind(parser_node); - - if expression_kind <> NodeKind.binary_expression then - first_instruction := _elna_tac_unary_expression(parser_node, symbol_table) - else - token_kind := _binary_expression_get_operator(parser_node); - - operand_node := _binary_expression_get_lhs(parser_node); - first_instruction := _elna_tac_unary_expression(operand_node, symbol_table); - - (* Save the value of the left expression on the stack. *) - instruction := _elna_tac_store_word(ElnaTacRegister.t0, ElnaTacRegister.sp, 64); - _elna_tac_instruction_set_next(first_instruction, instruction); - current_instruction := instruction; - - operand_node := _binary_expression_get_rhs(parser_node); - instruction := _elna_tac_unary_expression(operand_node, symbol_table); - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction; - - (* Load the left expression from the stack; *) - instruction := _elna_tac_load_word(ElnaTacRegister.t1, ElnaTacRegister.sp, 64); - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction; - - if token_kind = ElnaLexerKind.plus then - instruction := _elna_tac_add(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.minus then - instruction := _elna_tac_sub(ElnaTacRegister.t0, ElnaTacRegister.t1, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.multiplication then - instruction := _elna_tac_mul(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.and then - instruction := _elna_tac_and(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind._or then - instruction := _elna_tac_or(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind._xor then - instruction := _elna_tac_xor(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.equals then - instruction := _elna_tac_xor(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction; - - instruction := _elna_tac_seqz(ElnaTacRegister.t0, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.remainder then - instruction := _elna_tac_rem(ElnaTacRegister.t0, ElnaTacRegister.t1, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.division then - instruction := _elna_tac_div(ElnaTacRegister.t0, ElnaTacRegister.t1, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.less_than then - instruction := _elna_tac_slt(ElnaTacRegister.t0, ElnaTacRegister.t1, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.greater_than then - instruction := _elna_tac_slt(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.less_equal then - instruction := _elna_tac_slt(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction; - - instruction := _elna_tac_xor_immediate(ElnaTacRegister.t0, ElnaTacRegister.t0, 1); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.not_equal then - instruction := _elna_tac_xor(ElnaTacRegister.t0, ElnaTacRegister.t0, ElnaTacRegister.t1); - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction; - - instruction := _elna_tac_snez(ElnaTacRegister.t0, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(current_instruction, instruction) - elsif token_kind = ElnaLexerKind.greater_equal then - instruction := _elna_tac_slt(ElnaTacRegister.t0, ElnaTacRegister.t1, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction; - - instruction := _elna_tac_xor_immediate(ElnaTacRegister.t0, ElnaTacRegister.t0, 1); - _elna_tac_instruction_set_next(current_instruction, instruction) - end - end; - return first_instruction -end; - -(* 4 bytes node kind + 4 byte pointer to variable expression + 4 * 7 for arguments. *) -proc _call_size(); - return 44 -end; - -proc _call_get_name(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _call_set_name(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _call_get_argument(this: Word, n: Word); -begin - n := n * 4; - this := this + 8; - this := this + n; - return this^ -end; - -proc _call_set_argument(this: Word, n: Word, value: Word); -begin - n := n * 4; - this := this + 8; - this := this + n; - this^ := value -end; - -proc _elna_parser_call(callee: Word); -var - parsed_expression: Word; - result: Word; - argument_number: Word; - token_kind: Word; - call_size: Word; -begin - call_size := _call_size(); - result := _allocate(call_size); - _node_set_kind(result, NodeKind.call); - _statement_set_next(result, 0); - - argument_number := 1; - _call_set_name(result, callee); - - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind.right_paren then - _elna_lexer_skip_token(); - goto elna_parser_call_end - end; - - .elna_parser_call_loop; - parsed_expression := _elna_parser_binary_expression(); - _call_set_argument(result, argument_number, parsed_expression); - argument_number := argument_number + 1; - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - if token_kind = ElnaLexerKind.comma then - goto elna_parser_call_loop - end; - - .elna_parser_call_end; - (* Set the trailing argument to nil. *) - _call_set_argument(result, argument_number, 0); - - return result -end; - -proc _elna_tac_call(parsed_call: Word, symbol_table: Word); -var - name_length: Word; - name: Word; - argument_count: Word; - stack_offset: Word; - parsed_expression: Word; - instruction: Word; - first_instruction: Word; - current_instruction: Word; -begin - parsed_expression := _call_get_name(parsed_call); - name := _variable_expression_get_name(parsed_expression); - name_length := _variable_expression_get_length(parsed_expression); - argument_count := 0; - first_instruction := 0; - - .elna_tac_call_loop; - - parsed_expression := _call_get_argument(parsed_call, argument_count + 1); - if parsed_expression = 0 then - goto elna_tac_call_finalize - else - instruction := _elna_tac_binary_expression(parsed_expression, symbol_table); - if first_instruction = 0 then - first_instruction := instruction - else - _elna_tac_instruction_set_next(current_instruction, instruction) - end; - current_instruction := instruction; - - (* Save the argument on the stack. *) - stack_offset := argument_count * 4; - - instruction := _elna_tac_store_word(ElnaTacRegister.t0, - ElnaTacRegister.sp, 116 - stack_offset); - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction; - - argument_count := argument_count + 1; - goto elna_tac_call_loop - end; - .elna_tac_call_finalize; - - (* Load the argument from the stack. *) - if argument_count <> 0 then - (* Decrement the argument counter. *) - argument_count := argument_count - 1; - stack_offset := argument_count * 4; - - (* Calculate the stack offset: 116 - (4 * argument_counter) *) - instruction := _elna_tac_load_word(ElnaTacRegister.a0 + argument_count, - ElnaTacRegister.sp, 116 - stack_offset); - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction; - - goto elna_tac_call_finalize - end; - instruction := _elna_tac_jal(name, name_length); - if first_instruction = 0 then - first_instruction := instruction - else - _elna_tac_instruction_set_next(current_instruction, instruction) - end; - return first_instruction -end; - -(** - * All statements are chained into a list. Next contains a pointer to the next - * statement in the statement list. - *) -proc _statement_get_next(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _statement_set_next(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _goto_statement_size(); - return 16 -end; - -proc _goto_statement_get_label(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _goto_statement_set_label(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _goto_statement_get_length(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _goto_statement_set_length(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _elna_parser_goto_statement(); -var - token_kind: Word; - label_name: Word; - label_length: Word; - statement_size: Word; - result: Word; -begin - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - - label_name := _elna_lexer_global_get_start(); - label_length := _elna_lexer_global_get_end() - label_name; - _elna_lexer_skip_token(); - - statement_size := _goto_statement_size(); - result := _allocate(statement_size); - - _node_set_kind(result, NodeKind.goto_statement); - _statement_set_next(result, 0); - _goto_statement_set_label(result, label_name); - _goto_statement_set_length(result, label_length); - - return result -end; - -proc _elna_tac_goto_statement(parser_node: Word); -var - label_name: Word; - label_length: Word; - label_with_dot: Word; - instruction: Word; -begin - label_name := _goto_statement_get_label(parser_node); - label_length := _goto_statement_get_length(parser_node); - label_with_dot := _allocate(label_length + 1); - - _store_byte('.', label_with_dot); - _memcpy(label_with_dot + 1, label_name, label_length); - - return _elna_tac_jump(label_with_dot, label_length + 1) -end; - -proc _label_declaration_size(); - return 16 -end; - -proc _label_declaration_get_label(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _label_declaration_set_label(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _label_declaration_get_length(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _label_declaration_set_length(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _elna_parser_label_declaration(); -var - token_kind: Word; - label_name: Word; - label_length: Word; - statement_size: Word; - result: Word; -begin - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - - label_name := _elna_lexer_global_get_start(); - label_length := _elna_lexer_global_get_end() - label_name; - _elna_lexer_skip_token(); - - statement_size := _label_declaration_size(); - result := _allocate(statement_size); - - _node_set_kind(result, NodeKind.label_declaration); - _statement_set_next(result, 0); - _goto_statement_set_label(result, label_name); - _goto_statement_set_length(result, label_length); - - return result -end; - -proc _elna_tac_label_declaration(parser_node: Word); -var - label_name: Word; - label_length: Word; -begin - label_name := _label_declaration_get_label(parser_node); - label_length := _label_declaration_get_length(parser_node); - - return _elna_tac_label(label_name, label_length) -end; - -proc _elna_tac_local_designator(symbol: Word); -var - variable_offset: Word; -begin - variable_offset := _parameter_info_get_offset(symbol); - - return _elna_tac_add_immediate(ElnaTacRegister.t0, ElnaTacRegister.sp, variable_offset) -end; - -proc _elna_tac_global_designator(variable_expression: Word); -var - name: Word; - token_length: Word; -begin - name := _variable_expression_get_name(variable_expression); - token_length := _variable_expression_get_length(variable_expression); - - return _elna_tac_load_address(ElnaTacRegister.t0, name, token_length) -end; - -proc _field_access_expression_size(); - return 16 -end; - -proc _field_access_expression_get_aggregate(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _field_access_expression_set_aggregate(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _field_access_expression_get_field(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _field_access_expression_set_field(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _field_access_expression_get_length(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _field_access_expression_set_length(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _elna_tac_enumeration_value(field_access_expression: Word); -var - enumeration_type: Word; - members: Word; - members_length: Word; - token_type: Word; - value_name: Word; - name_length: Word; - member_name: Word; - member_length: Word; - counter: Word; - symbol: Word; - instruction: Word; -begin - symbol := _field_access_expression_get_aggregate(field_access_expression); - value_name := _variable_expression_get_name(symbol); - name_length := _variable_expression_get_length(symbol); - - symbol := _symbol_table_lookup(@symbol_table_global, value_name, name_length); - - enumeration_type := _type_info_get_type(symbol); - members := _enumeration_type_get_members(enumeration_type); - members_length := _enumeration_type_get_length(enumeration_type); - - _elna_lexer_read_token(@token_type); - - value_name := _field_access_expression_get_field(field_access_expression); - name_length := _field_access_expression_get_length(field_access_expression); - counter := 1; - - instruction := 0; - .elna_tac_enumeration_value_members; - if members_length > 0 then - member_name := members^; - member_length := members + 4; - member_length := member_length^; - - if _string_compare(value_name, name_length, member_name, member_length) = 0 then - members_length := members_length - 1; - members := members + 8; - counter := counter + 1; - goto elna_tac_enumeration_value_members - end; - instruction := _elna_tac_load_immediate(ElnaTacRegister.t0, counter, 0) - end; - return instruction -end; - -proc _elna_parser_field_access_expression(aggregate: Word); -var - token_kind: Word; - name: Word; - name_token: Word; - result: Word; - memory_size: Word; -begin - (* Skip dot. Read the enumeration value. *) - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - - name := _elna_lexer_global_get_start(); - name_token := _elna_lexer_global_get_end(); - name_token := name_token - name; - _elna_lexer_skip_token(); - memory_size := _field_access_expression_size(); - result := _allocate(memory_size); - - _node_set_kind(result, NodeKind.field_access_expression); - _field_access_expression_set_aggregate(result, aggregate); - _field_access_expression_set_field(result, name); - _field_access_expression_set_length(result, name_token); - - return result -end; - -proc _elna_tac_designator(parser_node: Word, symbol_table: Word, is_address: Word); -var - name_token: Word; - lookup_result: Word; - token_kind: Word; - parser_node: Word; - node_kind: Word; - first_instruction: Word; - instruction: Word; -begin - node_kind := _node_get_kind(parser_node); - - if node_kind = NodeKind.dereference_expression then - parser_node := _dereference_expression_get_pointer(parser_node); - first_instruction := _elna_tac_simple_expression(parser_node, symbol_table, is_address); - instruction := _elna_tac_load_word(ElnaTacRegister.t0, ElnaTacRegister.t0, 0); - _elna_tac_instruction_set_next(first_instruction, instruction) - elsif node_kind = NodeKind.field_access_expression then - first_instruction := _elna_tac_enumeration_value(parser_node); - is_address^ := 0 - elsif node_kind = NodeKind.call then - first_instruction := _elna_tac_call(parser_node, symbol_table); - instruction := _elna_tac_move(ElnaTacRegister.t0, ElnaTacRegister.a0); - _elna_tac_instruction_set_next(first_instruction, instruction); - is_address^ := 0 - else - first_instruction := _elna_tac_simple_expression(parser_node, symbol_table, is_address) - end; - return first_instruction -end; - -proc _assign_statement_size(); - return 16 -end; - -proc _assign_statement_get_assignee(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _assign_statement_set_assignee(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _assign_statement_get_assignment(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _assign_statement_set_assignment(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _elna_parser_assign_statement(assignee: Word); -var - statement_size: Word; - result: Word; - token_kind: Word; - assignment_node: Word; -begin - statement_size := _assign_statement_size(); - result := _allocate(statement_size); - - _node_set_kind(result, NodeKind.assign_statement); - _statement_set_next(result, 0); - _assign_statement_set_assignee(result, assignee); - - (* Skip the assignment sign (:=) with surrounding whitespaces. *) - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - assignment_node := _elna_parser_binary_expression(); - _assign_statement_set_assignment(result, assignment_node); - - return result -end; - -proc _elna_tac_assign_statement(parser_tree: Word, symbol_table: Word); -var - current_expression: Word; - is_address: Word; - first_instruction: Word; - instruction: Word; - current_instruction: Word; -begin - current_expression := _assign_statement_get_assignee(parser_tree); - first_instruction := _elna_tac_designator(current_expression, symbol_table, @is_address); - - (* Save the assignee address on the stack. *) - current_instruction := _elna_tac_store_word(ElnaTacRegister.t0, ElnaTacRegister.sp, 60); - _elna_tac_instruction_set_next(first_instruction, current_instruction); - - (* Compile the assignment. *) - current_expression := _assign_statement_get_assignment(parser_tree); - instruction := _elna_tac_binary_expression(current_expression, symbol_table); - _elna_tac_instruction_set_next(current_instruction, instruction); - - current_instruction := _elna_tac_load_word(ElnaTacRegister.t1, ElnaTacRegister.sp, 60); - _elna_tac_instruction_set_next(instruction, current_instruction); - - instruction := _elna_tac_store_word(ElnaTacRegister.t0, ElnaTacRegister.t1, 0); - _elna_tac_instruction_set_next(current_instruction, instruction); - - return first_instruction -end; - -proc _return_statement_size(); - return 12 -end; - -proc _return_statement_get_returned(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _return_statement_set_returned(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _elna_parser_return_statement(); -var - token_kind: Word; - returned: Word; - label_length: Word; - statement_size: Word; - result: Word; -begin - (* Skip "return" keyword and whitespace after it. *) - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - - returned := _elna_parser_binary_expression(); - - statement_size := _return_statement_size(); - result := _allocate(statement_size); - - _node_set_kind(result, NodeKind.return_statement); - _statement_set_next(result, 0); - _return_statement_set_returned(result, returned); - - return result -end; - -proc _elna_tac_return_statement(parser_node: Word, symbol_table: Word); -var - return_expression: Word; - first_instruction: Word; - instruction: Word; -begin - return_expression := _return_statement_get_returned(parser_node); - first_instruction := _elna_tac_binary_expression(return_expression, symbol_table); - instruction := _elna_tac_move(ElnaTacRegister.a0, ElnaTacRegister.t0); - _elna_tac_instruction_set_next(first_instruction, instruction); - return first_instruction -end; - -(** - * Writes a label, .Ln, where n is a unique number. - * - * Parameters: - * counter - Label counter. - *) -proc _write_label(counter: Word, length: Word); -var - first_byte: Word; -begin - if length = 0 then - _write_s(".L", 2); - _write_i(counter) - else - first_byte := _load_byte(counter); - if first_byte <> '.' then - _write_c('.') - end; - _write_s(counter, length) - end -end; - -proc _elna_parser_conditional_statements(); -var - conditional_size: Word; - token_kind: Word; - current_node: Word; - result: Word; -begin - conditional_size := _conditional_statements_size(); - result := _allocate(conditional_size); - - (* Skip "if", "while" or "elsif". *) - _elna_lexer_skip_token(); - - current_node := _elna_parser_binary_expression(); - _conditional_statements_set_condition(result, current_node); - - (* Skip "then" or "do". *) - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - current_node := _elna_parser_statements(); - _conditional_statements_set_statements(result, current_node); - - _conditional_statements_set_next(result, 0); - return result -end; - -proc _elna_tac_conditional_statements(parser_node: Word, after_end_label: Word, symbol_table: Word); -var - condition_label: Word; - current_node: Word; - instruction: Word; - current_instruction: Word; - first_instruction: Word; -begin - (* Compile condition. *) - current_node := _conditional_statements_get_condition(parser_node); - first_instruction := _elna_tac_binary_expression(current_node, symbol_table); - - (* condition_label is the label in front of the next elsif condition or end. *) - condition_label := label_counter; - label_counter := label_counter + 1; - - current_instruction := _elna_tac_beqz(ElnaTacRegister.t0, condition_label, 0); - _elna_tac_instruction_set_next(first_instruction, current_instruction); - - current_node := _conditional_statements_get_statements(parser_node); - instruction := _elna_tac_statements(current_node, symbol_table); - if instruction <> 0 then - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction - end; - - instruction := _elna_tac_jump(after_end_label, 0); - _elna_tac_instruction_set_next(current_instruction, instruction); - - current_instruction := _elna_tac_label(condition_label, 0); - _elna_tac_instruction_set_next(instruction, current_instruction); - - return first_instruction -end; - -(** - * Conditional statements is a list of pairs: condition and statements. - * Used for example to represent if and elsif blocks with beloning statements. - *) -proc _conditional_statements_size(); - return 12 -end; - -proc _conditional_statements_get_condition(this: Word); - return this^ -end; - -proc _conditional_statements_set_condition(this: Word, value: Word); -begin - this^ := value -end; - -proc _conditional_statements_get_statements(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _conditional_statements_set_statements(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _conditional_statements_get_next(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _conditional_statements_set_next(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _if_statement_size(); - return 16 -end; - -proc _if_statement_get_conditionals(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _if_statement_set_conditionals(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _if_statement_get_else(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _if_statement_set_else(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _elna_parser_if_statement(); -var - current_node: Word; - result: Word; - object_size: Word; - token_kind: Word; - previous_conditional: Word; - next_conditional: Word; -begin - object_size := _if_statement_size(); - result := _allocate(object_size); - - _node_set_kind(result, NodeKind.if_statement); - _statement_set_next(result, 0); - - previous_conditional := _elna_parser_conditional_statements(); - _if_statement_set_conditionals(result, previous_conditional); - - .elna_parser_if_statement_loop; - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind._elsif then - next_conditional := _elna_parser_conditional_statements(); - _conditional_statements_set_next(previous_conditional, next_conditional); - previous_conditional = next_conditional; - - goto elna_parser_if_statement_loop - elsif token_kind = ElnaLexerKind._else then - _elna_lexer_skip_token(); - - current_node := _elna_parser_statements(); - _if_statement_set_else(result, current_node) - else - _if_statement_set_else(result, 0) - end; - _elna_lexer_skip_token(); - - return result -end; - -proc _elna_parser_statement(); -var - token_kind: Word; - result : Word; -begin - result := 0; - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind._goto then - result := _elna_parser_goto_statement() - elsif token_kind = ElnaLexerKind._if then - result := _elna_parser_if_statement() - elsif token_kind = ElnaLexerKind._return then - result := _elna_parser_return_statement() - elsif token_kind = ElnaLexerKind.dot then - result := _elna_parser_label_declaration() - elsif token_kind = ElnaLexerKind.identifier then - result := _elna_parser_designator(); - - if _node_get_kind(result) <> NodeKind.call then - result := _elna_parser_assign_statement(result) - end - end; - return result -end; - -proc _elna_parser_statements(); -var - token_kind: Word; - previous_statement: Word; - next_statement: Word; - first_statement: Word; -begin - _skip_empty_lines(); - - first_statement := _elna_parser_statement(); - previous_statement := first_statement; - if previous_statement = 0 then - goto elna_parser_statements_end - end; - - .elna_parser_statement_loop; - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind.semicolon then - _elna_lexer_skip_token(); - _skip_empty_lines(); - next_statement := _elna_parser_statement(); - _statement_set_next(previous_statement, next_statement); - previous_statement := next_statement; - - if previous_statement <> 0 then - goto elna_parser_statement_loop - end - end; - .elna_parser_statements_end; - _skip_empty_lines(); - - return first_statement -end; - -proc _elna_tac_statements(parser_node: Word, symbol_table: Word); -var - current_statement: Word; - instruction: Word; - first_instruction: Word; - current_instruction: Word; -begin - current_statement := parser_node; - first_instruction := 0; - - .elna_tac_statements_loop; - if current_statement <> 0 then - instruction := _elna_tac_statement(current_statement, symbol_table); - current_statement := _statement_get_next(current_statement); - if instruction = 0 then - goto elna_tac_statements_loop - end; - if first_instruction = 0 then - first_instruction := instruction - else - _elna_tac_instruction_set_next(current_instruction, instruction) - end; - current_instruction := instruction; - goto elna_tac_statements_loop - end; - return first_instruction -end; - -proc _elna_tac_if_statement(parser_node: Word, symbol_table: Word); -var - current_node: Word; - after_end_label: Word; - condition_label: Word; - first_instruction: Word; - instruction: Word; - current_instruction: Word; -begin - after_end_label := label_counter; - label_counter := label_counter + 1; - - current_node := _if_statement_get_conditionals(parser_node); - first_instruction := _elna_tac_conditional_statements(current_node, after_end_label, symbol_table); - current_instruction := first_instruction; - - .elna_tac_if_statement_loop; - current_node := _conditional_statements_get_next(current_node); - if current_node <> 0 then - instruction := _elna_tac_conditional_statements(current_node, after_end_label, symbol_table); - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction; - goto elna_tac_if_statement_loop - end; - current_node := _if_statement_get_else(parser_node); - - if current_node <> 0 then - instruction := _elna_tac_statements(current_node, symbol_table); - if instruction <> 0 then - _elna_tac_instruction_set_next(current_instruction, instruction); - current_instruction := instruction - end - end; - instruction := _elna_tac_label(after_end_label, 0); - _elna_tac_instruction_set_next(current_instruction, instruction); - - return first_instruction -end; - -proc _elna_tac_statement(parser_node: Word, symbol_table: Word); -var - statement_kind: Word; - instruction: Word; -begin - statement_kind := _node_get_kind(parser_node); - - if statement_kind = NodeKind.goto_statement then - instruction := _elna_tac_goto_statement(parser_node) - elsif statement_kind = NodeKind.if_statement then - instruction := _elna_tac_if_statement(parser_node, symbol_table) - elsif statement_kind = NodeKind.return_statement then - instruction := _elna_tac_return_statement(parser_node, symbol_table) - elsif statement_kind = NodeKind.label_declaration then - instruction := _elna_tac_label_declaration(parser_node) - elsif statement_kind = NodeKind.call then - instruction := _elna_tac_call(parser_node, symbol_table) - elsif statement_kind = NodeKind.assign_statement then - instruction := _elna_tac_assign_statement(parser_node, symbol_table) - else - instruction := 0 - end; - return instruction -end; - -(** - * Writes a regster name to the standard output. - * - * Parameters: - * register_character - Register character. - * register_number - Register number. - *) -proc _write_register(register_character: Word, register_number: Word); -begin - _write_c(register_character); - _write_c(register_number + '0') -end; - -proc _type_get_kind(this: Word); - return this^ -end; - -proc _type_set_kind(this: Word, value: Word); -begin - this^ := value -end; - -proc _type_get_size(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _type_set_size(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _enumeration_type_size(); - return 16 -end; - -proc _enumeration_type_get_members(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _enumeration_type_set_members(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _enumeration_type_get_length(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _enumeration_type_set_length(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _enumeration_type_expression_size(); - return 12 -end; - -proc _enumeration_type_expression_get_members(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _enumeration_type_expression_set_members(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _enumeration_type_expression_get_length(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _enumeration_type_expression_set_length(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _record_type_size(); - return 16 -end; - -proc _record_type_get_members(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _record_type_set_members(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _record_type_get_length(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _record_type_set_length(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _record_type_expression_size(); - return 12 -end; - -proc _record_type_expression_get_members(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _record_type_expression_set_members(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _record_type_expression_get_length(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _record_type_expression_set_length(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _named_type_expression_size(); - return 12 -end; - -proc _named_type_expression_get_name(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _named_type_expression_set_name(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _named_type_expression_get_length(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _named_type_expression_set_length(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _elna_parser_record_type_expression(); -var - entry: Word; - member_count: Word; - memory_start: Word; - field_name: Word; - field_length: Word; - field_type: Word; - token_kind: Word; - type_expression_size: Word; - result: Word; - previous_entry: Word; -begin - _elna_lexer_skip_token(); - member_count := 0; - memory_start := 0; - - _elna_lexer_read_token(@token_kind); - if token_kind = ElnaLexerKind._end then - goto elna_parser_record_type_expression_end - end; - .elna_parser_record_type_expression_loop; - entry := _allocate(16); - member_count := member_count + 1; - - field_name := _elna_lexer_global_get_start(); - field_length := _elna_lexer_global_get_end() - field_name; - - entry^ := field_name; - entry := entry + 4; - - entry^ := field_length; - entry := entry + 4; - - (* Skip the identifier. *) - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - field_type := _elna_parser_type_expression(); - - entry^ := field_type; - entry := entry + 4; - - entry^ := 0; - if memory_start = 0 then - memory_start := entry - 12 - else - previous_entry^ := entry - 12 - end; - previous_entry := entry; - - _elna_lexer_read_token(@token_kind); - if token_kind = ElnaLexerKind.semicolon then - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - goto elna_parser_record_type_expression_loop - end; - - .elna_parser_record_type_expression_end; - _elna_lexer_skip_token(); - - type_expression_size := _enumeration_type_expression_size(); - result := _allocate(type_expression_size); - - _node_set_kind(result, NodeKind.record_type_expression); - _record_type_expression_set_members(result, memory_start); - _record_type_expression_set_length(result, member_count); - - return result -end; - -proc _elna_parser_enumeration_type_expression(); -var - token_kind: Word; - enumeration_name: Word; - name_length: Word; - memory_start: Word; - member_count: Word; - result: Word; - type_expression_size: Word; - entry: Word; - previous_entry: Word; -begin - _elna_lexer_skip_token(); - memory_start := 0; - member_count := 0; - - _elna_lexer_read_token(@token_kind); - if token_kind = ElnaLexerKind.right_paren then - goto elna_parser_enumeration_type_expression_end - end; - .elna_parser_enumeration_type_expression_loop; - entry := _allocate(12); - member_count := member_count + 1; - - enumeration_name := _elna_lexer_global_get_start(); - name_length := _elna_lexer_global_get_end() - enumeration_name; - - entry^ := enumeration_name; - entry := entry + 4; - - entry^ := name_length; - entry := entry + 4; - - entry^ := 0; - if memory_start = 0 then - memory_start := entry - 8 - else - previous_entry^ := entry - 8 - end; - previous_entry := entry; - - (* Skip the identifier. *) - _elna_lexer_skip_token(); - - _elna_lexer_read_token(@token_kind); - if token_kind = ElnaLexerKind.comma then - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - goto elna_parser_enumeration_type_expression_loop - end; - - .elna_parser_enumeration_type_expression_end; - _elna_lexer_skip_token(); - - type_expression_size := _enumeration_type_expression_size(); - result := _allocate(type_expression_size); - - _node_set_kind(result, NodeKind.enumeration_type_expression); - _enumeration_type_expression_set_members(result, memory_start); - _enumeration_type_expression_set_length(result, member_count); - - return result -end; - -(** - * Reads and creates enumeration type representation. - * - * record - * type_kind: Word; - * size: Word; - * members: StringArray; - * length: Word - * end; - * - * Returns enumeration type description. - *) -proc _elna_name_type_enumeration(parser_node: Word); -var - result: Word; - memory_start: Word; - member_count: Word; - member_array_size: Word; - member_array_start: Word; - member_array_current: Word; -begin - member_array_size := _enumeration_type_size(); - result := _allocate(member_array_size); - - memory_start := _enumeration_type_expression_get_members(parser_node); - member_count := _enumeration_type_expression_get_length(parser_node); - - (* Copy the list of enumeration members into an array of strings. *) - member_array_size := member_count * 8; - member_array_start := _allocate(member_array_size); - member_array_current := member_array_start; - - .elna_name_type_enumeration_loop; - if member_count > 0 then - member_array_current^ := memory_start^; - member_array_current := member_array_current + 4; - memory_start := memory_start + 4; - - member_array_current^ := memory_start^; - member_array_current := member_array_current + 4; - memory_start := memory_start + 4; - - memory_start := memory_start^; - member_count := member_count - 1; - goto elna_name_type_enumeration_loop - end; - member_count := _enumeration_type_expression_get_length(parser_node); - - _type_set_kind(result, TypeKind.enumeration); - _type_set_size(result, 4); - _enumeration_type_set_members(result, member_array_start); - _enumeration_type_set_length(result, member_count); - - return _type_info_create(result) -end; - -proc _elna_name_type_record(parser_node: Word); -var - result: Word; - memory_start: Word; - member_count: Word; - member_array_size: Word; - member_array_start: Word; - member_array_current: Word; -begin - member_array_size := _record_type_size(); - result := _allocate(member_array_size); - - memory_start := _record_type_expression_get_members(parser_node); - member_count := _record_type_expression_get_length(parser_node); - - member_array_size := member_count * 12; - member_array_start := _allocate(member_array_size); - member_array_current := member_array_start; - - .elna_name_type_record_loop; - if member_count > 0 then - member_array_current^ := memory_start^; - member_array_current := member_array_current + 4; - memory_start := memory_start + 4; - - member_array_current^ := memory_start^; - member_array_current := member_array_current + 4; - memory_start := memory_start + 4; - - member_array_current^ := _elna_name_type_expression(memory_start^); - member_array_current := member_array_current + 4; - memory_start := memory_start + 4; - - memory_start := memory_start^; - member_count := member_count - 1; - goto elna_name_type_record_loop - end; - member_count := _record_type_expression_get_length(parser_node); - - _type_set_kind(result, TypeKind._record); - _type_set_size(result, member_count * 4); - _record_type_set_members(result, member_array_start); - _record_type_set_length(result, member_count); - - return _type_info_create(result) -end; - -proc _elna_parser_named_type_expression(); -var - type_expression_size: Word; - result: Word; - type_name: Word; - name_length: Word; -begin - type_expression_size := _named_type_expression_size(); - result := _allocate(type_expression_size); - - _node_set_kind(result, NodeKind.named_type_expression); - type_name := _elna_lexer_global_get_start(); - name_length := _elna_lexer_global_get_end() - type_name; - _named_type_expression_set_name(result, type_name); - _named_type_expression_set_length(result, name_length); - _elna_lexer_skip_token(); - - return result -end; - -proc _elna_parser_type_expression(); -var - token_kind: Word; - result: Word; -begin - result := 0; - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind.identifier then - result := _elna_parser_named_type_expression() - elsif token_kind = ElnaLexerKind.left_paren then - result := _elna_parser_enumeration_type_expression() - elsif token_kind = ElnaLexerKind._record then - result := _elna_parser_record_type_expression() - end; - return result -end; - -proc _elna_name_type_expression(parser_node: Word); -var - token_kind: Word; - type_name: Word; - name_length: Word; - result: Word; -begin - token_kind := _node_get_kind(parser_node); - - if token_kind = NodeKind.named_type_expression then - type_name := _named_type_expression_get_name(parser_node); - name_length := _named_type_expression_get_length(parser_node); - - result := _symbol_table_lookup(@symbol_table_global, type_name, name_length); - result := _type_info_get_type(result) - elsif token_kind = NodeKind.enumeration_type_expression then - result := _elna_name_type_enumeration(parser_node) - elsif token_kind = NodeKind.record_type_expression then - result := _elna_name_type_record(parser_node) - end; - - return result -end; - -proc _type_info_get_type(this: Word); -begin - this := this + 4; - return this^ -end; - -(** - * Parameters: - * parameter_index - Parameter index. - *) -proc _parameter_info_create(parameter_index: Word); -var - offset: Word; - current_word: Word; - result: Word; -begin - result := _allocate(8); - current_word := result; - current_word^ := InfoKind.parameter_info; - - current_word := current_word + 4; - - (* Calculate the stack offset: 88 - (4 * parameter_counter) *) - offset := parameter_index * 4; - current_word^ := 88 - offset; - - return result -end; - -proc _parameter_info_get_offset(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _type_info_create(type_representation: Word); -var - result: Word; - current_word: Word; -begin - result := _allocate(8); - current_word := result; - current_word^ := InfoKind.type_info; - - current_word := current_word + 4; - current_word^ := type_representation; - - return result -end; - -(** - * Parameters: - * temporary_index - Parameter index. - *) -proc _temporary_info_create(temporary_index: Word); -var - offset: Word; - current_word: Word; - result: Word; -begin - result := _allocate(8); - current_word := result; - current_word^ := InfoKind.temporary_info; - current_word := current_word + 4; - - (* Calculate the stack offset: 4 * variable_counter. *) - current_word^ := temporary_index * 4; - - return result -end; - -(** - * Parameters: - * symbol_table - Local symbol table. - *) -proc _procedure_info_create(symbol_table: Word); -var - current_word: Word; - result: Word; -begin - result := _allocate(8); - current_word := result; - current_word^ := InfoKind.procedure_info; - current_word := current_word + 4; - - current_word^ := symbol_table; - - return result -end; - -proc _procedure_info_get_symbol_table(this: Word); -begin - this := this + 4; - return this^ -end; - -(** - * Parameters: - * parameter_index - Parameter index. - *) -proc _elna_name_procedure_parameter(parser_node: Word, parameter_index: Word, symbol_table: Word); -var - name_length: Word; - info: Word; - name_position: Word; -begin - name_position := _declaration_get_name(parser_node); - name_length := _declaration_get_length(parser_node); - - info := _parameter_info_create(parameter_index); - _symbol_table_enter(symbol_table, name_position, name_length, info) -end; - -(** - * Parameters: - * variable_index - Variable index. - *) -proc _elna_name_procedure_temporary(parser_node: Word, variable_index: Word, symbol_table: Word); -var - name_length: Word; - info: Word; - name_position: Word; -begin - name_position := _declaration_get_name(parser_node); - name_length := _declaration_get_length(parser_node); - - info := _temporary_info_create(variable_index); - _symbol_table_enter(symbol_table, name_position, name_length, info) -end; - -proc _elna_name_procedure_temporaries(parser_node: Word, symbol_table: Word); -var - temporary_counter: Word; -begin - temporary_counter := 0; - - .elna_name_procedure_temporaries_loop; - if parser_node <> 0 then - _elna_name_procedure_temporary(parser_node, temporary_counter, symbol_table); - - temporary_counter := temporary_counter + 1; - parser_node := _declaration_get_next(parser_node); - goto elna_name_procedure_temporaries_loop - end -end; - -proc _declaration_get_next(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _declaration_set_next(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _declaration_get_name(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _declaration_set_name(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _declaration_get_length(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _declaration_set_length(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -(* Kind + next declaration pointer + argument list + procedure name + statement list pointer + temporary list pointer. *) -proc _procedure_declaration_size(); - return 28 -end; - -proc _procedure_declaration_get_body(this: Word); -begin - this := this + 16; - return this^ -end; - -proc _procedure_declaration_set_body(this: Word, value: Word); -begin - this := this + 16; - this^ := value -end; - -proc _procedure_declaration_get_temporaries(this: Word); -begin - this := this + 20; - return this^ -end; - -proc _procedure_declaration_set_temporaries(this: Word, value: Word); -begin - this := this + 20; - this^ := value -end; - -proc _procedure_declaration_get_parameters(this: Word); -begin - this := this + 24; - return this^ -end; - -proc _procedure_declaration_set_parameters(this: Word, value: Word); -begin - this := this + 24; - this^ := value -end; - -proc _elna_parser_procedure_declaration(); -var - name_pointer: Word; - name_length: Word; - token_kind: Word; - result: Word; - declaration_size: Word; - parameter_head: Word; -begin - declaration_size := _procedure_declaration_size(); - result := _allocate(declaration_size); - - _node_set_kind(result, NodeKind.procedure_declaration); - _declaration_set_next(result, 0); - - (* Skip "proc ". *) - _elna_lexer_skip_token(); - - _elna_lexer_read_token(@token_kind); - name_pointer := _elna_lexer_global_get_start(); - name_length := _elna_lexer_global_get_end() - name_pointer; - - _declaration_set_name(result, name_pointer); - _declaration_set_length(result, name_length); - (* Skip procedure name. *) - _elna_lexer_skip_token(); - - (* Skip open paren. *) - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - parameter_head := 0; - - .elna_parser_procedure_declaration_parameter; - _elna_lexer_read_token(@token_kind); - - if token_kind <> ElnaLexerKind.right_paren then - name_pointer := _elna_parser_variable_declaration(); - if parameter_head = 0 then - parameter_head := name_pointer - else - _declaration_set_next(name_length, name_pointer) - end; - name_length := name_pointer; - - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind.comma then - _elna_lexer_skip_token(); - goto elna_parser_procedure_declaration_parameter - end - end; - (* Skip close paren. *) - _elna_lexer_skip_token(); - _procedure_declaration_set_parameters(result, parameter_head); - - (* Skip semicolon and newline. *) - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - parameter_head := _elna_parser_var_part(); - _procedure_declaration_set_temporaries(result, parameter_head); - - (* Skip semicolon, "begin" and newline. *) - _elna_lexer_read_token(@token_kind); - if token_kind = ElnaLexerKind._begin then - _elna_lexer_skip_token(); - parameter_head := _elna_parser_statements() - elsif token_kind = ElnaLexerKind._return then - parameter_head := _elna_parser_return_statement() - end; - _procedure_declaration_set_body(result, parameter_head); - - (* Skip the "end" keyword. *) - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - return result -end; - -proc _elna_tac_parameters(current_parameter: Word, new_symbol_table: Word); -var - name_pointer: Word; - name_length: Word; - parameter_counter: Word; - instruction: Word; - first_instruction: Word; - current_instruction: Word; - symbol_info: Word; -begin - first_instruction := 0; - parameter_counter := 0; - - .elna_tac_parameters_loop; - if current_parameter <> 0 then - name_pointer := _declaration_get_name(current_parameter); - name_length := _declaration_get_length(current_parameter); - symbol_info := _symbol_table_lookup(new_symbol_table, name_pointer, name_length); - - symbol_info := _parameter_info_get_offset(symbol_info); - - instruction := _elna_tac_store_word(ElnaTacRegister.a0 + parameter_counter, - ElnaTacRegister.sp, symbol_info); - if first_instruction = 0 then - first_instruction := instruction - else - _elna_tac_instruction_set_next(current_instruction, instruction) - end; - current_instruction := instruction; - - parameter_counter := parameter_counter + 1; - - current_parameter := _declaration_get_next(current_parameter); - goto elna_tac_parameters_loop - end; - return first_instruction -end; - -proc _elna_tac_procedure_declaration(parser_node: Word); -var - name_pointer: Word; - name_length: Word; - current_parameter: Word; - body: Word; - new_symbol_table: Word; - symbol_info: Word; - instruction: Word; - first_instruction: Word; - result: Word; - result_size: Word; -begin - result_size := _elna_tac_declaration_size(); - result := _allocate(result_size); - - _elna_tac_declaration_set_next(result, 0); - - name_pointer := _declaration_get_name(parser_node); - name_length := _declaration_get_length(parser_node); - - _elna_tac_declaration_set_name(result, name_pointer); - _elna_tac_declaration_set_length(result, name_length); - - symbol_info := _symbol_table_lookup(@symbol_table_global, name_pointer, name_length); - new_symbol_table := _procedure_info_get_symbol_table(symbol_info); - - (* Write the prologue. *) - first_instruction := _elna_tac_instruction_create(ElnaTacOperator.start); - - current_parameter := _procedure_declaration_get_parameters(parser_node); - current_parameter := _elna_tac_parameters(current_parameter, new_symbol_table); - _elna_tac_instruction_set_next(first_instruction, current_parameter); - - body := _procedure_declaration_get_body(parser_node); - instruction := _elna_tac_statements(body, new_symbol_table); - _elna_tac_instruction_set_next(first_instruction, instruction); - - (* Write the epilogue. *) - instruction := _elna_tac_instruction_create(ElnaTacOperator.ret); - _elna_tac_instruction_set_next(first_instruction, instruction); - - _elna_tac_declaration_set_body(result, first_instruction); - - return result -end; - -proc _elna_parser_procedures(); -var - parser_node: Word; - result: Word; - current_declaration: Word; - token_kind: Word; -begin - result := 0; - - .elna_parser_procedures_loop; - _skip_empty_lines(); - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind._proc then - parser_node := _elna_parser_procedure_declaration(); - if result = 0 then - result := parser_node - else - _declaration_set_next(current_declaration, parser_node) - end; - current_declaration := parser_node; - - (* Skip semicolon. *) - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - goto elna_parser_procedures_loop - end; - return result -end; - -proc _elna_tac_procedures(parser_node: Word); -var - result: Word; - current_procedure: Word; - first_procedure: Word; -begin - first_procedure := 0; - - .elna_tac_procedures_loop; - if parser_node = 0 then - goto elna_tac_procedures_end - end; - result := _elna_tac_procedure_declaration(parser_node); - if first_procedure = 0 then - first_procedure := result - else - _elna_tac_declaration_set_next(current_procedure, result) - end; - current_procedure := result; - - parser_node := _declaration_get_next(parser_node); - goto elna_tac_procedures_loop; - - .elna_tac_procedures_end; - return first_procedure -end; - -(** - * Skips comments. - *) -proc _skip_empty_lines(); -var - token_kind: Word; -begin - .skip_empty_lines_rerun; - - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind.comment then - _elna_lexer_skip_token(); - goto skip_empty_lines_rerun - end -end; - - -proc _type_declaration_size(); - return 20 -end; - -proc _type_declaration_get_type(this: Word); -begin - this := this + 16; - return this^ -end; - -proc _type_declaration_set_type(this: Word, value: Word); -begin - this := this + 16; - this^ := value -end; - -proc _elna_parser_type_declaration(); -var - token_kind: Word; - type_name: Word; - name_length: Word; - parser_node: Word; - result: Word; - declaration_size: Word; -begin - _elna_lexer_read_token(@token_kind); - type_name := _elna_lexer_global_get_start(); - name_length := _elna_lexer_global_get_end() - type_name; - - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - parser_node := _elna_parser_type_expression(); - declaration_size := _type_declaration_size(); - result := _allocate(declaration_size); - - _node_set_kind(result, NodeKind.type_declaration); - _declaration_set_next(result, 0); - _declaration_set_name(result, type_name); - _declaration_set_length(result, name_length); - _type_declaration_set_type(result, parser_node); - - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - return result -end; - -proc _elna_name_type_declaration(parser_node: Word); -var - type_name: Word; - name_length: Word; - type_info: Word; -begin - type_name := _declaration_get_name(parser_node); - name_length := _declaration_get_length(parser_node); - - parser_node := _type_declaration_get_type(parser_node); - type_info := _elna_name_type_expression(parser_node); - - _symbol_table_enter(@symbol_table_global, type_name, name_length, type_info) -end; - -proc _elna_type_type_declaration(parser_node: Word); -begin -end; - -proc _elna_parser_type_part(); -var - token_kind: Word; - parser_node: Word; - result: Word; - current_declaration: Word; -begin - result := 0; - _skip_empty_lines(); - _elna_lexer_read_token(@token_kind); - - if token_kind <> ElnaLexerKind._type then - goto elna_parser_type_part_end - end; - _elna_lexer_skip_token(); - - .elna_parser_type_part_loop; - _skip_empty_lines(); - - _elna_lexer_read_token(@token_kind); - if token_kind = ElnaLexerKind.identifier then - parser_node := _elna_parser_type_declaration(); - - if result = 0 then - result := parser_node - else - _declaration_set_next(current_declaration, parser_node) - end; - current_declaration := parser_node; - goto elna_parser_type_part_loop - end; - - .elna_parser_type_part_end; - return result -end; - -proc _variable_declaration_size(); - return 20 -end; - -proc _variable_declaration_get_type(this: Word); -begin - this := this + 16; - return this^ -end; - -proc _variable_declaration_set_type(this: Word, value: Word); -begin - this := this + 16; - this^ := value -end; - -proc _elna_parser_variable_declaration(); -var - token_kind: Word; - name: Word; - name_length: Word; - variable_type: Word; - result: Word; - declaration_size: Word; -begin - _elna_lexer_read_token(@token_kind); - - name := _elna_lexer_global_get_start(); - name_length := _elna_lexer_global_get_end() - name; - - (* Skip the variable name and colon with the type. *) - _elna_lexer_skip_token(); - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - variable_type := _elna_parser_type_expression(); - - declaration_size := _variable_declaration_size(); - result := _allocate(declaration_size); - - _node_set_kind(result, NodeKind.variable_declaration); - _declaration_set_next(result, 0); - _declaration_set_name(result, name); - _declaration_set_length(result, name_length); - _variable_declaration_set_type(result, variable_type); - - return result -end; - -proc _elna_tac_variable_declaration(parser_tree: Word); -var - name: Word; - name_length: Word; - variable_type: Word; - result: Word; - result_size: Word; -begin - result_size := _elna_tac_declaration_size(); - result := _allocate(result_size); - - _elna_tac_declaration_set_next(result, 0); - - name := _declaration_get_name(parser_tree); - name_length := _declaration_get_length(parser_tree); - variable_type := _variable_declaration_get_type(parser_tree); - - _elna_tac_declaration_set_name(result, name); - _elna_tac_declaration_set_length(result, name_length); - - name := _named_type_expression_get_name(variable_type); - name_length := _named_type_expression_get_length(variable_type); - - if _string_compare("Array", 5, name, name_length) then - (* Else we assume this is a zeroed 4096 bytes big array. *) - _elna_tac_declaration_set_body(result, 4096) - else - _elna_tac_declaration_set_body(result, 4) - end; - return result -end; - -proc _elna_tac_type_field(name_pointer: Word, name_length: Word, field_pointer: Word, field_offset: Word); -var - result_size: Word; - first_result: Word; - second_result: Word; - new_name: Word; - new_length: Word; - field_length: Word; - instruction: Word; - name_target: Word; - next_instruction: Word; -begin - result_size := _elna_tac_declaration_size(); - field_length := field_pointer + 4; - field_length := field_length^; - new_length := field_length + name_length; - new_length := new_length + 5; - - first_result := _allocate(result_size); - _elna_tac_declaration_set_next(first_result, 0); - - new_name := _allocate(new_length); - - name_target := new_name; - _memcpy(name_target, name_pointer, name_length); - name_target := name_target + name_length; - _memcpy(name_target, "_get_", 5); - name_target := name_target + 5; - _memcpy(name_target, field_pointer^, field_length); - - _elna_tac_declaration_set_name(first_result, new_name); - _elna_tac_declaration_set_length(first_result, new_length); - - instruction := _elna_tac_add_immediate(ElnaTacRegister.a0, ElnaTacRegister.a0, field_offset, 0); - next_instruction := _elna_tac_load_word(ElnaTacRegister.a0, ElnaTacRegister.a0, 0); - _elna_tac_instruction_set_next(instruction, next_instruction); - _elna_tac_declaration_set_body(first_result, instruction); - - second_result := _allocate(result_size); - _elna_tac_declaration_set_next(second_result, 0); - - new_name := _allocate(new_length); - - name_target := new_name; - _memcpy(name_target, name_pointer, name_length); - name_target := name_target + name_length; - _memcpy(name_target, "_set_", 5); - name_target := name_target + 5; - _memcpy(name_target, field_pointer^, field_length); - - _elna_tac_declaration_set_name(second_result, new_name); - _elna_tac_declaration_set_length(second_result, new_length); - - instruction := _elna_tac_add_immediate(ElnaTacRegister.a0, ElnaTacRegister.a0, field_offset, 0); - next_instruction := _elna_tac_store_word(ElnaTacRegister.a1, ElnaTacRegister.a0, 0); - _elna_tac_instruction_set_next(instruction, next_instruction); - _elna_tac_declaration_set_body(second_result, instruction); - - _elna_tac_declaration_set_next(first_result, second_result); - - return first_result -end; - -proc _elna_tac_type_record(name_pointer: Word, name_length: Word, type_representation: Word, current_result: Word); -var - result_size: Word; - first_result: Word; - result: Word; - type_size: Word; - new_name: Word; - new_length: Word; - instruction: Word; - field_count: Word; - field_offset: Word; - field_pointer: Word; -begin - result_size := _elna_tac_declaration_size(); - first_result := _allocate(result_size); - result := 0; - - (* Debug. Error stream output. - _syscall(2, name_pointer, name_length, 0, 0, 0, 64); *) - - type_size := _type_get_size(type_representation); - new_length := name_length + 5; - new_name := _allocate(new_length); - - _memcpy(new_name, name_pointer, name_length); - _memcpy(new_name + name_length, "_size", 5); - - _elna_tac_declaration_set_name(first_result, new_name); - _elna_tac_declaration_set_length(first_result, new_length); - - instruction := _elna_tac_load_immediate(ElnaTacRegister.a0, type_size, 0); - _elna_tac_declaration_set_body(first_result, instruction); - - field_count := _record_type_get_length(type_representation); - field_pointer := _record_type_get_members(type_representation); - field_offset := 0; - current_result^ := first_result; - - .elna_tac_type_record_fields; - if field_count > 0 then - result := _elna_tac_type_field(name_pointer, name_length, field_pointer, field_offset); - - _elna_tac_declaration_set_next(current_result^, result); - current_result^ := _elna_tac_declaration_get_next(result); - - field_offset := field_offset + 4; - field_count := field_count - 1; - field_pointer := field_pointer + 12; - goto elna_tac_type_record_fields - end; - - return first_result -end; - -proc _elna_tac_type_part(parser_node: Word); -var - name_pointer: Word; - name_length: Word; - result: Word; - first_result: Word; - symbol: Word; - info_type: Word; - type_kind: Word; - current_result: Word; - out_result: Word; -begin - first_result := 0; - - .elna_tac_type_part_loop; - if parser_node = 0 then - goto elna_tac_type_part_end - end; - - name_pointer := _declaration_get_name(parser_node); - name_length := _declaration_get_length(parser_node); - symbol := _symbol_table_lookup(@symbol_table_global, name_pointer, name_length); - - info_type := _type_info_get_type(symbol); - type_kind := _type_get_kind(info_type); - - if type_kind = TypeKind._record then - result := _elna_tac_type_record(name_pointer, name_length, info_type, @out_result) - else - result := 0; - out_result := 0 - end; - if first_result = 0 then - first_result := result; - current_result := out_result - elsif result <> 0 then - _elna_tac_declaration_set_next(current_result, result); - current_result := out_result - end; - parser_node := _declaration_get_next(parser_node); - goto elna_tac_type_part_loop; - - .elna_tac_type_part_end; - return first_result -end; - -proc _elna_parser_var_part(); -var - result: Word; - token_kind: Word; - variable_node: Word; - current_declaration: Word; -begin - result := 0; - _elna_lexer_read_token(@token_kind); - - if token_kind <> ElnaLexerKind._var then - goto elna_parser_var_part_end - end; - (* Skip "var". *) - _elna_lexer_skip_token(); - - .elna_parser_var_part_loop; - _skip_empty_lines(); - _elna_lexer_read_token(@token_kind); - - if token_kind = ElnaLexerKind.identifier then - variable_node := _elna_parser_variable_declaration(); - - (* Skip semicolon. *) - _elna_lexer_read_token(@token_kind); - _elna_lexer_skip_token(); - - if result = 0 then - result := variable_node - else - _declaration_set_next(current_declaration, variable_node) - end; - current_declaration := variable_node; - goto elna_parser_var_part_loop - end; - - .elna_parser_var_part_end; - return result -end; - -proc _elna_tac_var_part(parser_node: Word); -var - node: Word; - current_variable: Word; - first_variable: Word; -begin - first_variable := 0; - if parser_node = 0 then - goto elna_tac_var_part_end - end; - - .elna_tac_var_part_loop; - node := _elna_tac_variable_declaration(parser_node); - if first_variable = 0 then - first_variable := node - else - _elna_tac_declaration_set_next(current_variable, node) - end; - current_variable := node; - - parser_node := _declaration_get_next(parser_node); - if parser_node <> 0 then - goto elna_tac_var_part_loop - end; - - .elna_tac_var_part_end; - return first_variable -end; - -proc _module_declaration_size(); - return 16 -end; - -proc _module_declaration_get_types(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _module_declaration_set_types(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -proc _module_declaration_get_globals(this: Word); -begin - this := this + 8; - return this^ -end; - -proc _module_declaration_set_globals(this: Word, value: Word); -begin - this := this + 8; - this^ := value -end; - -proc _module_declaration_get_procedures(this: Word); -begin - this := this + 12; - return this^ -end; - -proc _module_declaration_set_procedures(this: Word, value: Word); -begin - this := this + 12; - this^ := value -end; - -proc _elna_parser_module_declaration(); -var - parser_node: Word; - declaration_size: Word; - result: Word; -begin - declaration_size := _module_declaration_size(); - result := _allocate(declaration_size); - - _node_set_kind(result, NodeKind.module_declaration); - - parser_node := _elna_parser_type_part(); - _module_declaration_set_types(result, parser_node); - - parser_node := _elna_parser_var_part(); - _module_declaration_set_globals(result, parser_node); - - parser_node := _elna_parser_procedures(); - _module_declaration_set_procedures(result, parser_node); - - return result -end; - -(** - * Process the source code and print the generated code. - *) -proc _elna_tac_module_declaration(parser_node: Word); -var - data_part: Word; - code_part: Word; - type_part: Word; - current_declaration: Word; - next_declaration: Word; -begin - type_part := _module_declaration_get_types(parser_node); - type_part := _elna_tac_type_part(type_part); - - data_part := _module_declaration_get_globals(parser_node); - data_part := _elna_tac_var_part(data_part); - - code_part := _module_declaration_get_procedures(parser_node); - code_part := _elna_tac_procedures(code_part); - - current_declaration := code_part; - - .elna_tac_module_declaration_types; - next_declaration := _elna_tac_declaration_get_next(current_declaration); - if next_declaration <> 0 then - current_declaration := next_declaration; - - goto elna_tac_module_declaration_types - end; - _elna_tac_declaration_set_next(current_declaration, type_part); - - return _elna_tac_module_create(data_part, code_part) -end; - -proc _elna_name_procedure_declaration(parser_node: Word); -var - name_pointer: Word; - name_length: Word; - new_symbol_table: Word; - parameter_counter: Word; - symbol_info: Word; - current_parameter: Word; -begin - new_symbol_table := _symbol_table_create(); - symbol_info := _procedure_info_create(new_symbol_table); - - name_pointer := _declaration_get_name(parser_node); - name_length := _declaration_get_length(parser_node); - - current_parameter := _procedure_declaration_get_parameters(parser_node); - parameter_counter := 0; - .elna_name_procedure_declaration_parameter; - if current_parameter <> 0 then - _elna_name_procedure_parameter(current_parameter, parameter_counter, new_symbol_table); - parameter_counter := parameter_counter + 1; - - current_parameter := _declaration_get_next(current_parameter); - goto elna_name_procedure_declaration_parameter - end; - current_parameter := _procedure_declaration_get_temporaries(parser_node); - _elna_name_procedure_temporaries(current_parameter, new_symbol_table); - - _symbol_table_enter(@symbol_table_global, name_pointer, name_length, symbol_info) -end; - -proc _elna_type_procedure_declaration(parser_node: Word); -begin -end; - -proc _elna_name_module_declaration(parser_node: Word); -var - current_part: Word; - result: Word; -begin - current_part := _module_declaration_get_types(parser_node); - .elna_name_module_declaration_type; - if current_part <> 0 then - _elna_name_type_declaration(current_part); - current_part := _declaration_get_next(current_part); - - goto elna_name_module_declaration_type - end; - - current_part := _module_declaration_get_procedures(parser_node); - .elna_name_module_declaration_procedure; - if current_part <> 0 then - _elna_name_procedure_declaration(current_part); - current_part := _declaration_get_next(current_part); - - goto elna_name_module_declaration_procedure - end -end; - -proc _elna_type_module_declaration(parser_node: Word); -var - current_part: Word; -begin - current_part := _module_declaration_get_types(parser_node); - .elna_type_module_declaration_type; - if current_part <> 0 then - _elna_type_type_declaration(current_part); - current_part := _declaration_get_next(current_part); - - goto elna_type_module_declaration_type - end; - - current_part := _module_declaration_get_procedures(parser_node); - .elna_type_module_declaration_procedure; - if current_part <> 0 then - _elna_type_procedure_declaration(current_part); - current_part := _declaration_get_next(current_part); - - goto elna_type_module_declaration_procedure - end -end; - -proc _compile(); -var - parser_node: Word; - tac: Word; -begin - parser_node := _elna_parser_module_declaration(); - _elna_name_module_declaration(parser_node); - _elna_type_module_declaration(parser_node); - tac := _elna_tac_module_declaration(parser_node); - _elna_writer_module(tac) -end; - -(** - * Terminates the program. a0 contains the return code. - * - * Parameters: - * a0 - Status code. - *) -proc _exit(status: Word); -begin - _syscall(status, 0, 0, 0, 0, 0, 93) -end; - -(** - * Looks for a symbol in the given symbol table. - * - * Parameters: - * symbol_table - Symbol table. - * symbol_name - Symbol name pointer. - * name_length - Symbol name length. - * - * Returns the symbol pointer or 0 in a0. - *) -proc _symbol_table_lookup(symbol_table: Word, symbol_name: Word, name_length: Word); -var - result: Word; - symbol_table_length: Word; - current_name: Word; - current_length: Word; -begin - result := 0; - - (* The first word in the symbol table is its length, get it. *) - symbol_table_length := symbol_table^; - - (* Go to the first symbol position. *) - symbol_table := symbol_table + 4; - - .symbol_table_lookup_loop; - if symbol_table_length = 0 then - goto symbol_table_lookup_end - end; - - (* Symbol name pointer and length. *) - current_name := symbol_table^; - current_length := symbol_table + 4; - current_length := current_length^; - - (* If lengths don't match, exit and return nil. *) - if name_length <> current_length then - goto symbol_table_lookup_repeat - end; - (* If names don't match, exit and return nil. *) - if _memcmp(symbol_name, current_name, name_length) then - goto symbol_table_lookup_repeat - end; - (* Otherwise, the symbol is found. *) - result := symbol_table + 8; - result := result^; - goto symbol_table_lookup_end; - - .symbol_table_lookup_repeat; - symbol_table := symbol_table + 12; - symbol_table_length := symbol_table_length - 1; - goto symbol_table_lookup_loop; - - .symbol_table_lookup_end; - return result -end; - -(** - * Create a new local symbol table in the symbol memory region after the last - * known symbol table. - *) -proc _symbol_table_create(); -var - new_symbol_table: Word; - table_length: Word; - current_table: Word; -begin - new_symbol_table := symbol_table_store; - - .symbol_table_create_loop; - table_length := new_symbol_table^; - - if table_length <> 0 then - table_length := table_length * 12; - table_length := table_length + 4; - new_symbol_table := new_symbol_table + table_length; - goto symbol_table_create_loop - end; - - return new_symbol_table -end; - -(** - * Inserts a symbol into the table. - * - * Parameters: - * symbol_table - Symbol table. - * symbol_name - Symbol name pointer. - * name_length - Symbol name length. - * symbol - Symbol pointer. - *) -proc _symbol_table_enter(symbol_table: Word, symbol_name: Word, name_length: Word, symbol: Word); -var - table_length: Word; - symbol_pointer: Word; -begin - (* The first word in the symbol table is its length, get it. *) - table_length := symbol_table^; - - (* Calculate the offset for the new symbol. *) - symbol_pointer := table_length * 12; - symbol_pointer := symbol_pointer + 4; - symbol_pointer := symbol_table + symbol_pointer; - - symbol_pointer^ := symbol_name; - symbol_pointer := symbol_pointer + 4; - symbol_pointer^ := name_length; - symbol_pointer := symbol_pointer + 4; - symbol_pointer^ := symbol; - - (* Increment the symbol table length. *) - table_length := table_length + 1; - symbol_table^ := table_length -end; - -proc _symbol_table_build(); -var - current_info: Word; - current_type: Word; -begin - (* Set the table length to 0. *) - symbol_table_global := 0; - - current_type := _allocate(8); - _type_set_kind(current_type, TypeKind.primitive); - _type_set_size(current_type, 4); - - (* Enter built-in symbols. *) - current_info := _type_info_create(current_type); - _symbol_table_enter(@symbol_table_global, "Word", 4, current_info); - - current_info := _type_info_create(current_type); - _symbol_table_enter(@symbol_table_global, "Array", 5, current_info) -end; - -(** - * Assigns some value to at array index. - * - * Parameters: - * array - Array pointer. - * index - Index (word offset into the array). - * data - Data to assign. - *) -proc _assign_at(array: Word, index: Word, data: Word); -var - target: Word; -begin - target := index - 1; - target := target * 4; - target := array + target; - - target^ := data -end; - -proc _get_at(array: Word, index: Word); -var - target: Word; -begin - target := index - 1; - target := target * 4; - target := array + target; - - return target^ -end; - -(** - * Initializes the array with character classes. - *) -proc _elna_lexer_classifications(); -var - code: Word; -begin - _assign_at(@classification, 1, ElnaLexerClass.eof); - _assign_at(@classification, 2, ElnaLexerClass.invalid); - _assign_at(@classification, 3, ElnaLexerClass.invalid); - _assign_at(@classification, 4, ElnaLexerClass.invalid); - _assign_at(@classification, 5, ElnaLexerClass.invalid); - _assign_at(@classification, 6, ElnaLexerClass.invalid); - _assign_at(@classification, 7, ElnaLexerClass.invalid); - _assign_at(@classification, 8, ElnaLexerClass.invalid); - _assign_at(@classification, 9, ElnaLexerClass.invalid); - _assign_at(@classification, 10, ElnaLexerClass.space); - _assign_at(@classification, 11, ElnaLexerClass.space); - _assign_at(@classification, 12, ElnaLexerClass.invalid); - _assign_at(@classification, 13, ElnaLexerClass.invalid); - _assign_at(@classification, 14, ElnaLexerClass.space); - _assign_at(@classification, 15, ElnaLexerClass.invalid); - _assign_at(@classification, 16, ElnaLexerClass.invalid); - _assign_at(@classification, 17, ElnaLexerClass.invalid); - _assign_at(@classification, 18, ElnaLexerClass.invalid); - _assign_at(@classification, 19, ElnaLexerClass.invalid); - _assign_at(@classification, 20, ElnaLexerClass.invalid); - _assign_at(@classification, 21, ElnaLexerClass.invalid); - _assign_at(@classification, 22, ElnaLexerClass.invalid); - _assign_at(@classification, 23, ElnaLexerClass.invalid); - _assign_at(@classification, 24, ElnaLexerClass.invalid); - _assign_at(@classification, 25, ElnaLexerClass.invalid); - _assign_at(@classification, 26, ElnaLexerClass.invalid); - _assign_at(@classification, 27, ElnaLexerClass.invalid); - _assign_at(@classification, 28, ElnaLexerClass.invalid); - _assign_at(@classification, 29, ElnaLexerClass.invalid); - _assign_at(@classification, 30, ElnaLexerClass.invalid); - _assign_at(@classification, 31, ElnaLexerClass.invalid); - _assign_at(@classification, 32, ElnaLexerClass.invalid); - _assign_at(@classification, 33, ElnaLexerClass.space); - _assign_at(@classification, 34, ElnaLexerClass.single); - _assign_at(@classification, 35, ElnaLexerClass.double_quote); - _assign_at(@classification, 36, ElnaLexerClass.other); - _assign_at(@classification, 37, ElnaLexerClass.other); - _assign_at(@classification, 38, ElnaLexerClass.single); - _assign_at(@classification, 39, ElnaLexerClass.single); - _assign_at(@classification, 40, ElnaLexerClass.single_quote); - _assign_at(@classification, 41, ElnaLexerClass.left_paren); - _assign_at(@classification, 42, ElnaLexerClass.right_paren); - _assign_at(@classification, 43, ElnaLexerClass.asterisk); - _assign_at(@classification, 44, ElnaLexerClass.single); - _assign_at(@classification, 45, ElnaLexerClass.single); - _assign_at(@classification, 46, ElnaLexerClass.minus); - _assign_at(@classification, 47, ElnaLexerClass.dot); - _assign_at(@classification, 48, ElnaLexerClass.single); - _assign_at(@classification, 49, ElnaLexerClass.zero); - _assign_at(@classification, 50, ElnaLexerClass.digit); - _assign_at(@classification, 51, ElnaLexerClass.digit); - _assign_at(@classification, 52, ElnaLexerClass.digit); - _assign_at(@classification, 53, ElnaLexerClass.digit); - _assign_at(@classification, 54, ElnaLexerClass.digit); - _assign_at(@classification, 55, ElnaLexerClass.digit); - _assign_at(@classification, 56, ElnaLexerClass.digit); - _assign_at(@classification, 57, ElnaLexerClass.digit); - _assign_at(@classification, 58, ElnaLexerClass.digit); - _assign_at(@classification, 59, ElnaLexerClass.colon); - _assign_at(@classification, 60, ElnaLexerClass.single); - _assign_at(@classification, 61, ElnaLexerClass.less); - _assign_at(@classification, 62, ElnaLexerClass.equals); - _assign_at(@classification, 63, ElnaLexerClass.greater); - _assign_at(@classification, 64, ElnaLexerClass.other); - _assign_at(@classification, 65, ElnaLexerClass.single); - _assign_at(@classification, 66, ElnaLexerClass.alpha); - _assign_at(@classification, 67, ElnaLexerClass.alpha); - _assign_at(@classification, 68, ElnaLexerClass.alpha); - _assign_at(@classification, 69, ElnaLexerClass.alpha); - _assign_at(@classification, 70, ElnaLexerClass.alpha); - _assign_at(@classification, 71, ElnaLexerClass.alpha); - _assign_at(@classification, 72, ElnaLexerClass.alpha); - _assign_at(@classification, 73, ElnaLexerClass.alpha); - _assign_at(@classification, 74, ElnaLexerClass.alpha); - _assign_at(@classification, 75, ElnaLexerClass.alpha); - _assign_at(@classification, 76, ElnaLexerClass.alpha); - _assign_at(@classification, 77, ElnaLexerClass.alpha); - _assign_at(@classification, 78, ElnaLexerClass.alpha); - _assign_at(@classification, 79, ElnaLexerClass.alpha); - _assign_at(@classification, 80, ElnaLexerClass.alpha); - _assign_at(@classification, 81, ElnaLexerClass.alpha); - _assign_at(@classification, 82, ElnaLexerClass.alpha); - _assign_at(@classification, 83, ElnaLexerClass.alpha); - _assign_at(@classification, 84, ElnaLexerClass.alpha); - _assign_at(@classification, 85, ElnaLexerClass.alpha); - _assign_at(@classification, 86, ElnaLexerClass.alpha); - _assign_at(@classification, 87, ElnaLexerClass.alpha); - _assign_at(@classification, 88, ElnaLexerClass.alpha); - _assign_at(@classification, 89, ElnaLexerClass.alpha); - _assign_at(@classification, 90, ElnaLexerClass.alpha); - _assign_at(@classification, 91, ElnaLexerClass.alpha); - _assign_at(@classification, 92, ElnaLexerClass.single); - _assign_at(@classification, 93, ElnaLexerClass.backslash); - _assign_at(@classification, 94, ElnaLexerClass.single); - _assign_at(@classification, 95, ElnaLexerClass.single); - _assign_at(@classification, 96, ElnaLexerClass.alpha); - _assign_at(@classification, 97, ElnaLexerClass.other); - _assign_at(@classification, 98, ElnaLexerClass.hex); - _assign_at(@classification, 99, ElnaLexerClass.hex); - _assign_at(@classification, 100, ElnaLexerClass.hex); - _assign_at(@classification, 101, ElnaLexerClass.hex); - _assign_at(@classification, 102, ElnaLexerClass.hex); - _assign_at(@classification, 103, ElnaLexerClass.hex); - _assign_at(@classification, 104, ElnaLexerClass.alpha); - _assign_at(@classification, 105, ElnaLexerClass.alpha); - _assign_at(@classification, 106, ElnaLexerClass.alpha); - _assign_at(@classification, 107, ElnaLexerClass.alpha); - _assign_at(@classification, 108, ElnaLexerClass.alpha); - _assign_at(@classification, 109, ElnaLexerClass.alpha); - _assign_at(@classification, 110, ElnaLexerClass.alpha); - _assign_at(@classification, 111, ElnaLexerClass.alpha); - _assign_at(@classification, 112, ElnaLexerClass.alpha); - _assign_at(@classification, 113, ElnaLexerClass.alpha); - _assign_at(@classification, 114, ElnaLexerClass.alpha); - _assign_at(@classification, 115, ElnaLexerClass.alpha); - _assign_at(@classification, 116, ElnaLexerClass.alpha); - _assign_at(@classification, 117, ElnaLexerClass.alpha); - _assign_at(@classification, 118, ElnaLexerClass.alpha); - _assign_at(@classification, 119, ElnaLexerClass.alpha); - _assign_at(@classification, 120, ElnaLexerClass.alpha); - _assign_at(@classification, 121, ElnaLexerClass.x); - _assign_at(@classification, 122, ElnaLexerClass.alpha); - _assign_at(@classification, 123, ElnaLexerClass.alpha); - _assign_at(@classification, 124, ElnaLexerClass.other); - _assign_at(@classification, 125, ElnaLexerClass.single); - _assign_at(@classification, 126, ElnaLexerClass.other); - _assign_at(@classification, 127, ElnaLexerClass.single); - _assign_at(@classification, 128, ElnaLexerClass.invalid); - - code := 129; - - (* Set the remaining 129 - 256 bytes to transitionClassOther. *) - .create_classification_loop; - _assign_at(@classification, code, ElnaLexerClass.other); - code := code + 1; - - if code < 257 then - goto create_classification_loop - end -end; - -proc _elna_lexer_get_transition(current_state: Word, character_class: Word); -var - transition_table: Word; - row_position: Word; - column_position: Word; - target: Word; -begin - (* Each state is 8 bytes long (2 words: action and next state). - There are 22 character classes, so a transition row 8 * 22 = 176 bytes long. *) - row_position := current_state - 1; - row_position := row_position * 176; - - column_position := character_class - 1; - column_position := column_position * 8; - - target := _elna_lexer_get_transition_table(); - target := target + row_position; - - return target + column_position -end; - -(** - * Parameters: - * current_state - First index into transitions table. - * character_class - Second index into transitions table. - * action - Action to assign. - * next_state - Next state to assign. - *) -proc _elna_lexer_set_transition(current_state: Word, character_class: Word, action: Word, next_state: Word); -var - transition: Word; -begin - transition := _elna_lexer_get_transition(current_state, character_class); - - _elna_lexer_transition_set_action(transition, action); - _elna_lexer_transition_set_state(transition, next_state) -end; - -(* Sets same action and state transition for all character classes in one transition row. *) - -(** - * Parameters: - * current_state - Current state (Transition state enumeration). - * default_action - Default action (Callback). - * next_state - Next state (Transition state enumeration). - *) -proc _elna_lexer_default_transition(current_state: Word, default_action: Word, next_state: Word); -begin - _elna_lexer_set_transition(current_state, ElnaLexerClass.invalid, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.digit, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.alpha, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.space, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.colon, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.equals, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.left_paren, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.right_paren, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.asterisk, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.backslash, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.single, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.hex, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.zero, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.x, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.eof, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.dot, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.minus, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.single_quote, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.double_quote, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.greater, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.less, default_action, next_state); - _elna_lexer_set_transition(current_state, ElnaLexerClass.other, default_action, next_state) -end; - -(** - * The transition table describes transitions from one state to another, given - * a symbol (character class). - * - * The table has m rows and n columns, where m is the amount of states and n is - * the amount of classes. So given the current state and a classified character - * the table can be used to look up the next state. - *) -proc _elna_lexer_transitions(); -begin - (* Start state. *) - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.digit, ElnaLexerAction.accumulate, ElnaLexerState.decimal); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.alpha, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.space, ElnaLexerAction.skip, ElnaLexerState.start); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.colon, ElnaLexerAction.accumulate, ElnaLexerState.colon); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.equals, ElnaLexerAction.single, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.left_paren, ElnaLexerAction.accumulate, ElnaLexerState.left_paren); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.right_paren, ElnaLexerAction.single, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.asterisk, ElnaLexerAction.single, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.backslash, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.single, ElnaLexerAction.single, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.hex, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.zero, ElnaLexerAction.accumulate, ElnaLexerState.leading_zero); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.x, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.eof, ElnaLexerAction.eof, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.dot, ElnaLexerAction.single, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.minus, ElnaLexerAction.accumulate, ElnaLexerState.minus); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.single_quote, ElnaLexerAction.accumulate, ElnaLexerState.character); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.double_quote, ElnaLexerAction.accumulate, ElnaLexerState.string); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.greater, ElnaLexerAction.accumulate, ElnaLexerState.greater); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.less, ElnaLexerAction.accumulate, ElnaLexerState.less); - _elna_lexer_set_transition(ElnaLexerState.start, ElnaLexerClass.other, ElnaLexerAction.none, ElnaLexerState.finish); - - (* Colon state. *) - _elna_lexer_default_transition(ElnaLexerState.colon, ElnaLexerAction.finalize, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.colon, ElnaLexerClass.equals, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Identifier state. *) - _elna_lexer_default_transition(ElnaLexerState.identifier, ElnaLexerAction.key_id, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.digit, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - _elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.alpha, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - _elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.hex, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - _elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.zero, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - _elna_lexer_set_transition(ElnaLexerState.identifier, ElnaLexerClass.x, ElnaLexerAction.accumulate, ElnaLexerState.identifier); - - (* Decimal state. *) - _elna_lexer_default_transition(ElnaLexerState.decimal, ElnaLexerAction.integer, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.digit, ElnaLexerAction.accumulate, ElnaLexerState.decimal); - _elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.alpha, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.hex, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.zero, ElnaLexerAction.accumulate, ElnaLexerState.decimal); - _elna_lexer_set_transition(ElnaLexerState.decimal, ElnaLexerClass.x, ElnaLexerAction.none, ElnaLexerState.finish); - - (* Leading zero. *) - _elna_lexer_default_transition(ElnaLexerState.leading_zero, ElnaLexerAction.integer, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.digit, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.alpha, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.hex, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.zero, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.leading_zero, ElnaLexerClass.x, ElnaLexerAction.none, ElnaLexerState.dot); - - (* Greater state. *) - _elna_lexer_default_transition(ElnaLexerState.greater, ElnaLexerAction.finalize, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.greater, ElnaLexerClass.equals, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Minus state. *) - _elna_lexer_default_transition(ElnaLexerState.minus, ElnaLexerAction.finalize, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.minus, ElnaLexerClass.greater, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Left paren state. *) - _elna_lexer_default_transition(ElnaLexerState.left_paren, ElnaLexerAction.finalize, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.left_paren, ElnaLexerClass.asterisk, ElnaLexerAction.accumulate, ElnaLexerState.comment); - - (* Less state. *) - _elna_lexer_default_transition(ElnaLexerState.less, ElnaLexerAction.finalize, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.equals, ElnaLexerAction.composite, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.less, ElnaLexerClass.greater, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Hexadecimal after 0x. *) - _elna_lexer_default_transition(ElnaLexerState.dot, ElnaLexerAction.finalize, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.dot, ElnaLexerClass.dot, ElnaLexerAction.composite, ElnaLexerState.finish); - - (* Comment. *) - _elna_lexer_default_transition(ElnaLexerState.comment, ElnaLexerAction.accumulate, ElnaLexerState.comment); - _elna_lexer_set_transition(ElnaLexerState.comment, ElnaLexerClass.asterisk, ElnaLexerAction.accumulate, ElnaLexerState.closing_comment); - _elna_lexer_set_transition(ElnaLexerState.comment, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - - (* Closing comment. *) - _elna_lexer_default_transition(ElnaLexerState.closing_comment, ElnaLexerAction.accumulate, ElnaLexerState.comment); - _elna_lexer_set_transition(ElnaLexerState.closing_comment, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.closing_comment, ElnaLexerClass.right_paren, ElnaLexerAction.delimited, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.closing_comment, ElnaLexerClass.asterisk, ElnaLexerAction.accumulate, ElnaLexerState.closing_comment); - _elna_lexer_set_transition(ElnaLexerState.closing_comment, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - - (* Character. *) - _elna_lexer_default_transition(ElnaLexerState.character, ElnaLexerAction.accumulate, ElnaLexerState.character); - _elna_lexer_set_transition(ElnaLexerState.character, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.character, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.character, ElnaLexerClass.single_quote, ElnaLexerAction.delimited, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.character, ElnaLexerClass.backslash, ElnaLexerAction.accumulate, ElnaLexerState.character_escape); - - (* Escape sequence in a character. *) - _elna_lexer_default_transition(ElnaLexerState.character_escape, ElnaLexerAction.accumulate, ElnaLexerState.character); - _elna_lexer_set_transition(ElnaLexerState.character_escape, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.character_escape, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - - (* String. *) - _elna_lexer_default_transition(ElnaLexerState.string, ElnaLexerAction.accumulate, ElnaLexerState.string); - _elna_lexer_set_transition(ElnaLexerState.string, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.string, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.string, ElnaLexerClass.double_quote, ElnaLexerAction.delimited, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.string, ElnaLexerClass.backslash, ElnaLexerAction.accumulate, ElnaLexerState.string_escape); - - (* Escape sequence in a string. *) - _elna_lexer_default_transition(ElnaLexerState.string_escape, ElnaLexerAction.accumulate, ElnaLexerState.string); - _elna_lexer_set_transition(ElnaLexerState.string_escape, ElnaLexerClass.invalid, ElnaLexerAction.none, ElnaLexerState.finish); - _elna_lexer_set_transition(ElnaLexerState.string_escape, ElnaLexerClass.eof, ElnaLexerAction.none, ElnaLexerState.finish) -end; - -(** - * Transition table is saved after character classification table. - * Each character entry is 1 word long and there are 256 characters. - * 1024 = 256 * 4 - *) -proc _elna_lexer_get_transition_table(); - return @classification + 1024 -end; - -(** - * Lexer state is saved after the transition tables. - * Each transition table entry is 8 bytes long. The table has 16 rows (transition states) - * and 22 columns (character classes), so 2992 = 8 * 17 * 22. - *) -proc _elna_lexer_global_state(); -var - result: Word; -begin - result := _elna_lexer_get_transition_table(); - return result + 2992 -end; - -(** - * Gets pointer to the token start. - *) -proc _elna_lexer_global_get_start(); -var - target: Word; -begin - target := _elna_lexer_global_state() + 4; - return target^ -end; - -(** - * Sets pointer to the token start. - *) -proc _elna_lexer_global_set_start(new_start: Word); -var - target: Word; -begin - target := _elna_lexer_global_state() + 4; - target^ := new_start -end; - -(** - * Gets pointer to the token end. - *) -proc _elna_lexer_global_get_end(); -var - target: Word; -begin - target := _elna_lexer_global_state() + 8; - return target^ -end; - -(** - * Sets pointer to the token end. - *) -proc _elna_lexer_global_set_end(new_start: Word); -var - target: Word; -begin - target := _elna_lexer_global_state() + 8; - target^ := new_start -end; - -proc _elna_lexer_transition_get_action(this: Word); - return this^ -end; - -proc _elna_lexer_transition_set_action(this: Word, value: Word); -begin - this^ := value -end; - -proc _elna_lexer_transition_get_state(this: Word); -begin - this := this + 4; - return this^ -end; - -proc _elna_lexer_transition_set_state(this: Word, value: Word); -begin - this := this + 4; - this^ := value -end; - -(** - * Resets the lexer state for reading the next token. - *) -proc _elna_lexer_reset(); -var - state: Word; -begin - (* Transition start state is 1. *) - state := _elna_lexer_global_state(); - state^ := ElnaLexerState.start; - - state := _elna_lexer_global_get_start(); - _elna_lexer_global_set_end(state) -end; - -(** - * One time lexer initialization. - *) -proc _elna_lexer_initialize(code_pointer: Word); -begin - _elna_lexer_classifications(); - _elna_lexer_transitions(); - - _elna_lexer_global_set_start(code_pointer); - _elna_lexer_global_set_end(code_pointer) -end; - -proc _elna_lexer_next_transition(); -var - current_character: Word; - character_class: Word; - current_state: Word; -begin - current_character := _elna_lexer_global_get_end(); - current_character := _load_byte(current_character); - - character_class := _get_at(@classification, current_character + 1); - - current_state := _elna_lexer_global_state(); - current_state := current_state^; - - return _elna_lexer_get_transition(current_state, character_class) -end; - -proc _string_compare(lhs_pointer: Word, lhs_length: Word, rhs_pointer: Word, rhs_length: Word); -var - result: Word; -begin - result := 0; - - if lhs_length = rhs_length then - result := _memcmp(lhs_pointer, rhs_pointer, lhs_length); - result := result = 0 - end; - return result -end; - -proc _elna_lexer_classify_keyword(position_start: Word, position_end: Word); -var - result: Word; - token_length: Word; -begin - result := ElnaLexerKind.identifier; - token_length := position_end - position_start; - - if _string_compare(position_start, token_length, "const", 5) then - result := ElnaLexerKind._const - elsif _string_compare(position_start, token_length, "var", 3) then - result := ElnaLexerKind._var - elsif _string_compare(position_start, token_length, "proc", 4) then - result := ElnaLexerKind._proc - elsif _string_compare(position_start, token_length, "type", 4) then - result := ElnaLexerKind._type - elsif _string_compare(position_start, token_length, "begin", 5) then - result := ElnaLexerKind._begin - elsif _string_compare(position_start, token_length, "end", 3) then - result := ElnaLexerKind._end - elsif _string_compare(position_start, token_length, "return", 6) then - result := ElnaLexerKind._return - elsif _string_compare(position_start, token_length, "goto", 4) then - result := ElnaLexerKind._goto - elsif _string_compare(position_start, token_length, "if", 2) then - result := ElnaLexerKind._if - elsif _string_compare(position_start, token_length, "while", 5) then - result := ElnaLexerKind._while - elsif _string_compare(position_start, token_length, "then", 4) then - result := ElnaLexerKind._then - elsif _string_compare(position_start, token_length, "else", 4) then - result := ElnaLexerKind._else - elsif _string_compare(position_start, token_length, "elsif", 5) then - result := ElnaLexerKind._elsif - elsif _string_compare(position_start, token_length, "record", 6) then - result := ElnaLexerKind._record - elsif _string_compare(position_start, token_length, "or", 2) then - result := ElnaLexerKind._or - elsif _string_compare(position_start, token_length, "xor", 2) then - result := ElnaLexerKind._xor - end; - return result -end; - -proc _elna_lexer_classify_finalize(start_position: Word); -var - character: Word; - result: Word; -begin - result := 0; - character := _load_byte(start_position); - - if character = ':' then - result := ElnaLexerKind.colon - elsif character = '.' then - result := ElnaLexerKind.dot - elsif character = '(' then - result := ElnaLexerKind.left_paren - elsif character = '-' then - result := ElnaLexerKind.minus - elsif character = '<' then - result := ElnaLexerKind.less_than - elsif character = '>' then - result := ElnaLexerKind.greater_than - end; - return result -end; - -proc _elna_lexer_classify_single(start_position: Word); -var - character: Word; - result: Word; -begin - result := 0; - character := _load_byte(start_position); - - if character = ';' then - result := ElnaLexerKind.semicolon - elsif character = ',' then - result := ElnaLexerKind.comma - elsif character = ')' then - result := ElnaLexerKind.right_paren - elsif character = '@' then - result := ElnaLexerKind.at - elsif character = '~' then - result := ElnaLexerKind.not - elsif character = '&' then - result := ElnaLexerKind.and - elsif character = '+' then - result := ElnaLexerKind.plus - elsif character = '*' then - result := ElnaLexerKind.multiplication - elsif character = '=' then - result := ElnaLexerKind.equals - elsif character = '%' then - result := ElnaLexerKind.remainder - elsif character = '/' then - result := ElnaLexerKind.division - elsif character = '.' then - result := ElnaLexerKind.dot - elsif character = '^' then - result := ElnaLexerKind.hat - end; - return result -end; - -proc _elna_lexer_classify_composite(start_position: Word, one_before_last: Word); -var - first_character: Word; - last_character: Word; - result: Word; -begin - first_character := _load_byte(start_position); - last_character := _load_byte(one_before_last); - - if first_character = ':' then - result := ElnaLexerKind.assignment - elsif first_character = '<' then - if last_character = '=' then - result := ElnaLexerKind.less_equal - elsif last_character = '>' then - result := ElnaLexerKind.not_equal - end - elsif first_character = '>' then - if last_character = '=' then - result := ElnaLexerKind.greater_equal - end - end; - - return result -end; - -proc _elna_lexer_classify_delimited(start_position: Word, end_position: Word); -var - token_length: Word; - delimiter: Word; - result: Word; -begin - token_length := end_position - start_position; - delimiter := _load_byte(start_position); - - if delimiter = '(' then - result := ElnaLexerKind.comment - elsif delimiter = '\'' then - result := ElnaLexerKind.character - elsif delimiter = '"' then - result := ElnaLexerKind.string - end; - return result -end; - -proc _elna_lexer_classify_integer(start_position: Word, end_position: Word); - return ElnaLexerKind.integer -end; - -proc _elna_lexer_execute_action(action_to_perform: Word, kind: Word); -var - position_start: Word; - position_end: Word; - intermediate: Word; -begin - position_start := _elna_lexer_global_get_start(); - position_end := _elna_lexer_global_get_end(); - - if action_to_perform = ElnaLexerAction.none then - elsif action_to_perform = ElnaLexerAction.accumulate then - _elna_lexer_global_set_end(position_end + 1) - elsif action_to_perform = ElnaLexerAction.skip then - _elna_lexer_global_set_start(position_start + 1); - _elna_lexer_global_set_end(position_end + 1) - elsif action_to_perform = ElnaLexerAction.single then - _elna_lexer_global_set_end(position_end + 1); - - intermediate := _elna_lexer_classify_single(position_start); - kind^ := intermediate - elsif action_to_perform = ElnaLexerAction.eof then - intermediate := ElnaLexerKind.eof; - kind^ := intermediate - elsif action_to_perform = ElnaLexerAction.finalize then - intermediate := _elna_lexer_classify_finalize(position_start); - kind^ := intermediate - elsif action_to_perform = ElnaLexerAction.composite then - _elna_lexer_global_set_end(position_end + 1); - - intermediate := _elna_lexer_classify_composite(position_start, position_end); - kind^ := intermediate - elsif action_to_perform = ElnaLexerAction.key_id then - intermediate := _elna_lexer_classify_keyword(position_start, position_end); - kind^ := intermediate - elsif action_to_perform = ElnaLexerAction.integer then - intermediate := _elna_lexer_classify_integer(position_start, position_end); - kind^ := intermediate - elsif action_to_perform = ElnaLexerAction.delimited then - _elna_lexer_global_set_end(position_end + 1); - - intermediate := _elna_lexer_classify_delimited(position_start, position_end + 1); - kind^ := intermediate - end -end; - -proc _elna_lexer_execute_transition(kind: Word); -var - next_transition: Word; - next_state: Word; - global_state: Word; - action_to_perform: Word; -begin - next_transition := _elna_lexer_next_transition(); - next_state := _elna_lexer_transition_get_state(next_transition); - action_to_perform := _elna_lexer_transition_get_action(next_transition); - - global_state := _elna_lexer_global_state(); - - global_state^ := next_state; - _elna_lexer_execute_action(action_to_perform, kind); - - return next_state -end; - -proc _elna_lexer_advance_token(kind: Word); -var - result_state: Word; -begin - result_state := _elna_lexer_execute_transition(kind); - if result_state <> ElnaLexerState.finish then - _elna_lexer_advance_token(kind) - end -end; - -(** - * Reads the next token and writes its type into the address in the kind parameter. - *) -proc _elna_lexer_read_token(kind: Word); -begin - _elna_lexer_reset(); - _elna_lexer_advance_token(kind) -end; - -(** - * Advances the token stream past the last read token. - *) -proc _elna_lexer_skip_token(); -var - old_end: Word; -begin - old_end := _elna_lexer_global_get_end(); - _elna_lexer_global_set_start(old_end) -end; - -proc _initialize_global_state(); -begin - compiler_strings_position := @compiler_strings; - memory_free_pointer := _mmap(4194304); - source_code := _mmap(495616); - symbol_table_store := _mmap(495616) -end; - -(* - * Entry point. - *) -proc _start(); -var - last_read: Word; - offset: Word; -begin - _initialize_global_state(); - _elna_lexer_initialize(source_code); - _symbol_table_build(); - - (* Read the source from the standard input. *) - offset := source_code; - - .start_read; - (* Second argument is buffer size. Modifying update the source_code definition. *) - last_read := _read_file(offset, 409600); - if last_read > 0 then - offset := offset + last_read; - goto start_read - end; - _compile(); - - _exit(0) -end; |
