From c2a0c80ea445f89d0fc4ed8efaad0f2911bdc0b4 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 13 Jun 2026 23:25:52 +0200 Subject: [PATCH] Check for parsing errors --- boot/stage22/cl.elna | 1 - boot/stage23/cl.elna | 1025 ++++++++++++++++++++++++++++-------------- 2 files changed, 695 insertions(+), 331 deletions(-) diff --git a/boot/stage22/cl.elna b/boot/stage22/cl.elna index 4e882a6..fa10d94 100644 --- a/boot/stage22/cl.elna +++ b/boot/stage22/cl.elna @@ -4759,7 +4759,6 @@ end proc elna_parser_module_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeModuleDeclaration var - parser_node: Word result: ^ElnaTreeModuleDeclaration parser_error: ^ElnaError token: ^ElnaLexerToken diff --git a/boot/stage23/cl.elna b/boot/stage23/cl.elna index 01f8f54..165c282 100644 --- a/boot/stage23/cl.elna +++ b/boot/stage23/cl.elna @@ -253,7 +253,7 @@ type ElnaTreeArrayTypeExpression = record kind: ElnaTreeKind; base: ^ElnaTreeTypeExpression; - length: Word + length: ^ElnaTreeExpression end ElnaTreeTraitExpression = record kind: ElnaTreeKind; @@ -348,10 +348,6 @@ type return_type: ^ElnaType end - ElnaError = record - next: Word - end - ElnaLexerAction = (none, accumulate, skip, single, eof, finalize, composite, key_id, integer, delimited) ElnaLexerState = ( start, @@ -436,9 +432,6 @@ type _program, _import, _cast, - _defer, - _case, - _of, trait, left_paren, right_paren, @@ -674,6 +667,21 @@ type allocated: Bool end + ElnaErrorKind = (unexpected_token) + ElnaError = record + next: Word; + kind: ElnaErrorKind; + position: ElnaPosition + end + ElnaErrorUnexpectedToken = record + next: Word; + kind: ElnaErrorKind; + position: ElnaPosition; + expected: ^ElnaLexerKind; + possibilities: Word; + got: ElnaLexerKind + end + var symbol_table_global: ^ElnaSymbolTable variable_map_global: ^ElnaSymbolTable @@ -693,6 +701,12 @@ var temporary_variable_counter: Word pseudo_counter: Word +proc free_and_nil(pointer: Pointer) -> Pointer +begin + free(pointer); + return nil +end + (** * Adds a string to the global, read-only string storage. * @@ -772,9 +786,9 @@ end * Parameters: * buffer - String to write. *) -proc _write_s(buffer: String) +proc _write_s(stream: Word, buffer: String) begin - write(1, buffer.ptr, buffer.length) + write(stream, buffer.ptr, buffer.length) end (** @@ -783,9 +797,9 @@ end * Parameters: * number - Whole number. *) -proc _write_i(number: Word) +proc _write_i(stream: Word, number: Word) begin - printf("%i\0".ptr, number); + dprintf(stream, "%i\0".ptr, number); fflush(nil) end @@ -795,9 +809,9 @@ end * Parameters: * character - Character to write. *) -proc _write_c(character: Word) +proc _write_c(stream: Word, character: Word) begin - write(1, @character, 1) + write(stream, @character, 1) end proc elna_list_initialize(list: ^ElnaList) @@ -847,6 +861,12 @@ begin existing^.next := new end +(* Returns whether the given list is empty. *) +proc elna_list_empty(list: ^ElnaList) -> Bool +begin + return list^.first = nil +end + proc elna_tac_make_variable(operand: ^ElnaTacOperand, symbol_table: ^ElnaSymbolTable, variable_type: ^ElnaType) var buffer: Word @@ -1577,84 +1597,84 @@ var begin if instruction_kind = ElnaRtlOperator.li then argument_count := 2; - _write_s("\tli") + _write_s(1, "\tli") elsif instruction_kind = ElnaRtlOperator.la then argument_count := 2; - _write_s("\tla") + _write_s(1, "\tla") elsif instruction_kind = ElnaRtlOperator.add then argument_count := 3; - _write_s("\tadd") + _write_s(1, "\tadd") elsif instruction_kind = ElnaRtlOperator.addi then argument_count := 3; - _write_s("\taddi") + _write_s(1, "\taddi") elsif instruction_kind = ElnaRtlOperator.lw then argument_count := 2; if source_type^.kind = ElnaRtlTypeKind.byte then - _write_s("\tlb") + _write_s(1, "\tlb") else - _write_s("\tlw") + _write_s(1, "\tlw") end elsif instruction_kind = ElnaRtlOperator.sw then argument_count := 2; if source_type^.kind = ElnaRtlTypeKind.byte then - _write_s("\tsb") + _write_s(1, "\tsb") else - _write_s("\tsw") + _write_s(1, "\tsw") end elsif instruction_kind = ElnaRtlOperator.jal then argument_count := 1; - _write_s("\tcall") + _write_s(1, "\tcall") elsif instruction_kind = ElnaRtlOperator.mv then argument_count := 2; - _write_s("\tmv") + _write_s(1, "\tmv") elsif instruction_kind = ElnaRtlOperator.sub then argument_count := 3; - _write_s("\tsub") + _write_s(1, "\tsub") elsif instruction_kind = ElnaRtlOperator.mul then argument_count := 3; - _write_s("\tmul") + _write_s(1, "\tmul") elsif instruction_kind = ElnaRtlOperator.div then argument_count := 3; - _write_s("\tdiv") + _write_s(1, "\tdiv") elsif instruction_kind = ElnaRtlOperator.rem then argument_count := 3; - _write_s("\trem") + _write_s(1, "\trem") elsif instruction_kind = ElnaRtlOperator._xor then argument_count := 3; - _write_s("\txor") + _write_s(1, "\txor") elsif instruction_kind = ElnaRtlOperator.xori then argument_count := 3; - _write_s("\txori") + _write_s(1, "\txori") elsif instruction_kind = ElnaRtlOperator._or then argument_count := 3; - _write_s("\tor") + _write_s(1, "\tor") elsif instruction_kind = ElnaRtlOperator.and then argument_count := 3; - _write_s("\tand") + _write_s(1, "\tand") elsif instruction_kind = ElnaRtlOperator.seqz then argument_count := 2; - _write_s("\tseqz") + _write_s(1, "\tseqz") elsif instruction_kind = ElnaRtlOperator.snez then argument_count := 2; - _write_s("\tsnez") + _write_s(1, "\tsnez") elsif instruction_kind = ElnaRtlOperator.slt then argument_count := 3; - _write_s("\tslt") + _write_s(1, "\tslt") elsif instruction_kind = ElnaRtlOperator.neg then argument_count := 2; - _write_s("\tneg") + _write_s(1, "\tneg") elsif instruction_kind = ElnaRtlOperator.not then argument_count := 2; - _write_s("\tnot") + _write_s(1, "\tnot") elsif instruction_kind = ElnaRtlOperator.j then argument_count := 1; - _write_s("\tj") + _write_s(1, "\tj") elsif instruction_kind = ElnaRtlOperator.beqz then argument_count := 2; - _write_s("\tbeqz") + _write_s(1, "\tbeqz") elsif instruction_kind = ElnaRtlOperator.bnez then argument_count := 2; - _write_s("\tbnez") + _write_s(1, "\tbnez") end; return argument_count end @@ -1671,14 +1691,14 @@ var begin operand_type := instruction^.operands[n].kind; - _write_c(' '); + _write_c(1, ' '); if operand_type = ElnaRtlKind.register then elna_riscv_register(instruction^.operands[n].value) elsif operand_type = ElnaRtlKind.memory then - _write_i(instruction^.operands[n].offset); - _write_c('('); + _write_i(1, instruction^.operands[n].offset); + _write_c(1, '('); elna_riscv_register(instruction^.operands[n].value); - _write_c(')') + _write_c(1, ')') elsif operand_type = ElnaRtlKind.data then if instruction^.operands[n].length = 0 then _write_label(instruction^.operands[n].value, 0) @@ -1686,7 +1706,7 @@ begin write(1, instruction^.operands[n].value, instruction^.operands[n].length) end elsif instruction^.operands[n].length = 0 then (* ElnaRtlKind.immediate *) - _write_i(instruction^.operands[n].value) + _write_i(1, instruction^.operands[n].value) else write(1, instruction^.operands[n].value, instruction^.operands[n].length) end @@ -1857,17 +1877,17 @@ begin load_instruction^ := instruction^; load_instruction^.next := nil; - instruction^.operator = ElnaRtlOperator.la; + instruction^.operator := ElnaRtlOperator.la; elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t1, 0, 0); elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.data, target_operand.value, target_operand.length, 0); elna_list_insert(instructions, instruction, load_instruction); - load_instruction^.operator = ElnaRtlOperator.sw; + load_instruction^.operator := ElnaRtlOperator.sw; elna_rtl_instruction_set_operand(load_instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t0, 0, 0); elna_rtl_instruction_set_operand(load_instruction, 2, ElnaRtlKind.memory, ElnaRtlRegister.t1, 0, 0) else pseudo_symbol := elna_alloc_variable(target_operand.value, target_operand.length, variable_map); - instruction^.operator = ElnaRtlOperator.sw; + instruction^.operator := ElnaRtlOperator.sw; elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t0, 0, 0); elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.memory, ElnaRtlRegister.sp, 0, pseudo_symbol^.counter); @@ -1882,15 +1902,15 @@ begin load_instruction^ := instruction^; load_instruction^.next := nil; - instruction^.operator = ElnaRtlOperator.la; + instruction^.operator := ElnaRtlOperator.la; elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t1, 0, 0); elna_list_insert(instructions, instruction, load_instruction); - load_instruction^.operator = ElnaRtlOperator.sw; + load_instruction^.operator := ElnaRtlOperator.sw; elna_rtl_instruction_set_operand(load_instruction, 2, ElnaRtlKind.memory, ElnaRtlRegister.t1, 0, 0) else pseudo_symbol := elna_alloc_variable(target_operand.value, target_operand.length, variable_map); - instruction^.operator = ElnaRtlOperator.sw; + instruction^.operator := ElnaRtlOperator.sw; elna_rtl_instruction_set_operand(instruction, 1, source_operand.kind, source_operand.value, source_operand.length, 0); @@ -1909,12 +1929,12 @@ begin instruction^.operator := ElnaRtlOperator.la; elna_list_insert(instructions, instruction, load_instruction); - load_instruction^.operator = ElnaRtlOperator.lw; + load_instruction^.operator := ElnaRtlOperator.lw; elna_rtl_instruction_set_operand(load_instruction, 2, ElnaRtlKind.memory, target_operand.value, target_operand.length, 0); load_instruction^.types[1] := pseudo_symbol^.rtl_type else - instruction^.operator = ElnaRtlOperator.lw; + instruction^.operator := ElnaRtlOperator.lw; elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.memory, ElnaRtlRegister.sp, 0, pseudo_symbol^.counter) end; @@ -2063,8 +2083,7 @@ begin if instruction^.operator = ElnaRtlOperator.label then _write_label(instruction^.operands[1].value, instruction^.operands[1].length); - (* _write_c(':') *) - _write_c(58) + _write_c(1, ':') elsif instruction^.operator = ElnaRtlOperator.allocate_stack then operand_value := instruction^.operands[1].value; @@ -2102,12 +2121,10 @@ begin current_argument := current_argument + 1 end; if current_argument <= argument_count then - (* _write_c(','); *) - _write_c(44); + _write_c(1, ','); goto elna_riscv_instruction_loop end; - - _write_c(10) + _write_c(1, '\n') end proc elna_rtl_instructions(instructions: ^ElnaList, instruction: ^ElnaTacInstruction, variable_map: ^ElnaSymbolTable) @@ -2182,7 +2199,7 @@ begin elna_riscv_instructions(procedure^.body.first); fflush(nil); - _write_s("\tret\n"); + _write_s(1, "\tret\n"); procedure := procedure^.next; if procedure <> nil then @@ -2299,15 +2316,15 @@ var compiler_strings_end: ^Char current_byte: Char begin - _write_s(".globl main\n\n.section .data\n"); + _write_s(1, ".globl main\n\n.section .data\n"); elna_riscv_variable(pair^.data); fflush(nil); - _write_s(".section .text\n\n"); + _write_s(1, ".section .text\n\n"); elna_riscv_procedure(pair^.code); fflush(nil); - _write_s(".section .rodata\n.type strings, @object\nstrings: .ascii \""); + _write_s(1, ".section .rodata\n.type strings, @object\nstrings: .ascii \""); compiler_strings_copy := @compiler_strings; compiler_strings_end := compiler_strings_position; @@ -2316,11 +2333,11 @@ begin if compiler_strings_copy < compiler_strings_end then current_byte := compiler_strings_copy^; compiler_strings_copy := compiler_strings_copy + 1; - _write_c(current_byte); + _write_c(1, current_byte); goto elna_riscv_module_loop end; - _write_s("\"\n") + _write_s(1, "\"\n") end proc elna_parser_integer_literal(cursor: ^ElnaLexerCursor) -> ^ElnaTreeIntegerLiteral @@ -2563,7 +2580,7 @@ begin end -proc elna_parser_trait_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeTraitExpression +proc elna_parser_trait_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeTraitExpression var result: ^ElnaTreeTraitExpression token: ^ElnaLexerToken @@ -2575,38 +2592,59 @@ begin result^.name := token^.start; result^.length := token^.length; - elna_lexer_read(cursor); - - result^.argument := elna_parser_type_expression(cursor); - - elna_lexer_read(cursor); - + if elna_parser_expect(cursor, ElnaLexerKind.left_paren, error_list) <> nil then + result^.argument := elna_parser_type_expression(cursor, error_list); + if result^.argument = nil then + result := free_and_nil(result) + else + if elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list) = nil then + result := free_and_nil(result) + end + end + else + result := free_and_nil(result) + end; return result end -proc elna_parser_cast_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeCastExpression +proc elna_parser_cast_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeCastExpression var result: ^ElnaTreeCastExpression token: ^ElnaLexerToken begin + result := nil; + + (* Skip the cast keyword and opening paren. *) + elna_lexer_read(cursor); + if elna_parser_expect(cursor, ElnaLexerKind.left_paren, error_list) = nil then + goto elna_parser_cast_expression_end + end; result := malloc(#size(ElnaTreeCastExpression)); result^.kind := ElnaTreeKind._cast; result^.type_decoration := nil; - (* Skip the cast keyword and opening paren. *) - elna_lexer_read(cursor); - elna_lexer_read(cursor); - result^.expression := elna_parser_binary_expression(cursor); - (* Skip the colon. *) - elna_lexer_read(cursor); - result^.type_expression := elna_parser_type_expression(cursor); - (* Skip the closing paren. *) - elna_lexer_read(cursor); - + result^.expression := elna_parser_binary_expression(cursor, error_list); + if result^.expression = nil then + result := free_and_nil(result); + goto elna_parser_cast_expression_end + end; + if elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) = nil then + result := free_and_nil(result); + goto elna_parser_cast_expression_end + end; + result^.type_expression := elna_parser_type_expression(cursor, error_list); + if result^.type_expression = nil then + result := free_and_nil(result); + goto elna_parser_cast_expression_end + end; + if elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list) = nil then + result := free_and_nil(result) + end; + .elna_parser_cast_expression_end; return result end -proc elna_parser_simple_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeExpression +proc elna_parser_simple_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeExpression var current_character: Word parser_node: ^ElnaTreeExpression @@ -2626,9 +2664,9 @@ begin elsif token^.kind = ElnaLexerKind.null then parser_node := elna_parser_nil_literal(cursor) elsif token^.kind = ElnaLexerKind._cast then - parser_node := elna_parser_cast_expression(cursor) + parser_node := elna_parser_cast_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.trait then - parser_node := elna_parser_trait_expression(cursor) + parser_node := elna_parser_trait_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.identifier then parser_node := elna_parser_variable_expression(cursor) end; @@ -2650,12 +2688,16 @@ begin return result end -proc elna_parser_designator(cursor: ^ElnaLexerCursor) -> ^ElnaTreeExpression +proc elna_parser_designator(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeExpression var simple_expression: ^ElnaTreeExpression token: ^ElnaLexerToken begin - simple_expression := elna_parser_simple_expression(cursor); + simple_expression := elna_parser_simple_expression(cursor, error_list); + if simple_expression = nil then + simple_expression := free_and_nil(simple_expression); + goto elna_parser_designator_end + end; .elna_parser_designator_loop; token := elna_lexer_peek(cursor); @@ -2667,12 +2709,17 @@ begin simple_expression := elna_parser_field_access_expression(cursor, simple_expression); goto elna_parser_designator_loop elsif token^.kind = ElnaLexerKind.left_square then - simple_expression := elna_parser_array_access_expression(cursor, simple_expression); - goto elna_parser_designator_loop + simple_expression := elna_parser_array_access_expression(cursor, simple_expression, error_list); + if simple_expression <> nil then + goto elna_parser_designator_loop + end elsif token^.kind = ElnaLexerKind.left_paren then - simple_expression := elna_parser_call(cursor, simple_expression); - goto elna_parser_designator_loop + simple_expression := elna_parser_call(cursor, simple_expression, error_list); + if simple_expression <> nil then + goto elna_parser_designator_loop + end end; + .elna_parser_designator_end; return simple_expression end @@ -2719,7 +2766,7 @@ begin end end -proc elna_parser_unary_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeExpression +proc elna_parser_unary_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeExpression var result: ^ElnaTreeUnaryExpression operand: Word @@ -2739,16 +2786,17 @@ begin if operator <> 0 then elna_lexer_read(cursor) end; - result := elna_parser_designator(cursor); + result := elna_parser_designator(cursor, error_list); + if result <> nil then + if operator <> 0 then + operand := result; + result := malloc(#size(ElnaTreeUnaryExpression)); - if operator <> 0 then - operand := result; - result := malloc(#size(ElnaTreeUnaryExpression)); - - result^.kind := ElnaTreeKind.unary_expression; - result^.operand := operand; - result^.operator := operator; - result^.type_decoration := nil + result^.kind := ElnaTreeKind.unary_expression; + result^.operand := operand; + result^.operator := operator; + result^.type_decoration := nil + end end; return result @@ -2838,59 +2886,60 @@ begin end end -proc elna_parser_binary_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeExpression +proc elna_parser_binary_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeExpression var lhs_node: ^ElnaTreeExpression rhs_node: ^ElnaTreeExpression result: ^ElnaTreeBinaryExpression token: ^ElnaLexerToken begin - lhs_node := elna_parser_unary_expression(cursor); + lhs_node := elna_parser_unary_expression(cursor, error_list); rhs_node := nil; + result := nil; token := elna_lexer_peek(cursor); if token^.kind = ElnaLexerKind.plus then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.minus then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.multiplication then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.and then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind._or then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind._xor then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.equals then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.remainder then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.division then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.less_than then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.greater_than then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.less_equal then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.not_equal then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.greater_equal then elna_lexer_read(cursor); - rhs_node := elna_parser_unary_expression(cursor) + rhs_node := elna_parser_unary_expression(cursor, error_list) end; if rhs_node <> nil then result := malloc(#size(ElnaTreeBinaryExpression)); @@ -2900,7 +2949,7 @@ begin result^.rhs := rhs_node; result^.operator := token^.kind; result^.type_decoration := nil - else + elsif elna_list_empty(error_list) then result := lhs_node end; return result @@ -3022,19 +3071,19 @@ begin end end -proc elna_parser_call(cursor: ^ElnaLexerCursor, callee: ^ElnaTreeExpression) -> ^ElnaTreeCall +proc elna_parser_call(cursor: ^ElnaLexerCursor, callee: ^ElnaTreeExpression, error_list: ^ElnaList) -> ^ElnaTreeCall var result: ^ElnaTreeCall - argument_number: Word argument_entry: ^ElnaTreeExpressionList token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken begin result := malloc(#size(ElnaTreeCall)); result^.kind := ElnaTreeKind.call; result^.next := nil; result^.arguments := nil; - argument_number := 1; + result^.count := 0; result^.callee := callee; elna_lexer_read(cursor); @@ -3054,19 +3103,28 @@ begin argument_entry := argument_entry^.next end; argument_entry^.next := nil; - argument_entry^.expression := elna_parser_binary_expression(cursor); + argument_entry^.expression := elna_parser_binary_expression(cursor, error_list); + if argument_entry^.expression = nil then + result := free_and_nil(result) + else + result^.count := result^.count + 1; + token := elna_lexer_peek(cursor); - argument_number := argument_number + 1; - token := elna_lexer_read(cursor); + if token^.kind = ElnaLexerKind.comma then + elna_lexer_read(cursor); + goto elna_parser_call_loop + elsif token^.kind = ElnaLexerKind.right_paren then + elna_lexer_read(cursor) + else + parser_error := elna_error_unexpected_token_create(cursor, 2); + parser_error^.expected[1] := ElnaLexerKind.comma; + parser_error^.expected[2] := ElnaLexerKind.right_paren; - if token^.kind = ElnaLexerKind.comma then - goto elna_parser_call_loop + elna_list_append(error_list, parser_error); + result := free_and_nil(result) + end end; - .elna_parser_call_end; - (* Save the number of arguments. *) - result^.count := argument_number - 1; - return result end @@ -3110,20 +3168,22 @@ begin elna_list_append(instructions, call_instruction) end -proc elna_parser_goto_statement(cursor: ^ElnaLexerCursor) -> ^ElnaTreeGotoStatement +proc elna_parser_goto_statement(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeGotoStatement var result: ^ElnaTreeGotoStatement token: ^ElnaLexerToken begin + (* Skip the goto. *) elna_lexer_read(cursor); - token := elna_lexer_read(cursor); - - result := malloc(#size(ElnaTreeGotoStatement)); - result^.kind := ElnaTreeKind.goto_statement; - result^.next := nil; - result^.label := token^.start; - result^.length := token^.length; + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token <> nil then + result := malloc(#size(ElnaTreeGotoStatement)); + result^.kind := ElnaTreeKind.goto_statement; + result^.next := nil; + result^.label := token^.start; + result^.length := token^.length + end; return result end @@ -3144,21 +3204,21 @@ begin elna_list_append(instructions, instruction) end -proc elna_parser_label_declaration(cursor: ^ElnaLexerCursor) -> ^ElnaTreeLabelDeclaration +proc elna_parser_label_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeLabelDeclaration var result: ^ElnaTreeLabelDeclaration token: ^ElnaLexerToken begin elna_lexer_read(cursor); - token := elna_lexer_read(cursor); - - result := malloc(#size(ElnaTreeLabelDeclaration)); - - result^.kind := ElnaTreeKind.label_declaration; - result^.next := nil; - result^.label := token^.start; - result^.length := token^.length; + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token <> nil then + result := malloc(#size(ElnaTreeLabelDeclaration)); + result^.kind := ElnaTreeKind.label_declaration; + result^.next := nil; + result^.label := token^.start; + result^.length := token^.length; + end; return result end @@ -3229,7 +3289,7 @@ begin end proc elna_parser_array_access_expression(cursor: ^ElnaLexerCursor, - array: ^ElnaTreeExpression) -> ^ElnaTreeArrayAccessExpression + array: ^ElnaTreeExpression, error_list: ^ElnaList) -> ^ElnaTreeArrayAccessExpression var result: ^ElnaTreeArrayAccessExpression begin @@ -3240,9 +3300,12 @@ begin result^.kind := ElnaTreeKind.array_access_expression; result^.type_decoration := nil; result^.array := array; - result^.index := elna_parser_binary_expression(cursor); - - elna_lexer_read(cursor); + result^.index := elna_parser_binary_expression(cursor, error_list); + if result^.index = nil then + result := free_and_nil(result) + elsif elna_parser_expect(cursor, ElnaLexerKind.right_square, error_list) = nil then + result := free_and_nil(result) + end; return result end @@ -3395,20 +3458,25 @@ begin elna_list_append(instructions, instruction) end -proc elna_parser_assign_statement(cursor: ^ElnaLexerCursor, assignee: ^ElnaTreeNode) -> ^ElnaTreeAssignStatement +proc elna_parser_assign_statement(cursor: ^ElnaLexerCursor, assignee: ^ElnaTreeNode, error_list: ^ElnaList) -> ^ElnaTreeAssignStatement var result: ^ElnaTreeAssignStatement + token: ^ElnaLexerToken begin result := malloc(#size(ElnaTreeAssignStatement)); result^.kind := ElnaTreeKind.assign_statement; result^.next := nil; result^.assignee := assignee; + result^.assignment := nil; (* Skip the assignment sign (:=) with surrounding whitespaces. *) - elna_lexer_read(cursor); - result^.assignment := elna_parser_binary_expression(cursor); - + if elna_parser_expect(cursor, ElnaLexerKind.assignment, error_list) <> nil then + result^.assignment := elna_parser_binary_expression(cursor, error_list); + end; + if result^.assignment = nil then + result := free_and_nil(result) + end; return result end @@ -3445,21 +3513,20 @@ begin elna_list_append(instructions, instruction) end -proc elna_parser_return_statement(cursor: ^ElnaLexerCursor) -> ^ElnaTreeReturnStatement +proc elna_parser_return_statement(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeReturnStatement var - returned: ^ElnaTreeExpression - label_length: Word result: ^ElnaTreeReturnStatement begin - (* Skip "return" keyword and whitespace after it. *) + (* Skip "return" keyword. *) elna_lexer_read(cursor); - returned := elna_parser_binary_expression(cursor); result := malloc(#size(ElnaTreeReturnStatement)); - result^.kind := ElnaTreeKind.return_statement; result^.next := nil; - result^.returned := returned; + result^.returned := elna_parser_binary_expression(cursor, error_list); + if result^.returned = nil then + result := free_and_nil(result) + end; return result end @@ -3494,7 +3561,8 @@ begin fflush(nil) end -proc elna_parser_conditional_statements(cursor: ^ElnaLexerCursor) -> ^ElnaTreeConditionalStatements +proc elna_parser_conditional_statements(cursor: ^ElnaLexerCursor, error_list: ^ElnaList, + block_keyword: ElnaLexerKind) -> ^ElnaTreeConditionalStatements var result: ^ElnaTreeConditionalStatements begin @@ -3502,14 +3570,20 @@ begin (* Skip "if", "while" or "elsif". *) elna_lexer_read(cursor); - result^.condition := elna_parser_binary_expression(cursor); - - (* Skip "then" or "do". *) - elna_lexer_read(cursor); - - result^.statements := elna_parser_statements(cursor); - result^.next := nil; - + result^.condition := elna_parser_binary_expression(cursor, error_list); + if result^.condition = nil then + result := free_and_nil(result) + else + (* Skip "then" or "do". *) + if elna_parser_expect(cursor, block_keyword, error_list) <> nil then + result^.statements := elna_parser_statements(cursor, error_list) + end; + if elna_list_empty(error_list) then + result^.next := nil + else + result := free_and_nil(result) + end + end; return result end @@ -3541,7 +3615,7 @@ begin elna_tac_label(instructions, condition_label, 0) end -proc elna_parser_if_statement(cursor: ^ElnaLexerCursor) -> ^ElnaTreeIfStatement +proc elna_parser_if_statement(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeIfStatement var result: ^ElnaTreeIfStatement previous_conditional: ^ElnaTreeConditionalStatements @@ -3553,21 +3627,21 @@ begin result^.kind := ElnaTreeKind.if_statement; result^.next := nil; - previous_conditional := elna_parser_conditional_statements(cursor); + previous_conditional := elna_parser_conditional_statements(cursor, error_list, ElnaLexerKind._then); result^.conditionals := previous_conditional; .elna_parser_if_statement_loop; token := elna_lexer_peek(cursor); if token^.kind = ElnaLexerKind._elsif then - next_conditional := elna_parser_conditional_statements(cursor); + next_conditional := elna_parser_conditional_statements(cursor, error_list, ElnaLexerKind._then); previous_conditional^.next := next_conditional; - previous_conditional = next_conditional; + previous_conditional := next_conditional; goto elna_parser_if_statement_loop elsif token^.kind = ElnaLexerKind._else then elna_lexer_read(cursor); - result^._else := elna_parser_statements(cursor) + result^._else := elna_parser_statements(cursor, error_list) else result^._else := nil end; @@ -3576,7 +3650,7 @@ begin return result end -proc elna_parser_statement(cursor: ^ElnaLexerCursor) -> ^ElnaTreeStatement +proc elna_parser_statement(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeStatement var result: ^ElnaTreeStatement designator: ^ElnaTreeNode @@ -3586,26 +3660,27 @@ begin token := elna_lexer_peek(cursor); if token^.kind = ElnaLexerKind._goto then - result := elna_parser_goto_statement(cursor) + result := elna_parser_goto_statement(cursor, error_list) elsif token^.kind = ElnaLexerKind._if then - result := elna_parser_if_statement(cursor) + result := elna_parser_if_statement(cursor, error_list) elsif token^.kind = ElnaLexerKind._return then - result := elna_parser_return_statement(cursor) + result := elna_parser_return_statement(cursor, error_list) elsif token^.kind = ElnaLexerKind.dot then - result := elna_parser_label_declaration(cursor) + result := elna_parser_label_declaration(cursor, error_list) elsif token^.kind = ElnaLexerKind.identifier then - designator := elna_parser_designator(cursor); - - if designator^.kind <> ElnaTreeKind.call then - result := elna_parser_assign_statement(cursor, designator) - else - result := designator + designator := elna_parser_designator(cursor, error_list); + if designator <> nil then + if designator^.kind <> ElnaTreeKind.call then + result := elna_parser_assign_statement(cursor, designator, error_list) + else + result := designator + end end end; return result end -proc elna_parser_statements(cursor: ^ElnaLexerCursor) -> ^ElnaTreeStatement +proc elna_parser_statements(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeStatement var previous_statement: ^ElnaTreeStatement next_statement: ^ElnaTreeStatement @@ -3614,9 +3689,9 @@ var begin elna_lexer_skip_empty_lines(cursor); - first_statement := elna_parser_statement(cursor); + first_statement := elna_parser_statement(cursor, error_list); previous_statement := first_statement; - if previous_statement = 0 then + if previous_statement = nil then goto elna_parser_statements_end end; @@ -3626,11 +3701,11 @@ begin if token^.kind = ElnaLexerKind.semicolon then elna_lexer_read(cursor); elna_lexer_skip_empty_lines(cursor); - next_statement := elna_parser_statement(cursor); + next_statement := elna_parser_statement(cursor, error_list); previous_statement^.next := next_statement; previous_statement := next_statement; - if previous_statement <> 0 then + if elna_list_empty(error_list) then goto elna_parser_statement_loop end end; @@ -3706,28 +3781,38 @@ end *) proc _write_register(register_character: Word, register_number: Word) begin - _write_c(register_character); - _write_c(register_number + '0') + _write_c(1, register_character); + _write_c(1, register_number + '0') end -proc elna_parser_record_type_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeRecordTypeExpression +proc elna_parser_record_type_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeRecordTypeExpression var entry: ^ElnaTreeField result: ^ElnaTreeRecordTypeExpression previous_entry: ^ElnaTreeField token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken begin elna_lexer_read(cursor); result := malloc(#size(ElnaTreeRecordTypeExpression)); + result^.kind := ElnaTreeKind.record_type_expression; result^.members := nil; result^.length := 0; + .elna_parser_record_type_expression_loop; token := elna_lexer_read(cursor); if token^.kind = ElnaLexerKind._end then goto elna_parser_record_type_expression_end + elsif token^.kind <> ElnaLexerKind.identifier then + parser_error := elna_error_unexpected_token_create(cursor, 2); + parser_error^.expected[1] := ElnaLexerKind._end; + parser_error^.expected[2] := ElnaLexerKind.identifier; + + elna_list_append(error_list, parser_error); + result := free_and_nil(result); + goto elna_parser_record_type_expression_end end; - .elna_parser_record_type_expression_loop; entry := malloc(#size(ElnaTreeField)); result^.length := result^.length + 1; @@ -3735,9 +3820,15 @@ begin entry^.length := token^.length; (* Skip the colon. *) - elna_lexer_read(cursor); + if elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) = nil then + result := free_and_nil(result); + goto elna_parser_record_type_expression_end + end; - entry^.type_expression := elna_parser_type_expression(cursor); + entry^.type_expression := elna_parser_type_expression(cursor, error_list); + if entry^.type_expression = nil then + goto elna_parser_record_type_expression_end + end; entry^.next := nil; if result^.members = nil then @@ -3749,22 +3840,26 @@ begin token := elna_lexer_read(cursor); if token^.kind = ElnaLexerKind.semicolon then - token := elna_lexer_read(cursor); goto elna_parser_record_type_expression_loop + elsif token^.kind <> ElnaLexerKind._end then + parser_error := elna_error_unexpected_token_create(cursor, 2); + parser_error^.expected[1] := ElnaLexerKind._end; + parser_error^.expected[2] := ElnaLexerKind.semicolon; + + elna_list_append(error_list, parser_error) end; .elna_parser_record_type_expression_end; - result^.kind := ElnaTreeKind.record_type_expression; - return result end -proc elna_parser_enumeration_type_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeEnumerationTypeExpression +proc elna_parser_enumeration_type_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeEnumerationTypeExpression var result: ^ElnaTreeEnumerationTypeExpression entry: ^ElnaTreeEnumeration previous_entry: ^ElnaTreeEnumeration token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken begin elna_lexer_read(cursor); @@ -3774,25 +3869,38 @@ begin result^.length := 0; .elna_parser_enumeration_type_expression_loop; - token := elna_lexer_read(cursor); - entry := malloc(#size(ElnaTreeEnumeration)); - result^.length := result^.length + 1; + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token <> nil then + entry := malloc(#size(ElnaTreeEnumeration)); + result^.length := result^.length + 1; - entry^.name := token^.start; - entry^.length := token^.length; - entry^.next := nil; + entry^.name := token^.start; + entry^.length := token^.length; + entry^.next := nil; - if result^.members = nil then - result^.members := entry + if result^.members = nil then + result^.members := entry + else + previous_entry^.next := entry + end; + previous_entry := entry; + + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.comma then + elna_lexer_read(cursor); + goto elna_parser_enumeration_type_expression_loop + elsif token^.kind = ElnaLexerKind.right_paren then + elna_lexer_read(cursor) + else + parser_error := elna_error_unexpected_token_create(cursor, 2); + parser_error^.expected[1] := ElnaLexerKind.comma; + parser_error^.expected[2] := ElnaLexerKind.right_paren; + + elna_list_append(error_list, parser_error); + result := free_and_nil(result) + end else - previous_entry^.next := entry - end; - previous_entry := entry; - - (* Skip the identifier. *) - token := elna_lexer_read(cursor); - if token^.kind = ElnaLexerKind.comma then - goto elna_parser_enumeration_type_expression_loop + result := free_and_nil(result) end; return result end @@ -3940,7 +4048,7 @@ begin return result end -proc elna_parser_pointer_type_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreePointerTypeExpression +proc elna_parser_pointer_type_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreePointerTypeExpression var result: ^ElnaTreePointerTypeExpression begin @@ -3948,12 +4056,15 @@ begin result := malloc(#size(ElnaTreePointerTypeExpression)); result^.kind := ElnaTreeKind.pointer_type_expression; - result^.base := elna_parser_type_expression(cursor); + result^.base := elna_parser_type_expression(cursor, error_list); + if result^.base = nil then + result := free_and_nil(result) + end; return result end -proc elna_parser_array_type_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeArrayTypeExpression +proc elna_parser_array_type_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeArrayTypeExpression var result: ^ElnaTreeArrayTypeExpression begin @@ -3961,20 +4072,29 @@ begin result := malloc(#size(ElnaTreeArrayTypeExpression)); result^.kind := ElnaTreeKind.array_type_expression; - result^.length := elna_parser_binary_expression(cursor); - (* Read and skip square bracket. *) - elna_lexer_read(cursor); - - result^.base := elna_parser_type_expression(cursor); + result^.length := elna_parser_binary_expression(cursor, error_list); + if result^.length = nil then + result := free_and_nil(result) + else + if elna_parser_expect(cursor, ElnaLexerKind.right_square, error_list) = nil then + result := free_and_nil(result) + else + result^.base := elna_parser_type_expression(cursor, error_list); + if result^.base = nil then + result := free_and_nil(result) + end + end + end; return result end -proc elna_parser_type_expression(cursor: ^ElnaLexerCursor) -> ^ElnaTreeNode +proc elna_parser_type_expression(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeNode var result: ^ElnaTreeNode token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken begin result := nil; token := elna_lexer_peek(cursor); @@ -3982,13 +4102,22 @@ begin if token^.kind = ElnaLexerKind.identifier then result := elna_parser_named_type_expression(cursor) elsif token^.kind = ElnaLexerKind.left_paren then - result := elna_parser_enumeration_type_expression(cursor) + result := elna_parser_enumeration_type_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind._record then - result := elna_parser_record_type_expression(cursor) + result := elna_parser_record_type_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.hat then - result := elna_parser_pointer_type_expression(cursor) + result := elna_parser_pointer_type_expression(cursor, error_list) elsif token^.kind = ElnaLexerKind.left_square then - result := elna_parser_array_type_expression(cursor) + result := elna_parser_array_type_expression(cursor, error_list) + else + parser_error := elna_error_unexpected_token_create(cursor, 5); + parser_error^.expected[1] := ElnaLexerKind.identifier; + parser_error^.expected[2] := ElnaLexerKind.left_paren; + parser_error^.expected[3] := ElnaLexerKind._record; + parser_error^.expected[4] := ElnaLexerKind.hat; + parser_error^.expected[5] := ElnaLexerKind.left_square; + + elna_list_append(error_list, parser_error) end; return result end @@ -4090,38 +4219,47 @@ begin end end -proc elna_parser_procedure_declaration(cursor: ^ElnaLexerCursor) -> ^ElnaTreeProcedureDeclaration +proc elna_parser_procedure_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeProcedureDeclaration var next_declaration: ^ElnaTreeDeclaration current_declaration: ^ElnaTreeDeclaration result: ^ElnaTreeProcedureDeclaration - parameter_head: ^ElnaTreeDeclaration token: ^ElnaLexerToken begin - result := malloc(#size(ElnaTreeProcedureDeclaration)); + (* Skip "proc ". *) + elna_lexer_read(cursor); + result := nil; + (* Skip procedure name. *) + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token = nil then + goto elna_parser_procedure_declaration_end + end; + + result := malloc(#size(ElnaTreeProcedureDeclaration)); result^.kind := ElnaTreeKind.procedure_declaration; result^.next := nil; - (* Skip "proc ". *) - elna_lexer_read(cursor); - - (* Skip procedure name. *) - token := elna_lexer_read(cursor); result^.name := token^.start; result^.length := token^.length; - (* Skip open paren. *) - elna_lexer_read(cursor); - parameter_head := nil; + if elna_parser_expect(cursor, ElnaLexerKind.left_paren, error_list) = nil then + result := free_and_nil(result); + goto elna_parser_procedure_declaration_end + end; + result^.parameters := nil; .elna_parser_procedure_declaration_parameter; token := elna_lexer_peek(cursor); if token^.kind <> ElnaLexerKind.right_paren then - next_declaration := elna_parser_variable_declaration(cursor); - if parameter_head = nil then - parameter_head := next_declaration + next_declaration := elna_parser_variable_declaration(cursor, error_list); + if next_declaration = nil then + result := free_and_nil(result); + goto elna_parser_procedure_declaration_end + end; + if result^.parameters = nil then + result^.parameters := next_declaration else current_declaration^.next := next_declaration end; @@ -4135,34 +4273,52 @@ begin end end; (* Skip close paren. *) - elna_lexer_read(cursor); - result^.parameters := parameter_head; + if elna_parser_expect(cursor, ElnaLexerKind.right_paren, error_list) = nil then + result := free_and_nil(result); + goto elna_parser_procedure_declaration_end + end; (* Skip semicolon or arrow. *) token := elna_lexer_peek(cursor); if token^.kind = ElnaLexerKind.arrow then elna_lexer_read(cursor); - result^.return_type := elna_parser_type_expression(cursor) + result^.return_type := elna_parser_type_expression(cursor, error_list); + if result^.return_type = nil then + result := free_and_nil(result); + goto elna_parser_procedure_declaration_end + end else result^.return_type := nil end; - parameter_head := elna_parser_var_part(cursor); - result^.temporaries := parameter_head; + result^.temporaries := elna_parser_var_part(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result); + goto elna_parser_procedure_declaration_end + end; - (* Skip semicolon, "begin" and newline. *) + (* Parser the procedure body if any. *) token := elna_lexer_peek(cursor); if token^.kind = ElnaLexerKind._begin then elna_lexer_read(cursor); - parameter_head := elna_parser_statements(cursor) + result^.body := elna_parser_statements(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result); + goto elna_parser_procedure_declaration_end + end elsif token^.kind = ElnaLexerKind._return then - parameter_head := elna_parser_return_statement(cursor) + result^.body := elna_parser_return_statement(cursor, error_list); + if result^.body = nil then + result := free_and_nil(result); + goto elna_parser_procedure_declaration_end + end end; - result^.body := parameter_head; - (* Skip the "end" keyword. *) - elna_lexer_read(cursor); + if elna_parser_expect(cursor, ElnaLexerKind._end, error_list) = false then + result := free_and_nil(result) + end; + .elna_parser_procedure_declaration_end; return result end @@ -4429,7 +4585,7 @@ begin return result end -proc elna_parser_procedures(cursor: ^ElnaLexerCursor) -> ^ElnaTreeDeclaration +proc elna_parser_procedures(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeDeclaration var parser_node: ^ElnaTreeDeclaration result: ^ElnaTreeDeclaration @@ -4443,15 +4599,17 @@ begin token := elna_lexer_peek(cursor); if token^.kind = ElnaLexerKind._proc then - parser_node := elna_parser_procedure_declaration(cursor); - if result = 0 then - result := parser_node - else - current_declaration^.next := parser_node - end; - current_declaration := parser_node; + parser_node := elna_parser_procedure_declaration(cursor, error_list); - goto elna_parser_procedures_loop + if parser_node <> nil then + if result = nil then + result := parser_node + else + current_declaration^.next := parser_node + end; + current_declaration := parser_node; + goto elna_parser_procedures_loop + end end; return result end @@ -4556,22 +4714,25 @@ begin end end -proc elna_parser_type_declaration(cursor: ^ElnaLexerCursor) -> ^ElnaTreeTypeDeclaration +proc elna_parser_type_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeTypeDeclaration var result: ^ElnaTreeTypeDeclaration token: ^ElnaLexerToken begin - result := malloc(#size(ElnaTreeTypeDeclaration)); token := elna_lexer_read(cursor); + result := nil; + result := malloc(#size(ElnaTreeTypeDeclaration)); result^.kind := ElnaTreeKind.type_declaration; result^.next := nil; result^.name := token^.start; result^.length := token^.length; - elna_lexer_read(cursor); - result^.type_expression := elna_parser_type_expression(cursor); - + if elna_parser_expect(cursor, ElnaLexerKind.equals, error_list) <> nil then + result^.type_expression := elna_parser_type_expression(cursor, error_list) + else + result := free_and_nil(result) + end; return result end @@ -4590,7 +4751,7 @@ proc elna_type_type_declaration(parser_node: Word) begin end -proc elna_parser_type_part(cursor: ^ElnaLexerCursor) -> ^ElnaTreeDeclaration +proc elna_parser_type_part(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeDeclaration var parser_node: ^ElnaTreeDeclaration result: ^ElnaTreeDeclaration @@ -4601,51 +4762,55 @@ begin elna_lexer_skip_empty_lines(cursor); token := elna_lexer_peek(cursor); - if token^.kind <> ElnaLexerKind._type then - goto elna_parser_type_part_end - end; - elna_lexer_read(cursor); + if token^.kind = ElnaLexerKind._type then + elna_lexer_read(cursor); - .elna_parser_type_part_loop; - elna_lexer_skip_empty_lines(cursor); + .elna_parser_type_part_loop; + elna_lexer_skip_empty_lines(cursor); - token := elna_lexer_peek(cursor); - if token^.kind = ElnaLexerKind.identifier then - parser_node := elna_parser_type_declaration(cursor); + token := elna_lexer_peek(cursor); + if token^.kind = ElnaLexerKind.identifier then + parser_node := elna_parser_type_declaration(cursor, error_list); - if result = nil then - result := parser_node - else - current_declaration^.next := parser_node + if parser_node <> nil then + if result = nil then + result := parser_node + else + current_declaration^.next := parser_node + end; + current_declaration := parser_node; + goto elna_parser_type_part_loop + end end; - current_declaration := parser_node; - goto elna_parser_type_part_loop end; - .elna_parser_type_part_end; return result end -proc elna_parser_variable_declaration(cursor: ^ElnaLexerCursor) -> ^ElnaTreeVariableDeclaration +proc elna_parser_variable_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeVariableDeclaration var variable_type: Word result: ^ElnaTreeVariableDeclaration token: ^ElnaLexerToken begin - token := elna_lexer_read(cursor); + token := elna_parser_expect(cursor, ElnaLexerKind.identifier, error_list); + if token <> nil then + result := nil; - (* Skip the variable name and colon with the type. *) - elna_lexer_read(cursor); + if elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) <> nil then + variable_type := elna_parser_type_expression(cursor, error_list); - variable_type := elna_parser_type_expression(cursor); - result := malloc(#size(ElnaTreeVariableDeclaration)); - - result^.kind := ElnaTreeKind.variable_declaration; - result^.next := nil; - result^.name := token^.start; - result^.length := token^.length; - result^.type_expression := variable_type; + if variable_type <> nil then + result := malloc(#size(ElnaTreeVariableDeclaration)); + result^.kind := ElnaTreeKind.variable_declaration; + result^.next := nil; + result^.name := token^.start; + result^.length := token^.length; + result^.type_expression := variable_type + end + end + end; return result end @@ -4665,7 +4830,7 @@ begin return result end -proc elna_parser_var_part(cursor: ^ElnaLexerCursor) -> ^ElnaTreeDeclaration +proc elna_parser_var_part(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeDeclaration var result: ^ElnaTreeDeclaration variable_node: ^ElnaTreeDeclaration @@ -4686,7 +4851,7 @@ begin token := elna_lexer_peek(cursor); if token^.kind = ElnaLexerKind.identifier then - variable_node := elna_parser_variable_declaration(cursor); + variable_node := elna_parser_variable_declaration(cursor, error_list); if result = nil then result := variable_node @@ -4730,7 +4895,7 @@ begin return first_variable end -proc elna_parser_program_body(cursor: ^ElnaLexerCursor) -> ^ElnaTreeStatement +proc elna_parser_program_body(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeStatement var result: ^ElnaTreeStatement token: ^ElnaLexerToken @@ -4740,38 +4905,82 @@ begin if token^.kind = ElnaLexerKind._begin then elna_lexer_read(cursor); - result := elna_parser_statements(cursor); + result := elna_parser_statements(cursor, error_list); end; return result end +proc elna_error_unexpected_token_create(cursor: ^ElnaLexerCursor, number_of_expected: Word) -> ^ElnaErrorUnexpectedToken +var + parser_error: ^ElnaErrorUnexpectedToken +begin + parser_error := malloc(#size(ElnaErrorUnexpectedToken)); + parser_error^.next := nil; + parser_error^.kind := ElnaErrorKind.unexpected_token; + parser_error^.position := cursor^.position; + parser_error^.possibilities := number_of_expected; + parser_error^.expected := malloc(#size(ElnaLexerKind) * number_of_expected); + parser_error^.got := cursor^.token^.kind; + + return parser_error +end + +(* Check and return whether the next token is of the expected kind. +If so the token is skipped, otherwise an error is added to the error list. *) +proc elna_parser_expect(cursor: ^ElnaLexerCursor, expected: ElnaLexerKind, error_list: ^ElnaList) -> ^ElnaLexerToken +var + token: ^ElnaLexerToken + parser_error: ^ElnaErrorUnexpectedToken +begin + elna_lexer_skip_empty_lines(cursor); + token := elna_lexer_peek(cursor); + + if token^.kind = expected then + token := elna_lexer_read(cursor) + else + token := nil; + + parser_error := elna_error_unexpected_token_create(cursor, 1); + parser_error^.expected[1] := expected; + + elna_list_append(error_list, parser_error) + end; + return token +end + proc elna_parser_module_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeModuleDeclaration var - parser_node: Word result: ^ElnaTreeModuleDeclaration - parser_error: ^ElnaError - token: ^ElnaLexerToken begin - result := malloc(#size(ElnaTreeModuleDeclaration)); - result^.kind := ElnaTreeKind.module_declaration; + result := nil; + if elna_parser_expect(cursor, ElnaLexerKind._program, error_list) <> nil then + if elna_parser_expect(cursor, ElnaLexerKind.semicolon, error_list) <> nil then + result := malloc(#size(ElnaTreeModuleDeclaration)); + result^.kind := ElnaTreeKind.module_declaration; - (* Skip "program;". *) - elna_lexer_skip_empty_lines(cursor); - token := elna_lexer_read(cursor); - - if token^.kind <> ElnaLexerKind._program then - parser_error := malloc(#size(ElnaError)); - parser_error^.next := nil; - - error_list^.first := parser_error; - error_list^.last := parser_error - else - elna_lexer_read(cursor); - - result^.types := elna_parser_type_part(cursor); - result^.globals := elna_parser_var_part(cursor); - result^.procedures := elna_parser_procedures(cursor); - result^.body := elna_parser_program_body(cursor) + result^.types := elna_parser_type_part(cursor, error_list); + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + end; + if result <> nil then + result^.globals := elna_parser_var_part(cursor, error_list); + end; + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + end; + if result <> nil then + result^.procedures := elna_parser_procedures(cursor, error_list); + end; + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + end; + if result <> nil then + result^.body := elna_parser_program_body(cursor, error_list) + end; + if elna_list_empty(error_list) = false then + result := free_and_nil(result) + end + end end; return result end @@ -5340,20 +5549,173 @@ begin end end +proc elna_error_print_token1(kind: ElnaLexerKind) +begin + if kind = ElnaLexerKind.identifier then + _write_s(2, "IDENTIFIER") + elsif kind = ElnaLexerKind._const then + _write_s(2, "\"const\"") + elsif kind = ElnaLexerKind._var then + _write_s(2, "\"var\"") + elsif kind = ElnaLexerKind._proc then + _write_s(2, "\"proc\"") + elsif kind = ElnaLexerKind._type then + _write_s(2, "\"type\"") + elsif kind = ElnaLexerKind._begin then + _write_s(2, "\"begin\"") + elsif kind = ElnaLexerKind._end then + _write_s(2, "\"end\"") + elsif kind = ElnaLexerKind._if then + _write_s(2, "\"if\"") + elsif kind = ElnaLexerKind._then then + _write_s(2, "\"then\"") + elsif kind = ElnaLexerKind._else then + _write_s(2, "\"else\"") + elsif kind = ElnaLexerKind._elsif then + _write_s(2, "\"elsif\"") + elsif kind = ElnaLexerKind._while then + _write_s(2, "\"while\"") + elsif kind = ElnaLexerKind._do then + _write_s(2, "\"do\"") + elsif kind = ElnaLexerKind._extern then + _write_s(2, "\"extern\"") + elsif kind = ElnaLexerKind._record then + _write_s(2, "\"record\"") + elsif kind = ElnaLexerKind.boolean then + _write_s(2, "BOOLEAN") + elsif kind = ElnaLexerKind.null then + _write_s(2, "NIL") + elsif kind = ElnaLexerKind.and then + _write_s(2, "\"&\"") + elsif kind = ElnaLexerKind._or then + _write_s(2, "\"or\"") + elsif kind = ElnaLexerKind._xor then + _write_s(2, "\"xor\"") + elsif kind = ElnaLexerKind.pipe then + _write_s(2, "\"|\"") + elsif kind = ElnaLexerKind.not then + _write_s(2, "\"~\"") + elsif kind = ElnaLexerKind._return then + _write_s(2, "\"return\"") + elsif kind = ElnaLexerKind._module then + _write_s(2, "\"module\"") + elsif kind = ElnaLexerKind._program then + _write_s(2, "\"program\"") + elsif kind = ElnaLexerKind._import then + _write_s(2, "\"import\"") + elsif kind = ElnaLexerKind._cast then + _write_s(2, "\"cast\"") + elsif kind = ElnaLexerKind.trait then + _write_s(2, "TRAIT") + elsif kind = ElnaLexerKind.left_paren then + _write_s(2, "\"(\"") + elsif kind = ElnaLexerKind.right_paren then + _write_s(2, "\")\"") + elsif kind = ElnaLexerKind.left_square then + _write_s(2, "\"[\"") + elsif kind = ElnaLexerKind.right_square then + _write_s(2, "\"]\"") + elsif kind = ElnaLexerKind.shift_left then + _write_s(2, "\"<<\"") + elsif kind = ElnaLexerKind.shift_right then + _write_s(2, "\">>\"") + elsif kind = ElnaLexerKind.greater_equal then + _write_s(2, "\">=\"") + elsif kind = ElnaLexerKind.less_equal then + _write_s(2, "\"<=\"") + elsif kind = ElnaLexerKind.greater_than then + _write_s(2, "\">\"") + elsif kind = ElnaLexerKind.less_than then + _write_s(2, "\"<\"") + elsif kind = ElnaLexerKind.not_equal then + _write_s(2, "\"<>\"") + elsif kind = ElnaLexerKind.equals then + _write_s(2, "\"=\"") + elsif kind = ElnaLexerKind.semicolon then + _write_s(2, "\";\"") + elsif kind = ElnaLexerKind.dot then + _write_s(2, "\".\"") + elsif kind = ElnaLexerKind.comma then + _write_s(2, "\",\"") + else + elna_error_print_token2(kind) + end +end + +proc elna_error_print_token2(kind: ElnaLexerKind) +begin + if kind = ElnaLexerKind.plus then + _write_s(2, "\"+\"") + elsif kind = ElnaLexerKind.arrow then + _write_s(2, "\"->\"") + elsif kind = ElnaLexerKind.minus then + _write_s(2, "\"-\"") + elsif kind = ElnaLexerKind.multiplication then + _write_s(2, "\"*\"") + elsif kind = ElnaLexerKind.division then + _write_s(2, "\"/\"") + elsif kind = ElnaLexerKind.remainder then + _write_s(2, "\"%\"") + elsif kind = ElnaLexerKind.assignment then + _write_s(2, "\":=\"") + elsif kind = ElnaLexerKind.colon then + _write_s(2, "\":\"") + elsif kind = ElnaLexerKind.hat then + _write_s(2, "\"^\"") + elsif kind = ElnaLexerKind.at then + _write_s(2, "\"@\"") + elsif kind = ElnaLexerKind.comment then + _write_s(2, "COMMENT") + elsif kind = ElnaLexerKind.string then + _write_s(2, "STRING") + elsif kind = ElnaLexerKind.character then + _write_s(2, "CHARACTER") + elsif kind = ElnaLexerKind.integer then + _write_s(2, "INTEGER") + elsif kind = ElnaLexerKind.word then + _write_s(2, "WORD") + elsif kind = ElnaLexerKind._goto then + _write_s(2, "\"goto\"") + elsif kind = ElnaLexerKind.eof then + _write_s(2, "EOF") + else + _write_s(2, "UNKNOWN") + end +end + +proc elna_error_print_unexpected_token(current_error: ^ElnaErrorUnexpectedToken) +begin + _write_s(2, "Parse error: Expecting token "); + elna_error_print_token1(current_error^.expected[1]); + _write_s(2, "; got "); + elna_error_print_token1(current_error^.got); + _write_s(2, ".\n") +end + +proc elna_error_print(current_error: ^ElnaError) +begin + if current_error^.kind = ElnaErrorKind.unexpected_token then + elna_error_print_unexpected_token(current_error) + else + _write_s(2, "Unknown error.\n") + end +end + proc compile() var parser_node: Word tac: Word rtl: Word error_list: ElnaList - compiled: Word + compiled: Bool lexer_state: ElnaLexerCursor + current_error: ^ElnaError begin elna_lexer_initialize(@lexer_state, source_code); elna_list_initialize(@error_list); parser_node := elna_parser_module_declaration(@lexer_state, @error_list); - compiled := error_list.first = nil; + compiled := elna_list_empty(@error_list); if compiled then elna_name_module_declaration(parser_node); @@ -5362,8 +5724,11 @@ begin rtl := elna_rtl_module_declaration(tac); elna_alloc_module(rtl); elna_fixup_module(rtl); - elna_riscv_module(rtl); - end; + elna_riscv_module(rtl) + else + current_error := error_list.first; + elna_error_print(current_error) + ind; return compiled end