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..e47585c 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, @@ -674,6 +670,20 @@ 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; + got: ElnaLexerKind + end + var symbol_table_global: ^ElnaSymbolTable variable_map_global: ^ElnaSymbolTable @@ -693,6 +703,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. * @@ -847,6 +863,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 @@ -1857,17 +1879,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 +1904,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 +1931,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; @@ -2563,7 +2585,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 +2597,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 +2669,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 +2693,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 +2714,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 +2771,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 +2791,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 +2891,59 @@ 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; 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)); @@ -3022,19 +3075,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 +3107,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 +3172,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 +3208,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 +3293,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 +3304,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 +3462,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 +3517,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 +3565,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 +3574,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 +3619,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 +3631,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 +3654,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 +3664,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 +3693,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 +3705,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; @@ -3710,24 +3789,34 @@ begin _write_c(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 +3824,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 +3844,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 +3873,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 +4052,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 +4060,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 +4076,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 +4106,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 +4223,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 +4277,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 +4589,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 +4603,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 +4718,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 +4755,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 +4766,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 +4834,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 +4855,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 +4899,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 +4909,81 @@ 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^.got := cursor^.token^.kind; + parser_error^.expected := malloc(#size(ElnaLexerKind) * number_of_expected); + + 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 @@ -5353,7 +5565,7 @@ begin 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);