summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/stage22/cl.elna1
-rw-r--r--boot/stage23/cl.elna1029
2 files changed, 697 insertions, 333 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 := malloc(#size(ElnaTreeCastExpression));
- result^.kind := ElnaTreeKind._cast;
- result^.type_decoration := nil;
+ result := 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);
+ 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;
+ 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);
-
- 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 := elna_parser_designator(cursor, error_list);
+ if result <> nil then
+ 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
+ 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
- else
- previous_entry^.next := entry
- end;
- previous_entry := entry;
+ if result^.members = nil then
+ result^.members := entry
+ 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
+ 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
+ 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));
-
- result^.kind := ElnaTreeKind.procedure_declaration;
- result^.next := nil;
-
(* Skip "proc ". *)
elna_lexer_read(cursor);
+ result := nil;
(* Skip procedure name. *)
- token := elna_lexer_read(cursor);
+ 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;
+
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);
-
- .elna_parser_type_part_loop;
- elna_lexer_skip_empty_lines(cursor);
+ if token^.kind = ElnaLexerKind._type then
+ elna_lexer_read(cursor);
- token := elna_lexer_peek(cursor);
- if token^.kind = ElnaLexerKind.identifier then
- parser_node := elna_parser_type_declaration(cursor);
+ .elna_parser_type_part_loop;
+ elna_lexer_skip_empty_lines(cursor);
- if result = nil then
- result := parser_node
- else
- current_declaration^.next := parser_node
+ token := elna_lexer_peek(cursor);
+ if token^.kind = ElnaLexerKind.identifier then
+ parser_node := elna_parser_type_declaration(cursor, error_list);
+
+ 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);
-
- variable_type := elna_parser_type_expression(cursor);
- result := malloc(#size(ElnaTreeVariableDeclaration));
+ if elna_parser_expect(cursor, ElnaLexerKind.colon, error_list) <> nil then
+ variable_type := elna_parser_type_expression(cursor, error_list);
- 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_parser_module_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeModuleDeclaration
+proc elna_error_unexpected_token_create(cursor: ^ElnaLexerCursor, number_of_expected: Word) -> ^ElnaErrorUnexpectedToken
var
- parser_node: Word
- result: ^ElnaTreeModuleDeclaration
- parser_error: ^ElnaError
- token: ^ElnaLexerToken
+ parser_error: ^ElnaErrorUnexpectedToken
begin
- result := malloc(#size(ElnaTreeModuleDeclaration));
- result^.kind := ElnaTreeKind.module_declaration;
+ 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;
- (* Skip "program;". *)
- elna_lexer_skip_empty_lines(cursor);
- token := elna_lexer_read(cursor);
+ return parser_error
+end
- if token^.kind <> ElnaLexerKind._program then
- parser_error := malloc(#size(ElnaError));
- parser_error^.next := nil;
+(* 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);
- error_list^.first := parser_error;
- error_list^.last := parser_error
+ if token^.kind = expected then
+ token := elna_lexer_read(cursor)
else
- elna_lexer_read(cursor);
+ 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
- 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)
+proc elna_parser_module_declaration(cursor: ^ElnaLexerCursor, error_list: ^ElnaList) -> ^ElnaTreeModuleDeclaration
+var
+ result: ^ElnaTreeModuleDeclaration
+begin
+ 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;
+
+ 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