diff --git a/Rakefile b/Rakefile index 111ae86..e59d474 100644 --- a/Rakefile +++ b/Rakefile @@ -36,22 +36,22 @@ end desc 'Convert previous stage language into the current stage language' task :convert do - File.open('boot/stage20/cl.elna', 'w') do |current_stage| - File.readlines('boot/stage19/cl.elna').each do |line| + File.open('boot/stage21/cl.elna', 'w') do |current_stage| + File.readlines('boot/stage20/cl.elna').each do |line| current_stage << line end - current_stage << <<~FUN - - proc f(m: ElnaInstructionModule); - begin - end; - - proc g(); - var - x: ElnaInstructionModule; - begin - f(x) - end; - FUN +# current_stage << <<~FUN +# +# proc f(m: ElnaInstructionModule); +# begin +# end; +# +# proc g(); +# var +# x: ElnaInstructionModule; +# begin +# f(x) +# end; +# FUN end end diff --git a/boot/stage20/cl.elna b/boot/stage20/cl.elna index 21c7259..7312a03 100644 --- a/boot/stage20/cl.elna +++ b/boot/stage20/cl.elna @@ -7,6 +7,8 @@ program; (* Stage 20 compiler. *) +(* - Allow program module body. *) + type ElnaListNode = record next: Word @@ -261,22 +263,23 @@ type name: Word; length: Word end; - ElnaTreeModuleDeclaration = record - kind: ElnaTreeKind; - types: Word; - globals: Word; - procedures: Word - end; ElnaTreeProcedureDeclaration = record kind: ElnaTreeKind; next: Word; name: Word; length: Word; - body: Word; + body: ^ElnaTreeStatement; temporaries: Word; parameters: Word; return_type: ^ElnaTreeNode end; + ElnaTreeModuleDeclaration = record + kind: ElnaTreeKind; + types: Word; + globals: Word; + procedures: ^ElnaTreeProcedureDeclaration; + body: ^ElnaTreeStatement + end; ElnaTreeTypeDeclaration = record kind: ElnaTreeKind; next: Word; @@ -844,7 +847,7 @@ begin operand_value^ := buffer; operand_length^ := strlen(buffer); - temporary_info := _temporary_info_create(1, word_type); + temporary_info := temporary_info_create(1, word_type); elna_symbol_table_enter(symbol_table, buffer, operand_length^, temporary_info) end; @@ -2923,7 +2926,7 @@ begin return result end; -proc elna_parser_statements(cursor: ^ElnaLexerCursor); +proc elna_parser_statements(cursor: ^ElnaLexerCursor) -> ^ElnaTreeStatement; var previous_statement: ^ElnaTreeStatement; next_statement: ^ElnaTreeStatement; @@ -3357,7 +3360,7 @@ begin return result end; -proc _type_info_create(type_representation: Word); +proc type_info_create(type_representation: Word); var result: ^ElnaSymbolTypeInfo; begin @@ -3373,7 +3376,7 @@ end; * attr - Local variable attributes. * temporary_type - Local variable type. *) -proc _temporary_info_create(attr: Word, temporary_type: Word); +proc temporary_info_create(attr: Word, temporary_type: Word); var result: ^ElnaSymbolTemporaryInfo; begin @@ -3391,7 +3394,7 @@ end; * Parameters: * symbol_table - Local symbol table. *) -proc _procedure_info_create(symbol_table: ^ElnaSymbolTable); +proc procedure_info_create(symbol_table: ^ElnaSymbolTable); var result: ^ElnaSymbolProcedureInfo; begin @@ -3413,7 +3416,7 @@ var begin variable_type := elna_name_type_expression(parser_node^._type); - info := _temporary_info_create(0, variable_type); + info := temporary_info_create(0, variable_type); elna_symbol_table_enter(symbol_table, parser_node^.name, parser_node^.length, info) end; @@ -3428,7 +3431,7 @@ begin end end; -proc elna_parser_procedure_declaration(cursor: ^ElnaLexerCursor); +proc elna_parser_procedure_declaration(cursor: ^ElnaLexerCursor) -> ^ElnaTreeProcedureDeclaration; var next_declaration: ^ElnaTreeDeclaration; current_declaration: ^ElnaTreeDeclaration; @@ -3718,7 +3721,7 @@ begin return result end; -proc elna_parser_procedures(cursor: ^ElnaLexerCursor); +proc elna_parser_procedures(cursor: ^ElnaLexerCursor) -> ^ElnaTreeDeclaration; var parser_node: ^ElnaTreeDeclaration; result: ^ElnaTreeDeclaration; @@ -3804,7 +3807,7 @@ begin return first_copy end; -proc elna_tac_procedures(parser_node: ^ElnaTreeDeclaration); +proc elna_tac_procedures(parser_node: ^ElnaTreeDeclaration) -> ^ElnaTacProcedure; var result: ^ElnaTacProcedure; current_procedure: ^ElnaTacProcedure; @@ -3880,7 +3883,7 @@ begin parser_node := parser_node^._type; type_info := elna_name_type_expression(parser_node); - type_info := _type_info_create(type_info); + type_info := type_info_create(type_info); elna_symbol_table_enter(@symbol_table_global, type_name, name_length, type_info) end; @@ -4032,7 +4035,22 @@ begin return first_variable end; -proc elna_parser_module_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList); +proc elna_parser_program_body(cursor: ^ElnaLexerCursor) -> ^ElnaTreeStatement; +var + result: ^ElnaTreeStatement; + token: ^ElnaLexerToken; +begin + result := nil; + token := elna_lexer_peek(cursor); + + if token^.kind = ElnaLexerKind._begin then + elna_lexer_read(cursor); + result := elna_parser_statements(cursor); + end; + return result +end; + +proc elna_parser_module_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeModuleDeclaration; var parser_node: Word; result: ^ElnaTreeModuleDeclaration; @@ -4057,19 +4075,63 @@ begin result^.types := elna_parser_type_part(cursor); result^.globals := elna_parser_var_part(cursor); - result^.procedures := elna_parser_procedures(cursor) + result^.procedures := elna_parser_procedures(cursor); + result^.body := elna_parser_program_body(cursor) end; return result end; +proc elna_tac_program_body(parser_node: ^ElnaTreeStatement); +var + result: ^ElnaTacProcedure; + symbol_info: ^ElnaSymbolProcedureInfo; +begin + result := malloc(#size(ElnaTacProcedure)); + result^.next := nil; + + elna_list_initialize(@result^.body); + + result^.name := "main"; + result^.length := 4; + + symbol_info := elna_symbol_table_lookup(@symbol_table_global, "main", 4); + + result^.symbol_table := symbol_info^.symbol_table; + + result^.parameters := nil; + result^.count := 0; + + elna_tac_statements(@result^.body, parser_node, result^.symbol_table); + + return result +end; + proc elna_tac_module_declaration(parser_node: ^ElnaTreeModuleDeclaration); var result: ^ElnaInstructionModule; + code: ^ElnaTacProcedure; begin result := malloc(#size(ElnaInstructionModule)); result^.data := elna_tac_var_part(parser_node^.globals); result^.code := elna_tac_procedures(parser_node^.procedures); + if parser_node^.body <> nil then + code := result^.code; + if code = nil then + result^.code := elna_tac_program_body(parser_node^.body); + + goto elna_tac_module_declaration_end + end; + .elna_tac_module_declaration_loop; + + if code^.next = nil then + code^.next := elna_tac_program_body(parser_node^.body) + else + code := code^.next; + goto elna_tac_module_declaration_loop + end + end; + .elna_tac_module_declaration_end; return result end; @@ -4079,7 +4141,7 @@ var symbol_info: Word; begin new_symbol_table := elna_symbol_table_create(); - symbol_info := _procedure_info_create(new_symbol_table); + symbol_info := procedure_info_create(new_symbol_table); elna_name_procedure_temporaries(parser_node^.parameters, new_symbol_table); elna_name_procedure_temporaries(parser_node^.temporaries, new_symbol_table); @@ -4087,6 +4149,17 @@ begin elna_symbol_table_enter(@symbol_table_global, parser_node^.name, parser_node^.length, symbol_info) end; +proc elna_name_program_body(parser_node: ^ElnaTreeStatement); +var + new_symbol_table: ^ElnaSymbolTable; + symbol_info: Word; +begin + new_symbol_table := elna_symbol_table_create(); + symbol_info := procedure_info_create(new_symbol_table); + + elna_symbol_table_enter(@symbol_table_global, "main", 4, symbol_info) +end; + proc elna_type_conditional_statements(parser_node: ^ElnaTreeConditionalStatements, symbol_table: ^ElnaSymbolTable); begin .elna_type_conditional_statements_loop; @@ -4392,6 +4465,9 @@ begin current_part := current_part^.next; goto elna_name_module_declaration_procedure + end; + if parser_node^.body <> nil then + elna_name_program_body(parser_node^.body) end end; @@ -4418,17 +4494,19 @@ begin end end; -proc _compile(cursor: ^ElnaLexerCursor); +proc compile(); var parser_node: Word; tac: Word; rtl: Word; error_list: ElnaList; compiled: Word; + lexer_state: ElnaLexerCursor; begin + elna_lexer_initialize(@lexer_state, source_code); elna_list_initialize(@error_list); - parser_node := elna_parser_module_declaration(cursor, @error_list); + parser_node := elna_parser_module_declaration(@lexer_state, @error_list); compiled := error_list.first = nil; if compiled then @@ -4559,22 +4637,30 @@ begin word_type^.kind := ElnaTypeKind.primitive; word_type^.size := 4; word_type^.alignment := 4; - current_info := _type_info_create(word_type); + current_info := type_info_create(word_type); elna_symbol_table_enter(@symbol_table_global, "Word", 4, current_info); current_type := malloc(#size(ElnaType)); current_type^.kind := ElnaTypeKind.primitive; current_type^.size := 4; current_type^.alignment := 4; - current_info := _type_info_create(current_type); + current_info := type_info_create(current_type); elna_symbol_table_enter(@symbol_table_global, "Pointer", 7, current_info); current_type := malloc(#size(ElnaType)); current_type^.kind := ElnaTypeKind.primitive; current_type^.size := 1; current_type^.alignment := 1; - current_info := _type_info_create(current_type); + current_info := type_info_create(current_type); elna_symbol_table_enter(@symbol_table_global, "Bool", 4, current_info); + + current_type := malloc(#size(ElnaType)); + current_type^.kind := ElnaTypeKind.primitive; + current_type^.size := 1; + current_type^.alignment := 1; + current_info := type_info_create(current_type); + elna_symbol_table_enter(@symbol_table_global, "Char", 4, current_info); + end; (** @@ -5235,25 +5321,17 @@ begin return token end; -proc _initialize_global_state(); +proc initialize_global_state(); begin compiler_strings_position := @compiler_strings; source_code := malloc(495616) end; -(* - * Entry point. - *) -proc main(); +proc read_source(); var last_read: Word; offset: Word; - lexer_state: ElnaLexerCursor; begin - _initialize_global_state(); - elna_lexer_initialize(@lexer_state, source_code); - elna_symbol_table_build(); - (* Read the source from the standard input. *) offset := source_code; @@ -5263,8 +5341,19 @@ begin if last_read > 0 then offset := offset + last_read; goto start_read - end; - if _compile(@lexer_state) then + end +end; + +(* + * Entry point. + *) +proc main(); +begin + initialize_global_state(); + elna_symbol_table_build(); + + read_source(); + if compile() then exit(0) else exit(4)