implementation module Transpiler; from FIO import WriteNBytes, StdOut; from SYSTEM import ADR, ADDRESS; from Terminal import Write, WriteLn, WriteString; from Lexer import Lexer, LexerToken, lexer_current, lexer_lex, LexerKind; type PTranspilerContext = ^TranspilerContext; TranspilerContext = record Indentation: CARDINAL end; (* Calls lexer_lex() but skips the comments. *) proc transpiler_lex(ALexer: PLexer): LexerToken; var Result: LexerToken; begin Result := lexer_lex(ALexer); while Result.Kind = lexerKindComment do Result := lexer_lex(ALexer) end; return Result end; (* Write a semicolon followed by a newline. *) proc write_semicolon(); begin WriteString(';'); WriteLn() end; proc transpile_import(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString('FROM '); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); WriteString(' IMPORT '); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); while Token.Kind <> lexerKindSemicolon do WriteString(', '); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer) end; write_semicolon(); Token := transpiler_lex(ALexer) end; proc transpile_import_part(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin Token := lexer_current(ALexer); while Token.Kind = lexerKindFrom do transpile_import(AContext, ALexer); Token := lexer_current(ALexer) end; WriteLn() end; proc transpile_constant(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' '); Token := lexer_current(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); WriteString(' = '); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); write_semicolon() end; proc transpile_constant_part(AContext: PTranspilerContext; ALexer: PLexer): BOOLEAN; var Token: LexerToken; Result: BOOLEAN; begin Token := lexer_current(ALexer); Result := Token.Kind = lexerKindConst; if Result then WriteString('CONST'); WriteLn(); Token := transpiler_lex(ALexer); while Token.Kind = lexerKindIdentifier do transpile_constant(AContext, ALexer); Token := transpiler_lex(ALexer) end end; return Result end; proc transpile_module(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := transpiler_lex(ALexer); if Token.Kind = lexerKindDefinition then WriteString('DEFINITION '); Token := transpiler_lex(ALexer) end; if Token.Kind = lexerKindImplementation then WriteString('IMPLEMENTATION '); Token := transpiler_lex(ALexer) end; WriteString('MODULE '); (* Write the module name and end the line with a semicolon and newline. *) Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); write_semicolon(); WriteLn(); (* Write the module body. *) Token := transpiler_lex(ALexer); transpile_import_part(AContext, ALexer); if transpile_constant_part(AContext, ALexer) then WriteLn() end; transpile_type_part(AContext, ALexer); if transpile_variable_part(AContext, ALexer) then WriteLn() end; transpile_procedure_part(AContext, ALexer); transpile_statement_part(AContext, ALexer); WriteString('END '); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); Write('.'); Token := transpiler_lex(ALexer); WriteLn() end; proc transpile_type_fields(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := transpiler_lex(ALexer); while Token.Kind <> lexerKindEnd do WriteString(' '); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); WriteString(': '); transpile_type_expression(AContext, ALexer); Token := transpiler_lex(ALexer); if Token.Kind = lexerKindSemicolon then Token := transpiler_lex(ALexer); Write(';') end; WriteLn() end end; proc transpile_record_type(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin WriteString('RECORD'); WriteLn(); transpile_type_fields(AContext, ALexer); WriteString(' END') end; proc transpile_pointer_type(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := lexer_current(ALexer); WriteString('POINTER TO '); if Token.Kind = lexerKindPointer then Token := transpiler_lex(ALexer) end; transpile_type_expression(AContext, ALexer) end; proc transpile_array_type(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString('ARRAY'); Token := lexer_current(ALexer); if Token.Kind = lexerKindArray then Token := transpiler_lex(ALexer) end; if Token.Kind <> lexerKindOf then WriteString('[1..'); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); Write(']') end; WriteString(' OF '); transpile_type_expression(AContext, ALexer) end; proc transpile_enumeration_type(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString('('); WriteLn(); WriteString(' '); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); while Token.Kind = lexerKindComma do Write(','); WriteLn(); WriteString(' '); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer) end; WriteLn(); WriteString(' )') end; proc transpile_union_type(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; end; proc transpile_procedure_type(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := transpiler_lex(ALexer); WriteString('PROCEDURE('); Token := transpiler_lex(ALexer); while Token.Kind <> lexerKindRightParen do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); if Token.Kind = lexerKindComma then Token := transpiler_lex(ALexer); WriteString(', ') end end; Write(')') end; proc transpile_type_expression(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := transpiler_lex(ALexer); if Token.Kind = lexerKindRecord then transpile_record_type(AContext, ALexer) end; if Token.Kind = lexerKindLeftParen then transpile_enumeration_type(AContext, ALexer) end; if (Token.Kind = lexerKindArray) OR (Token.Kind = lexerKindLeftSquare) then transpile_array_type(AContext, ALexer) end; if Token.Kind = lexerKindHat then transpile_pointer_type(AContext, ALexer) end; if Token.Kind = lexerKindProc then transpile_procedure_type(AContext, ALexer) end; if Token.Kind = lexerKindIdentifier then WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start) end end; proc transpile_type_declaration(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' '); Token := lexer_current(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); WriteString(' = '); transpile_type_expression(AContext, ALexer); Token := transpiler_lex(ALexer); write_semicolon(); end; proc transpile_type_part(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin Token := lexer_current(ALexer); if Token.Kind = lexerKindType then WriteString('TYPE'); WriteLn(); Token := transpiler_lex(ALexer); while Token.Kind = lexerKindIdentifier do transpile_type_declaration(AContext, ALexer); Token := transpiler_lex(ALexer) end; WriteLn() end end; proc transpile_variable_declaration(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' '); Token := lexer_current(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); WriteString(': '); transpile_type_expression(AContext, ALexer); Token := transpiler_lex(ALexer); write_semicolon() end; proc transpile_variable_part(AContext: PTranspilerContext; ALexer: PLexer): BOOLEAN; var Token: LexerToken; Result: BOOLEAN; begin Token := lexer_current(ALexer); Result := Token.Kind = lexerKindVar; if Result then WriteString('VAR'); WriteLn(); Token := transpiler_lex(ALexer); while Token.Kind = lexerKindIdentifier do transpile_variable_declaration(AContext, ALexer); Token := transpiler_lex(ALexer) end end; return Result end; proc transpile_procedure_heading(AContext: PTranspilerContext; ALexer: PLexer): LexerToken; var Token: LexerToken; Result: LexerToken; WrittenBytes: CARDINAL; begin WriteString('PROCEDURE '); Result := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); Write('('); Token := transpiler_lex(ALexer); while Token.Kind <> lexerKindRightParen do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); WriteString(': '); transpile_type_expression(AContext, ALexer); Token := transpiler_lex(ALexer); if Token.Kind = lexerKindSemicolon then WriteString('; '); Token := transpiler_lex(ALexer) end end; WriteString(')'); Token := transpiler_lex(ALexer); (* Check for the return type and write it. *) if Token.Kind = lexerKindColon then WriteString(': '); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer) end; Token := transpiler_lex(ALexer); write_semicolon(); return Result end; proc transpile_expression(AContext: PTranspilerContext; ALexer: PLexer; TrailingToken: LexerKind); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := transpiler_lex(ALexer); while (Token.Kind <> TrailingToken) AND (Token.Kind <> lexerKindEnd) do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Write(' '); Token := transpiler_lex(ALexer) end end; proc transpile_if_statement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' IF '); transpile_expression(AContext, ALexer, lexerKindThen); WriteString('THEN'); WriteLn(); transpile_statements(AContext, ALexer); WriteString(' END'); Token := transpiler_lex(ALexer) end; proc transpile_while_statement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' WHILE '); transpile_expression(AContext, ALexer, lexerKindDo); WriteString('DO'); WriteLn(); transpile_statements(AContext, ALexer); WriteString(' END'); Token := transpiler_lex(ALexer) end; proc transpile_assignment_statement(AContext: PTranspilerContext; ALexer: PLexer); begin WriteString(' := '); transpile_expression(AContext, ALexer, lexerKindSemicolon); end; proc transpile_call_statement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString('('); Token := transpiler_lex(ALexer); while (Token.Kind <> lexerKindSemicolon) AND (Token.Kind <> lexerKindEnd) do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer) end end; proc transpile_return_statement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' RETURN '); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer) end; proc transpile_statement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := transpiler_lex(ALexer); if Token.Kind = lexerKindIf then transpile_if_statement(AContext, ALexer) end; if Token.Kind = lexerKindWhile then transpile_while_statement(AContext, ALexer) end; if Token.Kind = lexerKindReturn then transpile_return_statement(AContext, ALexer) end; if Token.Kind = lexerKindIdentifier then WriteString(' '); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); while Token.Kind = lexerKindLeftSquare do Write('['); Token := transpiler_lex(ALexer); while Token.Kind <> lexerKindRightSquare do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer) end; Write(']'); Token := transpiler_lex(ALexer); end; if Token.Kind = lexerKindHat then Write('^'); Token := transpiler_lex(ALexer) end; if Token.Kind = lexerKindDot then Write('.'); Token := transpiler_lex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer); end; if Token.Kind = lexerKindHat then Write('^'); Token := transpiler_lex(ALexer) end; while Token.Kind = lexerKindLeftSquare do Write('['); Token := transpiler_lex(ALexer); while Token.Kind <> lexerKindRightSquare do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := transpiler_lex(ALexer) end; Write(']'); Token := transpiler_lex(ALexer); end; if Token.Kind = lexerKindAssignment then transpile_assignment_statement(AContext, ALexer) end; if Token.Kind = lexerKindLeftParen then transpile_call_statement(AContext, ALexer) end end end; proc transpile_statements(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin Token := lexer_current(ALexer); while Token.Kind <> lexerKindEnd do transpile_statement(AContext, ALexer); Token := lexer_current(ALexer); if Token.Kind = lexerKindSemicolon then Write(';') end; WriteLn() end end; proc transpile_statement_part(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin Token := lexer_current(ALexer); if Token.Kind = lexerKindBegin then WriteString('BEGIN'); WriteLn(); transpile_statements(AContext, ALexer) end end; proc transpile_procedure_declaration(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; SeenPart: BOOLEAN; WrittenBytes: CARDINAL; begin Token := transpile_procedure_heading(AContext, ALexer); SeenPart := transpile_constant_part(AContext, ALexer); SeenPart := transpile_variable_part(AContext, ALexer); transpile_statement_part(AContext, ALexer); WriteString('END '); WrittenBytes := WriteNBytes(StdOut, ORD(Token.identifierKind[1]), ADR(Token.identifierKind[2])); Token := transpiler_lex(ALexer); write_semicolon(); Token := transpiler_lex(ALexer) end; proc transpile_procedure_part(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin Token := lexer_current(ALexer); while Token.Kind = lexerKindProc do transpile_procedure_declaration(AContext, ALexer); Token := lexer_current(ALexer); WriteLn() end end; proc transpile(ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; Context: TranspilerContext; begin transpile_module(ADR(Context), ALexer) end; end Transpiler.