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 PTranspilerContext = pointer to TranspilerContext; TranspilerContext = record Indentation: CARDINAL end; (* 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); TranspileTypePart(AContext, ALexer); TranspileVariablePart(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 TranspileTypeFields(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; BEGIN Token := TranspilerLex(ALexer); WHILE Token.Kind <> lexerKindEnd DO WriteString(' '); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); WriteString(': '); TranspileTypeExpression(AContext, ALexer); Token := TranspilerLex(ALexer); IF Token.Kind = lexerKindSemicolon THEN Token := TranspilerLex(ALexer); WriteSemicolon() ELSE WriteLn() END END END TranspileTypeFields; PROCEDURE TranspileRecordType(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; BEGIN WriteString('RECORD'); WriteLn(); TranspileTypeFields(AContext, ALexer); WriteString(' END') END TranspileRecordType; PROCEDURE TranspilePointerType(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; BEGIN WriteString('POINTER TO '); Token := TranspilerLex(ALexer); TranspileTypeExpression(AContext, ALexer) END TranspilePointerType; PROCEDURE TranspileArrayType(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; BEGIN WriteString('ARRAY'); Token := TranspilerLex(ALexer); IF Token.Kind <> lexerKindOf THEN Write('['); Token := TranspilerLex(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); Write(']'); Token := TranspilerLex(ALexer) END; WriteString(' OF '); TranspileTypeExpression(AContext, ALexer) END TranspileArrayType; PROCEDURE TranspileEnumerationType(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; BEGIN WriteString('('); WriteLn(); WriteString(' '); Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); WHILE Token.Kind = lexerKindComma DO Write(','); WriteLn(); WriteString(' '); Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer) END; WriteLn(); WriteString(' )') END TranspileEnumerationType; PROCEDURE TranspileUnionType(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; END TranspileUnionType; PROCEDURE TranspileProcedureType(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; BEGIN Token := TranspilerLex(ALexer); WriteString('PROCEDURE('); Token := TranspilerLex(ALexer); WHILE Token.Kind <> lexerKindRightParen DO WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); IF Token.Kind = lexerKindComma THEN Token := TranspilerLex(ALexer); WriteString(', ') END END; Write(')') END TranspileProcedureType; PROCEDURE TranspileTypeExpression(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; BEGIN Token := TranspilerLex(ALexer); IF Token.Kind = lexerKindRecord THEN TranspileRecordType(AContext, ALexer) ELSIF Token.Kind = lexerKindLeftParen THEN TranspileEnumerationType(AContext, ALexer) ELSIF Token.Kind = lexerKindArray THEN TranspileArrayType(AContext, ALexer) ELSIF Token.Kind = lexerKindPointer THEN TranspilePointerType(AContext, ALexer) ELSIF Token.Kind = lexerKindProc THEN TranspileProcedureType(AContext, ALexer) ELSE WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start) END END TranspileTypeExpression; PROCEDURE TranspileTypeDeclaration(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(' = '); TranspileTypeExpression(AContext, ALexer); Token := TranspilerLex(ALexer); WriteSemicolon(); END TranspileTypeDeclaration; PROCEDURE TranspileTypePart(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; BEGIN Token := LexerCurrent(ALexer); IF Token.Kind = lexerKindType THEN WriteString('TYPE'); WriteLn(); Token := TranspilerLex(ALexer); WHILE Token.Kind = lexerKindIdentifier DO TranspileTypeDeclaration(AContext, ALexer); Token := TranspilerLex(ALexer) END; WriteLn() END END TranspileTypePart; PROCEDURE TranspileVariableDeclaration(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(': '); TranspileTypeExpression(AContext, ALexer); Token := TranspilerLex(ALexer); WriteSemicolon() END TranspileVariableDeclaration; PROCEDURE TranspileVariablePart(AContext: PTranspilerContext; ALexer: PLexer); VAR Token: LexerToken; BEGIN Token := LexerCurrent(ALexer); IF Token.Kind = lexerKindVar THEN WriteString('VAR'); WriteLn(); Token := TranspilerLex(ALexer); WHILE Token.Kind = lexerKindIdentifier DO TranspileVariableDeclaration(AContext, ALexer); Token := TranspilerLex(ALexer) END; WriteLn() END END TranspileVariablePart; PROCEDURE Transpile(ALexer: PLexer); VAR Token: LexerToken; WrittenBytes: CARDINAL; Context: TranspilerContext; BEGIN TranspileModule(ADR(Context), ALexer) END Transpile; END Transpiler.