-- 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.