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