Implement 2 word argument support

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