IMPLEMENTATION MODULE Transpiler; FROM FIO IMPORT WriteNBytes, StdOut; FROM SYSTEM IMPORT ADR, ADDRESS; FROM Terminal IMPORT Write, WriteLn, WriteString; FROM Lexer IMPORT Lexer, LexerToken, LexerCurrent, LexerLex, LexerKind; TYPE TranspilerContext = RECORD END; PTranspilerContext = POINTER TO TranspilerContext; (* Calls LexerLex() but skips the comments. *) PROCEDURE TranspilerLex(ALexer: PLexer): LexerToken; VAR Result: LexerToken; BEGIN Result := LexerLex(ALexer); WHILE Result.Kind = lexerKindComment DO Result := LexerLex(ALexer) END; RETURN Result END TranspilerLex; (* Write a semicolon followed by a newline. *) PROCEDURE WriteSemicolon(); BEGIN WriteString(';'); WriteLn() END WriteSemicolon; PROCEDURE TranspileImport(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; BEGIN WriteString('FROM '); Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); WriteString(' IMPORT '); Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); WHILE Token.Kind <> lexerKindSemicolon DO WriteString(', '); Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer) END; WriteSemicolon(); Token := TranspilerLex(ALexer) END TranspileImport; PROCEDURE TranspileImportPart(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; BEGIN Token := LexerCurrent(ALexer); WHILE Token.Kind = lexerKindFrom DO TranspileImport(AContext, ALexer); Token := LexerCurrent(ALexer) END; WriteLn() END TranspileImportPart; PROCEDURE TranspileConstant(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; BEGIN WriteString(' '); Token := LexerCurrent(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); WriteString(' = '); Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); WriteSemicolon() END TranspileConstant; PROCEDURE TranspileConstantPart(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; BEGIN Token := LexerCurrent(ALexer); IF Token.Kind = lexerKindConst THEN WriteString('CONST'); WriteLn(); Token := TranspilerLex(ALexer); WHILE Token.Kind = lexerKindIdentifier DO TranspileConstant(AContext, ALexer); Token := TranspilerLex(ALexer) END; WriteLn() END END TranspileConstantPart; PROCEDURE TranspileModule(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; BEGIN Token := TranspilerLex(ALexer); IF Token.Kind = lexerKindDefinition THEN WriteString('DEFINITION '); Token := TranspilerLex(ALexer); ELSIF Token.Kind = lexerKindImplementation THEN WriteString('IMPLEMENTATION '); Token := TranspilerLex(ALexer) END; WriteString('MODULE '); (* Write the module name and end the line with a semicolon and newline. *) Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); WriteSemicolon(); WriteLn(); (* Write the module body. *) Token := TranspilerLex(ALexer); TranspileImportPart(AContext, ALexer); TranspileConstantPart(AContext, ALexer); Token := LexerCurrent(ALexer); WHILE Token.Kind <> lexerKindEof DO WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); WriteLn(); Token := TranspilerLex(ALexer) END END TranspileModule; PROCEDURE Transpile(ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; Context: TranspilerContext; BEGIN TranspileModule(ADR(Context), ALexer) END Transpile; END Transpiler.