-- file Interface.Mesa -- last modified by Sandman, Jan 15, 1980 2:07 PM DIRECTORY AltoDisplay: FROM "altodisplay" USING [DCB, DCBHandle, DCBchainHead, MaxBitsPerLine, MaxScanLines], AltoFileDefs: FROM "altofiledefs" USING [FP], CharIO: FROM "chario" USING [ CR, NumberFormat, PutChar, PutDecimal, PutLine, PutNumber, PutString], CompilerOps: FROM "compilerops" USING [TableId, Transaction, Compile, NoSource, Punt, Sequencer], DirectoryDefs: FROM "directorydefs" USING [EnumerateDirectory], ImageDefs: FROM "imagedefs" USING [ CleanupItem, CleanupMask, CleanupProcedure, FileRequest, AddCleanupProcedure, AddFileRequest, AbortMesa, ImageTime, RunImage, StopMesa], InlineDefs: FROM "inlinedefs" USING [DIVMOD], KeyDefs: FROM "keydefs" USING [Keys, KeyBits], MiscDefs: FROM "miscdefs" USING [CallDebugger, CommandLineCFA], OsStaticDefs: FROM "osstaticdefs" USING [OsStatics], SDDefs: FROM "sddefs" USING [sAddFileRequest, SD], SegmentDefs: FROM "segmentdefs" USING [ FileHandle, FileSegmentHandle, DefaultVersion, DestroyFile, InsertFile, LockFile, NewFile, NewFileSegment, UnlockFile], StreamDefs: FROM "streamdefs" USING [ StreamHandle, StreamObject, Append, Read, Write, CloseDiskStream, CreateByteStream, JumpToFA, OpenDiskStream], StringDefs: FROM "stringdefs" USING [ AppendChar, AppendString, EquivalentString, MesaToBcplString, WordsForBcplString], SystemDefs: FROM "systemdefs" USING [ AllocateHeapNode, AllocateHeapString, FreeHeapString, FreeHeapNode], TimeDefs: FROM "timedefs" USING [DefaultTime, AppendDayTime, UnpackDT]; Interface: PROGRAM [ explicitSwapping: BOOLEAN, tableSegment: ARRAY CompilerOps.TableId OF SegmentDefs.FileSegmentHandle] IMPORTS CharIO, CompilerOps, DirectoryDefs, ImageDefs, InlineDefs, MiscDefs, SegmentDefs, StreamDefs, StringDefs, SystemDefs, TimeDefs EXPORTS CompilerOps = BEGIN OPEN StreamDefs; -- command line input control commandStream: StreamHandle; comCmRequest: ImageDefs.FileRequest ← [ name: "Com.Cm.", file: NIL, access: Read, link: ]; SetCommandInput: PROCEDURE = BEGIN c: CHARACTER; commandStream ← CreateByteStream[comCmRequest.file, Read]; IF ~image THEN JumpToFA[commandStream, @(MiscDefs.CommandLineCFA[]).fa] ELSE BEGIN [] ← SkipStreamBlanks[]; UNTIL commandStream.endof[commandStream] OR (c←commandStream.get[commandStream]) = ' OR c = CharIO.CR DO NULL ENDLOOP; END; END; SkipStreamBlanks: PROCEDURE RETURNS [c: CHARACTER] = BEGIN OPEN CharIO; UNTIL commandStream.endof[commandStream] DO c ← commandStream.get[commandStream]; IF c # ' AND c # CR THEN EXIT; ENDLOOP; END; CommandLineID: PROCEDURE [s: STRING] = BEGIN OPEN CharIO; c: CHARACTER; s.length ← 0; c ← SkipStreamBlanks[]; UNTIL commandStream.endof[commandStream] OR c = ' OR c = CR DO StringDefs.AppendChar[s, c]; c ← commandStream.get[commandStream]; ENDLOOP; END; -- special output stream control log: StreamHandle; logName: STRING = "Compiler.Log."; logRequest: ImageDefs.FileRequest ← [ name: logName, file: NIL, access: Write+Append, link: ]; SetTypescript: PROCEDURE = BEGIN OPEN SegmentDefs; IF logRequest.file = NIL THEN logRequest.file ← NewFile[logName, Write+Append, DefaultVersion]; log ← CreateByteStream[logRequest.file, Write+Append]; END; NewLine: PROCEDURE = BEGIN CharIO.PutChar[log, CharIO.CR] END; errorStream: StreamHandle; ErrorPut: PROCEDURE [s: StreamHandle, c: CHARACTER] = BEGIN OPEN SegmentDefs; errorName: STRING; IF errorStream = NIL THEN BEGIN errorName ← SystemDefs.AllocateHeapString[rootName.length + (".errlog"L).length]; StringDefs.AppendString[errorName, rootName]; StringDefs.AppendString[errorName, ".errlog"L]; errorStream ← CreateByteStream[ IF errorFile=NIL THEN SegmentDefs.NewFile[errorName, Write+Append, SegmentDefs.DefaultVersion] ELSE errorFile, Write+Append]; WriteHerald[errorStream, errorName]; errorStream.put[errorStream, CharIO.CR]; SystemDefs.FreeHeapString[errorName]; END; errorStream.put[errorStream, c]; END; ErrorDestroy: PROCEDURE [s: StreamHandle] = BEGIN SELECT TRUE FROM errorStream # NIL => errorStream.destroy[errorStream]; errorFile # NIL => SegmentDefs.DestroyFile[errorFile]; ENDCASE; SystemDefs.FreeHeapNode[s]; END; WriteHerald: PROCEDURE [s: StreamHandle, id: STRING] = BEGIN OPEN TimeDefs, CharIO; time: STRING ← [20]; PutString [s, "Alto/Mesa Compiler 6.0c of "L]; time.length ← 0; AppendDayTime[time, UnpackDT[ImageDefs.ImageTime[]]]; PutLine[s, time]; IF id # NIL THEN BEGIN PutString[s, id]; PutString[s, " -- "L] END; time.length ← 0; AppendDayTime[time, UnpackDT[DefaultTime]]; PutLine[s, time]; END; WriteTime: PROCEDURE [sec: CARDINAL] = BEGIN OPEN CharIO; hr, min: CARDINAL; f: NumberFormat ← [base:10, unsigned:TRUE, zerofill:FALSE, columns:1]; W: PROCEDURE [t: CARDINAL] = BEGIN IF t # 0 OR f.zerofill THEN BEGIN PutNumber[log, t, f]; PutChar[log, ':]; f ← [base:10, unsigned:TRUE, zerofill:TRUE, columns:2]; END; END; [min, sec] ← InlineDefs.DIVMOD[sec, 60]; [hr, min] ← InlineDefs.DIVMOD[min, 60]; W[hr]; W[min]; PutNumber[log, sec, f]; END; -- cleanup of files/streams compilerCleanupItem: ImageDefs.CleanupItem ← [ proc: CompilerCleanup, mask: ImageDefs.CleanupMask[InLd] + ImageDefs.CleanupMask[OutLd], link: ]; CompilerCleanup: ImageDefs.CleanupProcedure = BEGIN SELECT why FROM OutLd => IF errorStream # NIL THEN CloseDiskStream[errorStream]; InLd => IF errorStream # NIL THEN OpenDiskStream[errorStream]; ENDCASE; END; -- table storage management tableRequest: ImageDefs.FileRequest ← [ name: "Swatee.", file: NIL, access: Read+Write+Append, link: ]; -- compiler sequencing Initialize: PROCEDURE = BEGIN IF log # NIL THEN CloseDiskStream[log]; IF commandStream # NIL THEN CloseDiskStream[commandStream]; moduleStartTime ← secondsClock.low; END; Finalize: PROCEDURE = BEGIN SELECT TRUE FROM parms.nErrors = 0 => IF parms.object.stream # NIL THEN parms.object.stream.destroy[parms.object.stream]; ENDCASE => BEGIN IF parms.object.stream # NIL THEN BEGIN objectFile ← WITH s: parms.object.stream SELECT FROM Disk => objectFile ← s.file, ENDCASE => ERROR; SegmentDefs.LockFile[objectFile]; parms.object.stream.destroy[parms.object.stream]; SegmentDefs.UnlockFile[objectFile]; END; IF objectFile # NIL THEN BEGIN IF oldObjectFile THEN SegmentDefs.UnlockFile[objectFile]; SegmentDefs.DestroyFile[objectFile]; END; END; IF parms.source.stream # NIL THEN parms.source.stream.destroy[parms.source.stream]; IF parms.error.stream # NIL THEN parms.error.stream.destroy[parms.error.stream]; IF commandStream # NIL THEN OpenDiskStream[commandStream]; IF log # NIL THEN OpenDiskStream[log]; END; WriteClosing: PROCEDURE = BEGIN OPEN CharIO; IF (cursorLoc.y ← cursorLoc.y+16) > AltoDisplay.MaxScanLines-64 THEN cursorLoc.y ← 64; PutString[log, sourceName]; PutString[log, " -- "L]; IF parms.nErrors # 0 THEN BEGIN cursorLoc.x ← MIN[AltoDisplay.MaxBitsPerLine-64, cursorLoc.x+16]; errors ← TRUE; PutString[log, "aborted, "L]; PutDecimal[log, parms.nErrors]; PutString[log, " errors "L]; IF parms.nWarnings # 0 THEN BEGIN warnings ← TRUE; PutString[log, "and "L]; PutDecimal[log, parms.nWarnings]; PutString[log, " warnings "L]; END; PutString[log, "on "L]; PutString[log, rootName]; PutString[log, ".errlog"L]; END ELSE BEGIN PutString[log, "source tokens: "L]; PutNumber[log, parms.sourceTokens, [base:10,zerofill:FALSE,unsigned:TRUE,columns:1]]; PutString[log, ", time: "L]; WriteTime[secondsClock.low-moduleStartTime]; IF parms.objectBytes # 0 THEN BEGIN NewLine[]; PutString[log, " code bytes: "L]; PutDecimal[log, parms.objectBytes]; PutString[log, ", links: "L]; PutDecimal[log, parms.linkCount]; PutString[log, ", frame size: "L]; PutDecimal[log, parms.objectFrameSize]; END; IF parms.nWarnings # 0 THEN BEGIN warnings ← TRUE; NewLine[]; PutDecimal[log, parms.nWarnings]; PutString[log, " warnings on "L]; PutString[log, rootName]; PutString[log, ".errlog"L]; END; END; END; StopCompiler: PROCEDURE = BEGIN IF moduleCount > 1 THEN BEGIN OPEN CharIO; NewLine[]; PutString[log, "Total elapsed time: "L]; WriteTime[secondsClock.low-compilerStartTime]; NewLine[]; END; log.destroy[log]; IF (errors OR warnings) AND SwitchDefaults['p] THEN BEGIN CursorBits: TYPE = ARRAY [0..16) OF WORD; Cursor: POINTER TO CursorBits = LOOPHOLE[431B]; BlankCursor: CursorBits = ALL[0]; QueryCursor: CursorBits = [2000B, 74000B, 140000B, 12767B, 12525B, 53566B, 111113B, 163100B, 0B, 0B, 154000B, 53520B, 62520B, 53360B, 155440B, 140B]; savedCursor: CursorBits = Cursor↑; KeyBits: TYPE = ARRAY [0..SIZE[KeyDefs.KeyBits]-1) OF WORD; Keys: POINTER TO KeyBits = LOOPHOLE[KeyDefs.Keys+1]; savedKeys: KeyBits = Keys↑; RTC: POINTER TO MACHINE DEPENDENT RECORD [high: [0..4096), low: [0..16)] = LOOPHOLE[430B]; savedTime: CARDINAL; state: {off, on1, on2}; Cursor↑ ← BlankCursor; state ← off; savedTime ← RTC.high; DO IF RTC.high # savedTime THEN BEGIN SELECT state FROM off => BEGIN Cursor↑ ← QueryCursor; state ← on1 END; on1 => state ← on2; on2 => BEGIN Cursor↑ ← BlankCursor; state ← off END; ENDCASE; savedTime ← RTC.high; END; IF Keys↑ # savedKeys THEN EXIT; ENDLOOP; Cursor↑ ← savedCursor; END; END; transaction: CompilerOps.Transaction; parms: POINTER TO CompilerOps.Transaction = @transaction; SwitchDefaults: PACKED ARRAY CHARACTER ['a..'z] OF BOOLEAN ← [ --a/k/u b/l/v c/m/w d/n/x e/o/y f/p/z g/q h/r i/s j/t -- TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE]; sourceName: STRING ← [40]; objectName: STRING ← [40]; rootName: STRING ← [40]; sourceFile: SegmentDefs.FileHandle; errorFile: SegmentDefs.FileHandle; objectFile: SegmentDefs.FileHandle; oldObjectFile: BOOLEAN; FindFiles: PROCEDURE [fp: POINTER TO AltoFileDefs.FP, s: STRING] RETURNS [BOOLEAN] = BEGIN IF s.length = sourceName.length AND StringDefs.EquivalentString[sourceName, s] THEN sourceFile ← SegmentDefs.InsertFile[fp, Read]; IF s.length = objectName.length AND StringDefs.EquivalentString[objectName, s] THEN BEGIN objectFile ← SegmentDefs.InsertFile[fp, Write+Append]; SegmentDefs.LockFile[objectFile]; oldObjectFile ← TRUE; END; IF s.length = rootName.length + (".errlog."L).length THEN BEGIN errorName: STRING ← [40]; StringDefs.AppendString[errorName, rootName]; StringDefs.AppendString[errorName, ".errlog."L]; IF StringDefs.EquivalentString[errorName, s] THEN errorFile ← SegmentDefs.InsertFile[fp, Write+Append]; END; RETURN [sourceFile # NIL AND errorFile # NIL AND objectFile # NIL] END; errors, warnings: BOOLEAN; moduleCount: CARDINAL; compilerStartTime, moduleStartTime: CARDINAL; secondsClock: POINTER TO MACHINE DEPENDENT RECORD [high, low: CARDINAL] = LOOPHOLE[572B]; -- * * * * * * M A I N B O D Y C O D E * * * * * * image: BOOLEAN = (SDDefs.SD[SDDefs.sAddFileRequest] # 0); dcbSpace: ARRAY [0..SIZE[AltoDisplay.DCB]+1) OF UNSPECIFIED; dcb, saveDCB: AltoDisplay.DCBHandle; CursorXY: TYPE = MACHINE DEPENDENT RECORD [x,y: CARDINAL]; cursorLoc: POINTER TO CursorXY = LOOPHOLE[426B]; saveCursorXY: CursorXY; -- add cleanup procedure ImageDefs.AddCleanupProcedure[@compilerCleanupItem]; IF image THEN BEGIN ImageDefs.AddFileRequest[@comCmRequest]; ImageDefs.AddFileRequest[@logRequest]; ImageDefs.AddFileRequest[@tableRequest]; STOP; -- wait for restart END ELSE BEGIN fp: AltoFileDefs.FP ← MiscDefs.CommandLineCFA[].fp; comCmRequest.file ← SegmentDefs.InsertFile[@fp, Read]; END; dcb ← @dcbSpace[0]; IF LOOPHOLE[dcb, CARDINAL] MOD 2 # 0 THEN dcb ← dcb + 1; dcb↑ ← AltoDisplay.DCB[NIL, high, black, 0, 0, NIL, 0]; saveDCB ← AltoDisplay.DCBchainHead↑; AltoDisplay.DCBchainHead↑ ← dcb; saveCursorXY ← cursorLoc↑; cursorLoc↑ ← [64,64]; errorStream ← NIL; IF tableRequest.file = NIL THEN tableRequest.file ← SegmentDefs.NewFile[ "Swatee.", Read+Write+Append, SegmentDefs.DefaultVersion]; START CompilerOps.Sequencer[ explicitSwapping, tableRequest.file, tableSegment]; compilerStartTime ← secondsClock.low; moduleCount ← 0; -- do the compilation SetCommandInput[]; SetTypescript[]; WriteHerald[log, NIL]; errors ← warnings ← FALSE; DO OPEN CharIO; BEGIN i, sourceLength: CARDINAL; c: CHARACTER; sense, sourceExtension: BOOLEAN; CompleteFileName: PROCEDURE RETURNS [fileName: STRING, bcpl: BOOLEAN] = BEGIN OPEN StringDefs; j: CARDINAL; extension: STRING ← [40]; fileName ← SystemDefs.AllocateHeapString[40]; AppendString[fileName, rootName]; IF ~sourceExtension THEN AppendString[extension, "image"L] ELSE FOR j IN [rootName.length+1 .. sourceLength) DO AppendChar[extension, sourceName[j]] ENDLOOP; bcpl ← EquivalentString[extension, "run"L]; AppendChar[fileName, '.]; AppendString[fileName, extension]; RETURN END; WriteCommandFile: PROCEDURE [fileName: STRING] = BEGIN j: CARDINAL; copy: StreamHandle; copy ← CreateByteStream[ SegmentDefs.NewFile[ "com.cm."L, Write+Append, SegmentDefs.DefaultVersion], Write+Append]; FOR j IN [0..fileName.length) DO copy.put[copy, fileName[j]] ENDLOOP; IF sourceName.length > i+1 THEN BEGIN copy.put[copy, '/]; FOR j IN (i..sourceName.length) DO copy.put[copy, sourceName[j]] ENDLOOP; END; IF commandStream = NIL OR commandStream.endof[commandStream] THEN copy.put[copy, CR] ELSE BEGIN copy.put[copy, ' ]; UNTIL commandStream.endof[commandStream] DO copy.put[copy, commandStream.get[commandStream]] ENDLOOP; END; IF commandStream # NIL THEN commandStream.destroy[commandStream]; copy.destroy[copy]; RETURN END; Run: PROCEDURE [fileName: STRING, bcpl: BOOLEAN] = BEGIN IF bcpl THEN BEGIN p: POINTER = OsStaticDefs.OsStatics.EventVector; EVItem: TYPE = MACHINE DEPENDENT RECORD [ type: [0..7777B], length: [0..17B]]; p↑ ← EVItem[6, StringDefs.WordsForBcplString[fileName.length]+1]; StringDefs.MesaToBcplString[fileName, p+1]; ImageDefs.StopMesa[]; END ELSE BEGIN OPEN SegmentDefs; ImageDefs.RunImage[NewFileSegment[ file: NewFile[fileName, Read, DefaultVersion], base: 1, pages: 1, access: Read]]; END; END; parms.switches ← SwitchDefaults; parms.switches['p] ← FALSE; parms.debugPass ← LAST[CARDINAL]; CommandLineID[sourceName]; IF sourceName.length = 0 THEN EXIT; NewLine[]; PutString[log, "Compile: "]; PutString[log, sourceName]; IF sourceName[0] = 04C THEN GO TO debugger; -- ↑D => debug rootName.length ← 0; sourceExtension ← FALSE; FOR i IN [0..sourceName.length) DO c ← sourceName[i]; SELECT c FROM '. => sourceExtension ← TRUE; '/ => GO TO Switches; ENDCASE; IF ~sourceExtension THEN StringDefs.AppendChar[rootName, c]; REPEAT Switches => BEGIN sourceLength ← i; i ← i+1; sense ← TRUE; WHILE i < sourceName.length DO SELECT (c ← sourceName[i]) FROM '-, '~ => sense ← ~sense; 'r, 'R => BEGIN fileName: STRING; bcpl: BOOLEAN; [fileName, bcpl] ← CompleteFileName[]; WriteCommandFile[fileName]; StopCompiler[]; Run[fileName, bcpl ! ANY => ImageDefs.AbortMesa]; -- never returns END; 'c, 'C => BEGIN sense ← TRUE; FOR i IN [0..sourceLength) DO SELECT (c ← sourceName[i]) FROM '-, '~ => sense ← ~sense; IN ['a..'z] => BEGIN SwitchDefaults[c] ← sense; EXIT END; IN ['A..'Z] => BEGIN SwitchDefaults[c+('a-'A)] ← sense; EXIT END; ENDCASE => EXIT; ENDLOOP; GO TO skip END; IN ['a..'z] => BEGIN parms.switches[c] ← sense; sense ← TRUE END; IN ['A..'Z] => BEGIN parms.switches[c+('a-'A)] ← sense; sense ← TRUE END; IN ['1..'5] => BEGIN parms.debugPass ← c-'0; sense ← TRUE END; ENDCASE; i ← i+1; ENDLOOP; END; FINISHED => sourceLength ← sourceName.length; ENDLOOP; NewLine[]; sourceName.length ← sourceLength; IF ~sourceExtension THEN StringDefs.AppendString[sourceName, ".mesa"]; IF sourceName[sourceName.length-1] # '. THEN StringDefs.AppendChar[sourceName, '.]; parms.source ← [name: sourceName, stream: NIL]; parms.error.name ← NIL; errorStream ← NIL; parms.error.stream ← SystemDefs.AllocateHeapNode[SIZE[Other StreamObject]]; parms.error.stream↑ ← [NULL, NULL, NULL, ErrorPut, NULL, ErrorDestroy, NIL, Other[,]]; objectName.length ← 0; StringDefs.AppendString[objectName, rootName]; StringDefs.AppendString[objectName, ".bcd."]; parms.object ← [name: objectName, stream: NIL]; BEGIN OPEN SegmentDefs; ENABLE ANY => CONTINUE; sourceFile ← errorFile ← objectFile ← NIL; oldObjectFile ← FALSE; DirectoryDefs.EnumerateDirectory[FindFiles]; IF sourceFile # NIL THEN parms.source.stream ← CreateByteStream[sourceFile, Read]; END; moduleCount ← moduleCount + 1; Initialize[]; CompilerOps.Compile[parms ! CompilerOps.NoSource => GO TO noSource; CompilerOps.Punt => GO TO punt]; Finalize[]; WriteClosing[]; EXITS skip => NULL; noSource => BEGIN Finalize[]; errors ← TRUE; PutString[log, sourceName]; PutString[log, " -- File error"]; END; debugger => MiscDefs.CallDebugger[NIL]; END; NewLine[]; IF (errors OR warnings) AND parms.switches['p] THEN GO TO truncateList; REPEAT truncateList => SwitchDefaults['p] ← TRUE; punt => BEGIN Finalize[]; WriteClosing[]; NewLine[] END; ENDLOOP; StopCompiler[]; cursorLoc↑ ← saveCursorXY; AltoDisplay.DCBchainHead↑ ← saveDCB; ImageDefs.StopMesa[]; END.