Files
elna/source/Parser.elna

1195 lines
31 KiB
Plaintext

(* This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/. *)
module;
from FIO import ReadNBytes;
from MemUtils import MemZero;
from Storage import ALLOCATE, REALLOCATE;
from Common import Identifier, ShortString;
from Lexer import Lexer, LexerKind, LexerToken, lexer_current, lexer_lex;
type
Parser = record
lexer: ^Lexer
end;
AstLiteralKind* = (
integer,
string,
null,
boolean
);
AstLiteral* = record
kind: AstLiteralKind;
value: union
integer: Int;
string: ShortString;
boolean: Bool
end
end;
AstUnaryOperator* = (
reference,
not,
minus
);
AstBinaryOperator* = (
sum,
subtraction,
multiplication,
division,
remainder,
equals,
not_equals,
less,
greater,
less_equal,
greater_equal,
disjunction,
conjunction,
exclusive_disjunction,
shift_left,
shift_right
);
AstExpressionKind* = (
literal,
identifier,
array_access,
dereference,
field_access,
unary,
binary,
call
);
AstExpression* = record
kind: AstExpressionKind
value: union
literal: ^AstLiteral;
identifier: Identifier;
reference: ^AstExpression;
array_access: record
array: ^AstExpression;
index: ^AstExpression
end;
field_access: record
aggregate: ^AstExpression;
field: Identifier
end;
unary: record
operator: AstUnaryOperator;
operand: ^AstExpression
end;
binary: record
operator: AstBinaryOperator;
lhs: ^AstExpression;
rhs: ^AstExpression
end;
call: record
callable: ^AstExpression;
argument_count: Word;
arguments: ^^AstExpression
end
end
end;
ConditionalStatement = record
condition: ^AstExpression;
branch: AstCompoundStatement
end;
AstStatementKind* = (
if_statement,
while_statement,
assignment_statement,
return_statement,
call_statement
);
AstStatement* = record
kind: AstStatementKind
value: union
if_statement: ConditionalStatement;
while_statement: ConditionalStatement;
assignment_statement: record
assignee: ^AstExpression;
assignment: ^AstExpression
end;
return_statement: ^AstExpression;
call_statement: ^AstExpression
end
end;
AstCompoundStatement* = record
count: Word;
statements: ^^AstStatement
end;
AstImportStatement* = record
package: Identifier;
symbols: ^Identifier
end;
AstConstantDeclaration* = record
constant_name: Identifier;
constant_value: Int
end;
AstFieldDeclaration* = record
field_name: Identifier;
field_type: ^AstTypeExpression
end;
AstTypeExpressionKind* = (
named_expression,
record_expression,
enumeration_expression,
array_expression,
pointer_expression,
procedure_expression
);
AstTypeExpression* = record
kind: AstTypeExpressionKind;
value: union
name: Identifier;
cases: ^Identifier;
target: ^AstTypeExpression;
fields: ^AstFieldDeclaration;
array_expression: record
base: ^AstTypeExpression;
length: Word
end;
parameters: ^^AstTypeExpression
end
end;
AstTypedDeclaration* = record
identifier: Identifier;
type_expression: ^AstTypeExpression
end;
AstVariableDeclaration* = record
variable_name: Identifier;
variable_type: ^AstTypeExpression
end;
AstProcedureDeclaration* = record
name: Identifier;
parameter_count: Word;
parameters: ^AstTypedDeclaration;
return_type: ^AstTypeExpression;
constants: ^^AstConstantDeclaration;
variables: ^^AstVariableDeclaration;
statements: AstCompoundStatement
end;
AstModule* = record
main: Bool;
imports: ^^AstImportStatement;
constants: ^^AstConstantDeclaration;
types: ^^AstTypedDeclaration;
variables: ^^AstVariableDeclaration;
procedures: ^^AstProcedureDeclaration;
statements: AstCompoundStatement
end;
(* Calls lexer_lex() but skips the comments. *)
proc parser_lex(lexer: ^Lexer) -> LexerToken;
var
result: LexerToken;
begin
result := lexer_lex(lexer);
while result.kind = lexerKindComment do
result := lexer_lex(lexer)
end;
return result
end;
proc parse_type_fields(parser: ^Parser) -> ^AstFieldDeclaration;
var
token: LexerToken;
field_declarations: ^AstFieldDeclaration;
field_count: Word;
current_field: ^AstFieldDeclaration;
begin
ALLOCATE(field_declarations, #size(AstFieldDeclaration));
token := parser_lex(parser^.lexer);
field_count := 0;
while token.kind <> lexerKindEnd do
field_count := field_count + 2u;
REALLOCATE(field_declarations, #size(AstFieldDeclaration) * field_count);
field_count := field_count - 1u;
current_field := field_declarations;
INC(current_field , #size(AstFieldDeclaration) * (field_count - 1));
token := parser_lex(parser^.lexer);
current_field^.field_name := token.identifierKind;
token := parser_lex(parser^.lexer);
current_field^.field_type := parse_type_expression(parser);
token := parser_lex(parser^.lexer);
if token.kind = lexerKindSemicolon then
token := parser_lex(parser^.lexer)
end
end;
INC(current_field, #size(AstFieldDeclaration));
MemZero(current_field, #size(AstFieldDeclaration));
return field_declarations
end;
proc parse_record_type(parser: ^Parser) -> ^AstTypeExpression;
var
result: ^AstTypeExpression;
begin
NEW(result);
result^.kind := AstTypeExpressionKind.record_expression;
result^.fields := parse_type_fields(parser);
return result
end;
proc parse_pointer_type(parser: ^Parser) -> ^AstTypeExpression;
var
token: LexerToken;
result: ^AstTypeExpression;
begin
NEW(result);
result^.kind := AstTypeExpressionKind.pointer_expression;
token := lexer_current(parser^.lexer);
if token.kind = lexerKindPointer then
token := parser_lex(parser^.lexer)
end;
token := lexer_current(parser^.lexer);
result^.target := parse_type_expression(parser);
return result
end;
proc parse_array_type(parser: ^Parser) -> ^AstTypeExpression;
var
token: LexerToken;
buffer: [20]CHAR;
result: ^AstTypeExpression;
begin
NEW(result);
result^.kind := AstTypeExpressionKind.array_expression;
result^.array_expression.length := 0u;
token := lexer_current(parser^.lexer);
if token.kind = lexerKindArray then
token := parser_lex(parser^.lexer)
end;
if token.kind <> lexerKindOf then
token := parser_lex(parser^.lexer);
result^.array_expression.length := token.integerKind;
token := parser_lex(parser^.lexer)
end;
token := parser_lex(parser^.lexer);
result^.array_expression.base := parse_type_expression(parser);
return result
end;
proc parse_enumeration_type(parser: ^Parser) -> ^AstTypeExpression;
var
token: LexerToken;
result: ^AstTypeExpression;
current_case: ^Identifier;
case_count: Word;
begin
NEW(result);
result^.kind := AstTypeExpressionKind.enumeration_expression;
case_count := 1;
ALLOCATE(result^.cases, #size(Identifier) * 2);
token := parser_lex(parser^.lexer);
current_case := result^.cases;
current_case^ := token.identifierKind;
token := parser_lex(parser^.lexer);
while token.kind = lexerKindComma do
token := parser_lex(parser^.lexer);
case_count := case_count + 2u;
REALLOCATE(result^.cases, #size(Identifier) * case_count);
case_count := case_count - 1u;
current_case := result^.cases;
INC(current_case, #size(Identifier) * (case_count - 1));
current_case^ := token.identifierKind;
token := parser_lex(parser^.lexer)
end;
INC(current_case, #size(Identifier));
MemZero(current_case, #size(Identifier));
return result
end;
proc parse_named_type(parser: ^Parser) -> ^AstTypeExpression;
var
token: LexerToken;
result: ^AstTypeExpression;
begin
token := lexer_current(parser^.lexer);
NEW(result);
result^.kind := AstTypeExpressionKind.named_expression;
result^.name := token.identifierKind;
return result
end;
proc parse_procedure_type(parser: ^Parser) -> ^AstTypeExpression;
var
token: LexerToken;
result: ^AstTypeExpression;
current_parameter: ^^AstTypeExpression;
parameter_count: Word;
begin
parameter_count := 0;
NEW(result);
result^.kind := AstTypeExpressionKind.procedure_expression;
ALLOCATE(result^.parameters, 1);
token := parser_lex(parser^.lexer);
token := parser_lex(parser^.lexer);
while token.kind <> lexerKindRightParen do
parameter_count := parameter_count + 2u;
REALLOCATE(result^.parameters, #size(^AstTypeExpression) * parameter_count);
parameter_count := parameter_count - 1u;
current_parameter := result^.parameters;
INC(current_parameter, #size(^AstTypeExpression) * (parameter_count - 1));
current_parameter^ := parse_type_expression(parser);
token := parser_lex(parser^.lexer);
if token.kind = lexerKindComma then
token := parser_lex(parser^.lexer)
end
end;
current_parameter := result^.parameters;
INC(current_parameter, #size(^AstTypeExpression) * parameter_count);
current_parameter^ := nil;
return result
end;
proc parse_type_expression(parser: ^Parser) -> ^AstTypeExpression;
var
token: LexerToken;
result: ^AstTypeExpression;
begin
result := nil;
token := lexer_current(parser^.lexer);
if token.kind = lexerKindRecord then
result := parse_record_type(parser)
end;
if token.kind = lexerKindLeftParen then
result := parse_enumeration_type(parser)
end;
if (token.kind = lexerKindArray) or (token.kind = lexerKindLeftSquare) then
result := parse_array_type(parser)
end;
if token.kind = lexerKindHat then
result := parse_pointer_type(parser)
end;
if token.kind = lexerKindProc then
result := parse_procedure_type(parser)
end;
if token.kind = lexerKindIdentifier then
result := parse_named_type(parser)
end;
return result
end;
proc parse_type_declaration(parser: ^Parser) -> ^AstTypedDeclaration;
var
token: LexerToken;
result: ^AstTypedDeclaration;
begin
token := lexer_current(parser^.lexer);
NEW(result);
result^.identifier := token.identifierKind;
token := parser_lex(parser^.lexer);
token := parser_lex(parser^.lexer);
result^.type_expression := parse_type_expression(parser);
token := parser_lex(parser^.lexer);
return result
end;
proc parse_type_part(parser: ^Parser) -> ^^AstTypedDeclaration;
var
token: LexerToken;
result: ^^AstTypedDeclaration;
current_declaration: ^^AstTypedDeclaration;
declaration_count: Word;
begin
token := lexer_current(parser^.lexer);
ALLOCATE(result, #size(^AstTypedDeclaration));
current_declaration := result;
declaration_count := 0u;
if token.kind = lexerKindType then
token := parser_lex(parser^.lexer);
while token.kind = lexerKindIdentifier do
declaration_count := declaration_count + 1u;
REALLOCATE(result, #size(^AstTypedDeclaration) * (declaration_count + 1));
current_declaration := result;
INC(current_declaration, #size(^AstTypedDeclaration) * (declaration_count - 1));
current_declaration^ := parse_type_declaration(parser);
token := parser_lex(parser^.lexer)
end
end;
if declaration_count <> 0u then
INC(current_declaration, #size(^AstTypedDeclaration))
end;
current_declaration^ := nil;
return result
end;
proc parse_variable_declaration(parser: ^Parser) -> ^AstVariableDeclaration;
var
token: LexerToken;
result: ^AstVariableDeclaration;
begin
NEW(result);
token := lexer_current(parser^.lexer);
result^.variable_name := token.identifierKind;
token := parser_lex(parser^.lexer);
token := parser_lex(parser^.lexer);
result^.variable_type := parse_type_expression(parser);
token := parser_lex(parser^.lexer);
return result
end;
proc parse_variable_part(parser: ^Parser) -> ^^AstVariableDeclaration;
var
token: LexerToken;
result: ^^AstVariableDeclaration;
current_declaration: ^^AstVariableDeclaration;
declaration_count: Word;
begin
token := lexer_current(parser^.lexer);
ALLOCATE(result, #size(^AstVariableDeclaration));
current_declaration := result;
declaration_count := 0;
if token.kind = lexerKindVar then
token := parser_lex(parser^.lexer);
while token.kind = lexerKindIdentifier do
declaration_count := declaration_count + 1u;
REALLOCATE(result, #size(^AstVariableDeclaration) * (declaration_count + 1));
current_declaration := result;
INC(current_declaration, #size(^AstVariableDeclaration) * (declaration_count - 1));
current_declaration^ := parse_variable_declaration(parser);
token := parser_lex(parser^.lexer)
end
end;
if declaration_count <> 0 then
INC(current_declaration, #size(^AstVariableDeclaration))
end;
current_declaration^ := nil;
return result
end;
proc parse_constant_declaration(parser: ^Parser) -> ^AstConstantDeclaration;
var
token: LexerToken;
result: ^AstConstantDeclaration;
begin
NEW(result);
token := lexer_current(parser^.lexer);
result^.constant_name := token.identifierKind;
token := parser_lex(parser^.lexer);
token := parser_lex(parser^.lexer);
result^.constant_value := token.integerKind;
token := parser_lex(parser^.lexer);
return result
end;
proc parse_constant_part(parser: ^Parser) -> ^^AstConstantDeclaration;
var
token: LexerToken;
result: ^^AstConstantDeclaration;
current_declaration: ^^AstConstantDeclaration;
declaration_count: Word;
begin
token := lexer_current(parser^.lexer);
ALLOCATE(result, #size(^AstConstantDeclaration));
current_declaration := result;
declaration_count := 0;
if token.kind = lexerKindConst then
token := parser_lex(parser^.lexer);
while token.kind = lexerKindIdentifier do
declaration_count := declaration_count + 1u;
REALLOCATE(result, #size(^AstConstantDeclaration) * (declaration_count + 1));
current_declaration := result;
INC(current_declaration, #size(^AstConstantDeclaration) * (declaration_count - 1));
current_declaration^ := parse_constant_declaration(parser);
token := parser_lex(parser^.lexer)
end
end;
if declaration_count <> 0 then
INC(current_declaration, #size(^AstConstantDeclaration))
end;
current_declaration^ := nil;
return result
end;
proc parse_import_statement(parser: ^Parser) -> ^AstImportStatement;
var
result: ^AstImportStatement;
token: LexerToken;
symbol_count: Word;
current_symbol: ^Identifier;
begin
NEW(result);
symbol_count := 1u;
token := parser_lex(parser^.lexer);
result^.package := token.identifierKind;
token := parser_lex(parser^.lexer);
ALLOCATE(result^.symbols, #size(Identifier) * 2);
current_symbol := result^.symbols;
token := parser_lex(parser^.lexer);
current_symbol^ := token.identifierKind;
token := parser_lex(parser^.lexer);
while token.kind <> lexerKindSemicolon do
token := parser_lex(parser^.lexer);
symbol_count := symbol_count + 1u;
REALLOCATE(result^.symbols, #size(Identifier) * (symbol_count + 1));
current_symbol := result^.symbols;
INC(current_symbol, #size(Identifier) * (symbol_count - 1));
current_symbol^ := token.identifierKind;
token := parser_lex(parser^.lexer)
end;
INC(current_symbol, #size(Identifier));
MemZero(current_symbol, #size(Identifier));
token := parser_lex(parser^.lexer);
return result
end;
proc parse_import_part(parser: ^Parser) -> ^^AstImportStatement;
var
token: LexerToken;
import_statement: ^^AstImportStatement;
result: ^^AstImportStatement;
import_count: Word;
begin
token := lexer_current(parser^.lexer);
ALLOCATE(result, #size(^AstImportStatement));
import_statement := result;
import_count := 0u;
while token.kind = lexerKindFrom do
import_count := import_count + 1u;
REALLOCATE(result, #size(^AstImportStatement) * (import_count + 1));
import_statement := result;
INC(import_statement, #size(^AstImportStatement) * (import_count - 1));
import_statement^ := parse_import_statement(parser);
token := lexer_current(parser^.lexer)
end;
if import_count > 0 then
INC(import_statement, #size(^AstImportStatement))
end;
import_statement^ := nil;
return result
end;
proc parse_literal(parser: ^Parser) -> ^AstLiteral;
var
literal: ^AstLiteral;
token: LexerToken;
begin
literal := nil;
token := lexer_current(parser^.lexer);
if token.kind = lexerKindInteger then
NEW(literal);
literal^.kind := AstLiteralKind.integer;
literal^.integer := token.integerKind
end;
if (token.kind = lexerKindCharacter) or (token.kind = lexerKindString) then
NEW(literal);
literal^.kind := AstLiteralKind.string;
literal^.string := token.stringKind
end;
if token.kind = lexerKindNull then
NEW(literal);
literal^.kind := AstLiteralKind.null
end;
if token.kind = lexerKindBoolean then
NEW(literal);
literal^.kind := AstLiteralKind.boolean;
literal^.boolean := token.booleanKind
end;
if literal <> nil then
token := parser_lex(parser^.lexer)
end;
return literal
end;
proc parse_factor(parser: ^Parser) -> ^AstExpression;
var
next_token: LexerToken;
result: ^AstExpression;
literal: ^AstLiteral;
begin
result := nil;
next_token := lexer_current(parser^.lexer);
literal := parse_literal(parser);
if (result = nil) & (literal <> nil) then
NEW(result);
result^.kind := AstExpressionKind.literal;
result^.literal := literal
end;
if (result = nil) & (next_token.kind = lexerKindMinus) then
NEW(result);
next_token := parser_lex(parser^.lexer);
result^.kind := AstExpressionKind.unary;
result^.unary.operator := AstUnaryOperator.minus;
result^.unary.operand := parse_factor(parser)
end;
if (result = nil) & (next_token.kind = lexerKindTilde) then
NEW(result);
next_token := parser_lex(parser^.lexer);
result^.kind := AstExpressionKind.unary;
result^.unary.operator := AstUnaryOperator.not;
result^.unary.operand := parse_factor(parser)
end;
if (result = nil) & (next_token.kind = lexerKindLeftParen) then
next_token := parser_lex(parser^.lexer);
result := parse_expression(parser);
if result <> nil then
next_token := parser_lex(parser^.lexer)
end
end;
if (result = nil) & (next_token.kind = lexerKindIdentifier) then
NEW(result);
result^.kind := AstExpressionKind.identifier;
result^.identifier := next_token.identifierKind;
next_token := parser_lex(parser^.lexer)
end;
return result
end;
proc parse_designator(parser: ^Parser) -> ^AstExpression;
var
next_token: LexerToken;
inner_expression: ^AstExpression;
designator: ^AstExpression;
arguments: ^^AstExpression;
handled: Bool;
begin
designator := parse_factor(parser);
handled := designator <> nil;
next_token := lexer_current(parser^.lexer);
while handled do
inner_expression := designator;
handled := false;
if ~handled & (next_token.kind = lexerKindHat) then
NEW(designator);
designator^.kind := AstExpressionKind.dereference;
designator^.reference := inner_expression;
next_token := parser_lex(parser^.lexer);
handled := true
end;
if ~handled & (next_token.kind = lexerKindLeftSquare) then
NEW(designator);
next_token := parser_lex(parser^.lexer);
designator^.kind := AstExpressionKind.array_access;
designator^.array_access.array := inner_expression;
designator^.array_access.index := parse_expression(parser);
next_token := parser_lex(parser^.lexer);
handled := true
end;
if ~handled & (next_token.kind = lexerKindDot) then
NEW(designator);
next_token := parser_lex(parser^.lexer);
designator^.kind := AstExpressionKind.field_access;
designator^.field_access.aggregate := inner_expression;
designator^.field_access.field := next_token.identifierKind;
next_token := parser_lex(parser^.lexer);
handled := true
end;
if ~handled & (next_token.kind = lexerKindLeftParen) then
NEW(designator);
next_token := parser_lex(parser^.lexer);
designator^.kind := AstExpressionKind.call;
designator^.call.callable := inner_expression;
designator^.call.argument_count := 0;
designator^.call.arguments := nil;
if next_token.kind <> lexerKindRightParen then
ALLOCATE(designator^.arguments, #size(^AstExpression));
designator^.argument_count := 1;
designator^.arguments^ := parse_expression(parser);
next_token := lexer_current(parser^.lexer);
while next_token.kind = lexerKindComma do
next_token := parser_lex(parser^.lexer);
designator^.argument_count := designator^.argument_count + 1;
REALLOCATE(designator^.arguments, #size(^AstExpression) * designator^.argument_count);
arguments := designator^.arguments;
INC(arguments, #size(^AstExpression) * (designator^.argument_count - 1));
arguments^ := parse_expression(parser);
next_token := lexer_current(parser^.lexer)
end
end;
next_token := parser_lex(parser^.lexer);
handled := true
end
end;
return designator
end;
proc parse_binary_expression(parser: ^Parser, left: ^AstExpression, operator: AstBinaryOperator) -> ^AstExpression;
var
next_token: LexerToken;
result: ^AstExpression;
right: ^AstExpression;
begin
next_token := parser_lex(parser^.lexer);
right := parse_designator(parser);
result := nil;
if right <> nil then
NEW(result);
result^.kind := AstExpressionKind.binary;
result^.binary.operator := operator;
result^.binary.lhs := left;
result^.binary.rhs := right
end;
return result
end;
proc parse_expression(parser: ^Parser) -> ^AstExpression;
var
next_token: LexerToken;
left: ^AstExpression;
result: ^AstExpression;
written_bytes: Word;
begin
left := parse_designator(parser);
result := nil;
next_token := lexer_current(parser^.lexer);
if left <> nil then
if (result = nil) & (next_token.kind = lexerKindNotEqual) then
result := parse_binary_expression(parser, left, AstBinaryOperator.not_equals)
end;
if (result = nil) & (next_token.kind = lexerKindEqual) then
result := parse_binary_expression(parser, left, AstBinaryOperator.equals)
end;
if (result = nil) & (next_token.kind = lexerKindGreaterThan) then
result := parse_binary_expression(parser, left, AstBinaryOperator.greater)
end;
if (result = nil) & (next_token.kind = lexerKindLessThan) then
result := parse_binary_expression(parser, left, AstBinaryOperator.less)
end;
if (result = nil) & (next_token.kind = lexerKindGreaterEqual) then
result := parse_binary_expression(parser, left, AstBinaryOperator.greater_equal)
end;
if (result = nil) & (next_token.kind = lexerKindLessEqual) then
result := parse_binary_expression(parser, left, AstBinaryOperator.less_equal)
end;
if (result = nil) & (next_token.kind = lexerKindAnd) then
result := parse_binary_expression(parser, left, AstBinaryOperator.conjunction)
end;
if (result = nil) & (next_token.kind = lexerKindOr) then
result := parse_binary_expression(parser, left, AstBinaryOperator.disjunction)
end;
if (result = nil) & (next_token.kind = lexerKindMinus) then
result := parse_binary_expression(parser, left, AstBinaryOperator.subtraction)
end;
if (result = nil) & (next_token.kind = lexerKindPlus) then
result := parse_binary_expression(parser, left, AstBinaryOperator.sum)
end;
if (result = nil) & (next_token.kind = lexerKindAsterisk) then
result := parse_binary_expression(parser, left, AstBinaryOperator.multiplication)
end
end;
if (result = nil) & (left <> nil) then
result := left
end;
return result
end;
proc parse_return_statement(parser: ^Parser) -> ^AstStatement;
var
token: LexerToken;
result: ^AstStatement;
begin
NEW(result);
result^.kind := AstStatementKind.return_statement;
token := parser_lex(parser^.lexer);
result^.return_statement := parse_expression(parser);
return result
end;
proc parse_assignment_statement(parser: ^Parser, assignee: ^AstExpression) -> ^AstStatement;
var
token: LexerToken;
result: ^AstStatement;
begin
NEW(result);
result^.kind := AstStatementKind.assignment_statement;
result^.assignment_statement.assignee := assignee;
token := parser_lex(parser^.lexer);
result^.assignment_statement.assignment := parse_expression(parser);
return result
end;
proc parse_call_statement(parser: ^Parser, call: ^AstExpression) -> ^AstStatement;
var
result: ^AstStatement;
begin
NEW(result);
result^.kind := AstStatementKind.call_statement;
result^.call_statement := call;
return result
end;
proc parse_compound_statement(parser: ^Parser) -> AstCompoundStatement;
var
result: AstCompoundStatement;
token: LexerToken;
current_statement: ^^AstStatement;
old_count: Word;
begin
result.count := 0u;
result.statements := nil;
token := lexer_current(parser^.lexer);
while token.kind <> lexerKindEnd do
old_count := result.count;
result.count := result.count + 1u;
REALLOCATE(result.statements, #size(^AstStatement) * result.count);
current_statement := result.statements;
INC(current_statement, #size(^AstStatement) * old_count);
current_statement^ := parse_statement(parser);
token := lexer_current(parser^.lexer)
end;
return result
end;
proc parse_statement(parser: ^Parser) -> ^AstStatement;
var
token: LexerToken;
statement: ^AstStatement;
designator: ^AstExpression;
begin
statement := nil;
token := parser_lex(parser^.lexer);
if token.kind = lexerKindIf then
statement := parse_if_statement(parser)
end;
if token.kind = lexerKindWhile then
statement := parse_while_statement(parser)
end;
if token.kind = lexerKindReturn then
statement := parse_return_statement(parser)
end;
if token.kind = lexerKindIdentifier then
designator := parse_designator(parser);
token := lexer_current(parser^.lexer);
if token.kind = lexerKindAssignment then
statement := parse_assignment_statement(parser, designator)
end;
if token.kind <> lexerKindAssignment then
statement := parse_call_statement(parser, designator)
end
end;
return statement
end;
proc parse_if_statement(parser: ^Parser) -> ^AstStatement;
var
token: LexerToken;
result: ^AstStatement;
begin
NEW(result);
result^.kind := AstStatementKind.if_statement;
token := parser_lex(parser^.lexer);
result^.if_statement.condition := parse_expression(parser);
result^.if_statement.branch := parse_compound_statement(parser);
token := parser_lex(parser^.lexer);
return result
end;
proc parse_while_statement(parser: ^Parser) -> ^AstStatement;
var
token: LexerToken;
result: ^AstStatement;
begin
NEW(result);
result^.kind := AstStatementKind.while_statement;
token := parser_lex(parser^.lexer);
result^.while_statement.condition := parse_expression(parser);
result^.while_statement.body := parse_compound_statement(parser);
token := parser_lex(parser^.lexer);
return result
end;
proc parse_statement_part(parser: ^Parser) -> AstCompoundStatement;
var
token: LexerToken;
compound: AstCompoundStatement;
begin
compound.count := 0;
compound.statements := nil;
token := lexer_current(parser^.lexer);
if token.kind = lexerKindBegin then
compound := parse_compound_statement(parser)
end;
return compound
end;
proc parse_procedure_heading(parser: ^Parser) -> ^AstProcedureDeclaration;
var
token: LexerToken;
declaration: ^AstProcedureDeclaration;
parameter_index: Word;
current_parameter: ^AstTypedDeclaration;
begin
NEW(declaration);
token := parser_lex(parser^.lexer);
declaration^.name := token.identifierKind;
token := parser_lex(parser^.lexer);
declaration^.parameters := nil;
declaration^.parameter_count := 0;
token := parser_lex(parser^.lexer);
while token.kind <> lexerKindRightParen do
parameter_index := declaration^.parameter_count;
INC(declaration^.parameter_count);
REALLOCATE(declaration^.parameters, #size(AstTypedDeclaration) * declaration^.parameter_count);
current_parameter := declaration^.parameters;
INC(current_parameter, #size(AstTypedDeclaration) * parameter_index);
current_parameter^.identifier := token.identifierKind;
token := parser_lex(parser^.lexer);
token := parser_lex(parser^.lexer);
current_parameter^.type_expression := parse_type_expression(parser);
token := parser_lex(parser^.lexer);
if token.kind = lexerKindComma then
token := parser_lex(parser^.lexer)
end
end;
token := parser_lex(parser^.lexer);
declaration^.return_type := nil;
(* Check for the return type and write it. *)
if token.kind = lexerKindArrow then
token := parser_lex(parser^.lexer);
declaration^.return_type := parse_type_expression(parser);
token := parser_lex(parser^.lexer)
end;
token := parser_lex(parser^.lexer);
return declaration
end;
proc parse_procedure_declaration(parser: ^Parser) -> ^AstProcedureDeclaration;
var
token: LexerToken;
declaration: ^AstProcedureDeclaration;
begin
declaration := parse_procedure_heading(parser);
declaration^.constants := parse_constant_part(parser);
declaration^.variables := parse_variable_part(parser);
declaration^.statements := parse_statement_part(parser);
token := parser_lex(parser^.lexer);
token := parser_lex(parser^.lexer);
return declaration
end;
proc parse_procedure_part(parser: ^Parser) -> ^^AstProcedureDeclaration;
var
token: LexerToken;
current_declaration: ^^AstProcedureDeclaration;
result: ^^AstProcedureDeclaration;
declaration_count: Word;
declaration_index: Word;
begin
token := lexer_current(parser^.lexer);
declaration_count := 0u;
declaration_index := 0u;
ALLOCATE(result, #size(^AstProcedureDeclaration));
while token.kind = lexerKindProc do
declaration_count := declaration_count + 1u;
REALLOCATE(result, #size(^AstProcedureDeclaration) * (declaration_count + 1));
current_declaration := result;
INC(current_declaration, #size(^AstProcedureDeclaration) * declaration_index);
current_declaration^ := parse_procedure_declaration(parser);
token := lexer_current(parser^.lexer);
declaration_index := declaration_count
end;
current_declaration := result;
INC(current_declaration, #size(^AstProcedureDeclaration) * declaration_index);
current_declaration^ := nil;
return result
end;
proc parse_module(parser: ^Parser) -> ^AstModule;
var
token: LexerToken;
result: ^AstModule;
begin
NEW(result);
token := parser_lex(parser^.lexer);
result^.main := true;
if token.kind = lexerKindModule then
result^.main := false
end;
token := parser_lex(parser^.lexer);
(* Write the module body. *)
token := parser_lex(parser^.lexer);
result^.imports := parse_import_part(parser);
result^.constants := parse_constant_part(parser);
result^.types := parse_type_part(parser);
result^.variables := parse_variable_part(parser);
result^.procedures := parse_procedure_part(parser);
result^.statements := parse_statement_part(parser);
token := parser_lex(parser^.lexer);
token := parser_lex(parser^.lexer);
return result
end;
proc parse*(lexer: ^Lexer) -> ^AstModule;
var
parser: Parser;
begin
parser.lexer := lexer;
return parse_module(@parser)
end;
end.