implementation module Parser; from SYSTEM import TSIZE; from MemUtils import MemZero; from Storage import ALLOCATE, REALLOCATE; from Lexer import LexerKind, LexerToken, lexer_current, lexer_lex; (* Calls lexer_lex() but skips the comments. *) proc transpiler_lex(lexer: PLexer) -> 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(lexer: PLexer) -> PAstFieldDeclaration; var token: LexerToken; field_declarations: PAstFieldDeclaration; field_count: CARDINAL; current_field: PAstFieldDeclaration; begin ALLOCATE(field_declarations, TSIZE(AstFieldDeclaration)); token := transpiler_lex(lexer); field_count := 0; while token.kind <> lexerKindEnd do INC(field_count); REALLOCATE(field_declarations, TSIZE(AstFieldDeclaration) * (field_count + 1)); current_field := field_declarations; INC(current_field , TSIZE(AstFieldDeclaration) * (field_count - 1)); token := transpiler_lex(lexer); current_field^.field_name := token.identifierKind; token := transpiler_lex(lexer); current_field^.field_type := parse_type_expression(lexer); token := transpiler_lex(lexer); if token.kind = lexerKindSemicolon then token := transpiler_lex(lexer) end end; INC(current_field, TSIZE(AstFieldDeclaration)); MemZero(current_field, TSIZE(AstFieldDeclaration)); return field_declarations end; proc parse_record_type(lexer: PLexer) -> PAstTypeExpression; var result: PAstTypeExpression; begin ALLOCATE(result, TSIZE(AstTypeExpression)); result^.kind := astTypeExpressionKindRecord; result^.fields := parse_type_fields(lexer); return result end; proc parse_pointer_type(lexer: PLexer) -> PAstTypeExpression; var token: LexerToken; result: PAstTypeExpression; begin ALLOCATE(result, TSIZE(AstTypeExpression)); result^.kind := astTypeExpressionKindPointer; token := lexer_current(lexer); if token.kind = lexerKindPointer then token := transpiler_lex(lexer) end; token := lexer_current(lexer); result^.target := parse_type_expression(lexer); return result end; proc parse_array_type(lexer: PLexer) -> PAstTypeExpression; var token: LexerToken; buffer: [20]CHAR; result: PAstTypeExpression; begin ALLOCATE(result, TSIZE(AstTypeExpression)); result^.kind := astTypeExpressionKindArray; result^.length := 0; token := lexer_current(lexer); if token.kind = lexerKindArray then token := transpiler_lex(lexer) end; if token.kind <> lexerKindOf then token := transpiler_lex(lexer); result^.length := token.integerKind; token := transpiler_lex(lexer); end; token := transpiler_lex(lexer); result^.base := parse_type_expression(lexer); return result end; proc parse_enumeration_type(lexer: PLexer) -> PAstTypeExpression; var token: LexerToken; result: PAstTypeExpression; current_case: PIdentifier; case_count: CARDINAL; begin ALLOCATE(result, TSIZE(AstTypeExpression)); result^.kind := astTypeExpressionKindEnumeration; case_count := 1; ALLOCATE(result^.cases, TSIZE(Identifier) * 2); token := transpiler_lex(lexer); current_case := result^.cases; current_case^ := token.identifierKind; token := transpiler_lex(lexer); while token.kind = lexerKindComma do token := transpiler_lex(lexer); INC(case_count); REALLOCATE(result^.cases, TSIZE(Identifier) * (case_count + 1)); current_case := result^.cases; INC(current_case, TSIZE(Identifier) * (case_count - 1)); current_case^ := token.identifierKind; token := transpiler_lex(lexer) end; INC(current_case, TSIZE(Identifier)); MemZero(current_case, TSIZE(Identifier)); return result end; proc parse_named_type(lexer: PLexer) -> PAstTypeExpression; var token: LexerToken; result: PAstTypeExpression; written_bytes: CARDINAL; begin token := lexer_current(lexer); ALLOCATE(result, TSIZE(AstTypeExpression)); result^.kind := astTypeExpressionKindNamed; result^.name := token.identifierKind; return result end; proc parse_procedure_type(lexer: PLexer) -> PAstTypeExpression; var token: LexerToken; result: PAstTypeExpression; current_parameter: PPAstTypeExpression; parameter_count: CARDINAL; begin parameter_count := 0; ALLOCATE(result, TSIZE(AstTypeExpression)); result^.kind := astTypeExpressionKindProcedure; ALLOCATE(result^.parameters, 1); token := transpiler_lex(lexer); token := transpiler_lex(lexer); while token.kind <> lexerKindRightParen do INC(parameter_count); REALLOCATE(result^.parameters, TSIZE(PAstTypeExpression) * (parameter_count + 1)); current_parameter := result^.parameters; INC(current_parameter, TSIZE(PAstTypeExpression) * (parameter_count - 1)); current_parameter^ := parse_type_expression(lexer); token := transpiler_lex(lexer); if token.kind = lexerKindComma then token := transpiler_lex(lexer) end end; current_parameter := result^.parameters; INC(current_parameter, TSIZE(PAstTypeExpression) * parameter_count); current_parameter^ := nil; return result end; proc parse_type_expression(lexer: PLexer) -> PAstTypeExpression; var token: LexerToken; result: PAstTypeExpression; begin result := nil; token := lexer_current(lexer); if token.kind = lexerKindRecord then result := parse_record_type(lexer) end; if token.kind = lexerKindLeftParen then result := parse_enumeration_type(lexer) end; if (token.kind = lexerKindArray) or (token.kind = lexerKindLeftSquare) then result := parse_array_type(lexer) end; if token.kind = lexerKindHat then result := parse_pointer_type(lexer) end; if token.kind = lexerKindProc then result := parse_procedure_type(lexer) end; if token.kind = lexerKindIdentifier then result := parse_named_type(lexer) end; return result end; end.