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 = ^TranspilerContext; TranspilerContext = record Indentation: CARDINAL end; (* Calls LexerLex() but skips the comments. *) proc TranspilerLex(ALexer: PLexer): LexerToken; var Result: LexerToken; begin Result := LexerLex(ALexer); while Result.Kind = lexerKindComment do Result := LexerLex(ALexer) end; return Result end; (* Write a semicolon followed by a newline. *) proc WriteSemicolon(); begin WriteString(';'); WriteLn() end; proc 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; proc 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; proc 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; proc TranspileConstantPart(AContext: PTranspilerContext; ALexer: PLexer): BOOLEAN; var Token: LexerToken; Result: BOOLEAN; begin Token := LexerCurrent(ALexer); Result := Token.Kind = lexerKindConst; if Result then WriteString('CONST'); WriteLn(); Token := TranspilerLex(ALexer); while Token.Kind = lexerKindIdentifier do TranspileConstant(AContext, ALexer); Token := TranspilerLex(ALexer) end end; return Result end; proc TranspileModule(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := TranspilerLex(ALexer); if Token.Kind = lexerKindDefinition then WriteString('DEFINITION '); Token := TranspilerLex(ALexer) end; if 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); if TranspileConstantPart(AContext, ALexer) then WriteLn() end; TranspileTypePart(AContext, ALexer); if TranspileVariablePart(AContext, ALexer) then WriteLn() end; TranspileProcedurePart(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; proc 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); Write(';') end; WriteLn() end end; proc TranspileRecordType(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin WriteString('RECORD'); WriteLn(); TranspileTypeFields(AContext, ALexer); WriteString(' END') end; proc TranspilePointerType(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := LexerCurrent(ALexer); WriteString('POINTER TO '); if Token.Kind = lexerKindPointer then Token := TranspilerLex(ALexer) end; TranspileTypeExpression(AContext, ALexer) end; proc 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; proc 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; proc TranspileUnionType(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; end; proc 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; proc TranspileTypeExpression(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := TranspilerLex(ALexer); if Token.Kind = lexerKindRecord then TranspileRecordType(AContext, ALexer) end; if Token.Kind = lexerKindLeftParen then TranspileEnumerationType(AContext, ALexer) end; if Token.Kind = lexerKindArray then TranspileArrayType(AContext, ALexer) end; if (Token.Kind = lexerKindPointer) OR (Token.Kind = lexerKindHat) then TranspilePointerType(AContext, ALexer) end; if Token.Kind = lexerKindProc then TranspileProcedureType(AContext, ALexer) end; if Token.Kind = lexerKindIdentifier then WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start) end end; proc 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; proc 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; proc 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; proc TranspileVariablePart(AContext: PTranspilerContext; ALexer: PLexer): BOOLEAN; var Token: LexerToken; Result: BOOLEAN; begin Token := LexerCurrent(ALexer); Result := Token.Kind = lexerKindVar; if Result then WriteString('VAR'); WriteLn(); Token := TranspilerLex(ALexer); while Token.Kind = lexerKindIdentifier do TranspileVariableDeclaration(AContext, ALexer); Token := TranspilerLex(ALexer) end end; return Result end; proc TranspileProcedureHeading(AContext: PTranspilerContext; ALexer: PLexer): LexerToken; var Token: LexerToken; Result: LexerToken; WrittenBytes: CARDINAL; begin WriteString('PROCEDURE '); Result := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); Write('('); Token := TranspilerLex(ALexer); while Token.Kind <> lexerKindRightParen do 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 WriteString('; '); Token := TranspilerLex(ALexer) end end; WriteString(')'); Token := TranspilerLex(ALexer); (* Check for the return type and write it. *) if Token.Kind = lexerKindColon then WriteString(': '); Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer) end; Token := TranspilerLex(ALexer); WriteSemicolon(); return Result end; proc TranspileIfStatement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' IF '); Token := TranspilerLex(ALexer); while Token.Kind <> lexerKindThen do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Write(' '); Token := TranspilerLex(ALexer) end; WriteString('THEN'); WriteLn(); TranspileStatements(AContext, ALexer); WriteString(' END'); Token := TranspilerLex(ALexer) end; proc TranspileWhileStatement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' WHILE '); Token := TranspilerLex(ALexer); while Token.Kind <> lexerKindDo do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Write(' '); Token := TranspilerLex(ALexer) end; WriteString('DO'); WriteLn(); TranspileStatements(AContext, ALexer); WriteString(' END'); Token := TranspilerLex(ALexer) end; proc TranspileAssignmentStatement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' := '); Token := TranspilerLex(ALexer); while (Token.Kind <> lexerKindSemicolon) AND (Token.Kind <> lexerKindEnd) do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Write(' '); Token := TranspilerLex(ALexer) end end; proc TranspileCallStatement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString('('); Token := TranspilerLex(ALexer); while (Token.Kind <> lexerKindSemicolon) AND (Token.Kind <> lexerKindEnd) do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer) end end; proc TranspileReturnStatement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin WriteString(' RETURN '); Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer) end; proc TranspileStatement(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; begin Token := TranspilerLex(ALexer); if Token.Kind = lexerKindIf then TranspileIfStatement(AContext, ALexer) end; if Token.Kind = lexerKindWhile then TranspileWhileStatement(AContext, ALexer) end; if Token.Kind = lexerKindReturn then TranspileReturnStatement(AContext, ALexer) end; if Token.Kind = lexerKindIdentifier then WriteString(' '); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); while Token.Kind = lexerKindLeftSquare do Write('['); Token := TranspilerLex(ALexer); while Token.Kind <> lexerKindRightSquare do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer) end; Write(']'); Token := TranspilerLex(ALexer); end; if Token.Kind = lexerKindHat then Write('^'); Token := TranspilerLex(ALexer) end; if Token.Kind = lexerKindDot then Write('.'); Token := TranspilerLex(ALexer); WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer); end; if Token.Kind = lexerKindHat then Write('^'); Token := TranspilerLex(ALexer) end; while Token.Kind = lexerKindLeftSquare do Write('['); Token := TranspilerLex(ALexer); while Token.Kind <> lexerKindRightSquare do WrittenBytes := WriteNBytes(StdOut, ADDRESS(ALexer^.Current - ALexer^.Start), ALexer^.Start); Token := TranspilerLex(ALexer) end; Write(']'); Token := TranspilerLex(ALexer); end; if Token.Kind = lexerKindAssignment then TranspileAssignmentStatement(AContext, ALexer) end; if Token.Kind = lexerKindLeftParen then TranspileCallStatement(AContext, ALexer) end end end; proc TranspileStatements(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin Token := LexerCurrent(ALexer); while Token.Kind <> lexerKindEnd do TranspileStatement(AContext, ALexer); Token := LexerCurrent(ALexer); if Token.Kind = lexerKindSemicolon then Write(';') end; WriteLn() end end; proc TranspileStatementPart(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin Token := LexerCurrent(ALexer); if Token.Kind = lexerKindBegin then WriteString('BEGIN'); WriteLn(); TranspileStatements(AContext, ALexer) end end; proc TranspileProcedureDeclaration(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; SeenPart: BOOLEAN; WrittenBytes: CARDINAL; begin Token := TranspileProcedureHeading(AContext, ALexer); SeenPart := TranspileConstantPart(AContext, ALexer); SeenPart := TranspileVariablePart(AContext, ALexer); TranspileStatementPart(AContext, ALexer); WriteString('END '); WrittenBytes := WriteNBytes(StdOut, ORD(Token.identifierKind[1]), ADR(Token.identifierKind[2])); Token := TranspilerLex(ALexer); WriteSemicolon(); Token := TranspilerLex(ALexer) end; proc TranspileProcedurePart(AContext: PTranspilerContext; ALexer: PLexer); var Token: LexerToken; begin Token := LexerCurrent(ALexer); while Token.Kind = lexerKindProc do TranspileProcedureDeclaration(AContext, ALexer); Token := LexerCurrent(ALexer); WriteLn() end end; proc Transpile(ALexer: PLexer); var Token: LexerToken; WrittenBytes: CARDINAL; Context: TranspilerContext; begin TranspileModule(ADR(Context), ALexer) end; END Transpiler.