-- file Interface.Mesa
-- last modified by Satterthwaite, April 13, 1981 10:45 AM
-- last modified by Sweet, March 27, 1981 8:50 AM
-- last modified by Karlton, Feb 14, 1981 11:54 AM
DIRECTORY
AltoDisplay: TYPE USING [
CursorBits, Coordinate, DCB, DCBHandle, DCBchainHead,
Cursor, CursorXY, MaxBitsPerLine, MaxScanLines],
CharIO: TYPE USING [
CR, NumberFormat, GetChar, PutChar, PutDecimal, PutLine, PutNumber, PutString],
CommandUtil: TYPE USING [
PairList,
CopyString, Echo, Failed, FreePairList, FreeString, GetNth, ListLength, Parse,
SetExtension, SkipNonBlank],
CompilerOps: TYPE USING [
TableHandle, TableId, StreamId, Transaction, CompileAction, Punt, Sequencer],
CoreSwapDefs: TYPE USING [level],
FrameDefs: TYPE USING [IsBound],
ImageDefs: TYPE USING [
FileRequest, AbortMesa, AddFileRequest, ImageTime, RunImage, StopMesa],
Inline: TYPE USING [DIVMOD],
KeyDefs: TYPE USING [Keys, KeyBits],
MiniDisplay: TYPE USING [Append, Clear, Initialize, Finalize],
MiscDefs: TYPE USING [CallDebugger, CommandLineCFA],
MiscOps: TYPE USING [AllocateDebuggerBitmap, BitmapPages, ReleaseDebuggerBitmap],
OsStaticDefs: TYPE USING [OsStatics],
SDDefs: TYPE USING [sAddFileRequest, SD],
Segments: TYPE USING [
FHandle, FP, FPHandle, SHandle, Read, Write,
DeleteSegment, DestroyFile, EnumerateDirectory, GetFileTimes,
InsertFile, LockFile, NewFile, NewSegment, SetFileTimes, UnlockFile],
Storage: TYPE USING [FreePages, Pages],
StreamDefs: TYPE USING [JumpToFA],
Streams: TYPE USING [
Handle, CreateStream, Destroy, Ended, FileFromStream, GetBlock, GetIndex,
PutChar, PutBlock, Restart, Suspend],
String: TYPE USING [AppendChar, AppendString, EquivalentString],
StringDefs: TYPE USING [MesaToBcplString, WordsForBcplString],
Style: TYPE USING [ItemQueueInit],
Time: TYPE USING [Append, AppendCurrent, Unpack];
Interface: PROGRAM [
explicitSwapping: BOOLEAN,
tableSegment: ARRAY CompilerOps.TableId [parse..debug] OF CompilerOps.TableHandle]
IMPORTS
CharIO, CommandUtil, CompilerOps, CoreSwapDefs, FrameDefs, ImageDefs,
Inline, MiniDisplay, MiscDefs, MiscOps, Segments, Storage, StreamDefs,
Streams, String, StringDefs, Style, Time
EXPORTS CompilerOps, Style =
BEGIN
-- command input
formatting: BOOLEAN = FrameDefs.IsBound[Style.ItemQueueInit];
headerComment: PUBLIC STRING ← NIL;
commandStream: Streams.Handle;
comCmRequest: ImageDefs.FileRequest ← [
name: "Com.Cm.", file: NIL, access: Segments.Read, link: ];
SetCommandInput: PROC = INLINE {
IF comCmRequest.file = NIL
THEN {
comCmRequest.file ← Segments.NewFile[comCmRequest.name, Segments.Read];
Segments.LockFile[comCmRequest.file]};
commandStream ← Streams.CreateStream[comCmRequest.file, Segments.Read];
IF ~image
THEN StreamDefs.JumpToFA[commandStream, @(MiscDefs.CommandLineCFA[]).fa]
ELSE CommandUtil.SkipNonBlank[commandStream]};
-- command logging
log: Streams.Handle;
logName: STRING = IF formatting THEN "Formatter.log." ELSE "Compiler.Log.";
logRequest: ImageDefs.FileRequest ← [
name: logName, file: NIL, access: Segments.Write, link: ];
SetTypescript: PROC = INLINE {
IF logRequest.file = NIL
THEN {
logRequest.file ← Segments.NewFile[logName, Segments.Write];
Segments.LockFile[logRequest.file]};
log ← Streams.CreateStream[logRequest.file, Segments.Write]};
NewLine: PROC = {CharIO.PutChar[log, CharIO.CR]};
WriteHerald: PROC [s: Streams.Handle, id: STRING] = {
OPEN CharIO;
time: STRING ← [20];
PutString[s,
IF formatting THEN "Mesa Formatter 7.0/6.1 of "L
ELSE "Mesa Compiler 6.1 of "L];
time.length ← 0; Time.Append[time, Time.Unpack[ImageDefs.ImageTime[]]];
PutLine[s, time];
IF id # NIL THEN {PutString[s, id]; PutString[s, " -- "L]};
time.length ← 0; Time.AppendCurrent[time];
PutLine[s, time]};
WriteTime: PROC [sec: CARDINAL] = {
OPEN CharIO;
hr, min: CARDINAL;
f: NumberFormat ← [base:10, unsigned:TRUE, zerofill:FALSE, columns:1];
W: PROC [t: CARDINAL] = {
IF t # 0 OR f.zerofill
THEN {
PutNumber[log, t, f]; PutChar[log, ':];
f ← [base:10, unsigned:TRUE, zerofill:TRUE, columns:2]}};
[min, sec] ← Inline.DIVMOD[sec, 60]; [hr, min] ← Inline.DIVMOD[min, 60];
W[hr]; W[min]; PutNumber[log, sec, f]};
-- user feedback
fontSeg: Segments.SHandle;
fontRequest: ImageDefs.FileRequest ← [
name: "sysfont.al", file: NIL, access: Segments.Read, link: ];
-- compiler input and output stream management
sourceName: STRING;
objectName: STRING;
rootName: STRING ← [40];
sourceFile: Segments.FHandle ← NIL;
sourceStream: Streams.Handle ← NIL;
objectFile: Segments.FHandle ← NIL;
objectStream: Streams.Handle ← NIL;
scratchFile: Segments.FHandle ← NIL;
ObjectInit: PROC = INLINE {
IF objectFile = NIL
THEN {
objectFile ← Segments.NewFile[objectName, Segments.Write];
Segments.LockFile[objectFile]};
objectStream ← Streams.CreateStream[objectFile, Segments.Write]};
ObjectReset: PROC [keep: BOOLEAN] = INLINE {
IF keep
THEN {
IF objectFile # NIL THEN Segments.UnlockFile[objectFile];
IF objectStream # NIL THEN Streams.Destroy[objectStream]}
ELSE {
IF objectStream # NIL THEN Streams.Destroy[objectStream];
IF objectFile # NIL THEN {
IF formatting THEN {
sourceFile ← Streams.FileFromStream[sourceStream];
Segments.LockFile[sourceFile];
CopyFile[from: sourceFile, to: objectFile];
Segments.UnlockFile[objectFile];
Segments.UnlockFile[sourceFile]; sourceFile ← NIL}
ELSE {Segments.UnlockFile[objectFile]; Segments.DestroyFile[objectFile]}}};
objectStream ← NIL; objectFile ← NIL};
errorFile: Segments.FHandle ← NIL;
errorStream: Streams.Handle ← NIL;
ErrorInit: PROC = {
errorName: STRING ← CommandUtil.SetExtension[
CommandUtil.CopyString[rootName, 2+("errlog"L).length],
"errlog"L];
IF errorFile = NIL
THEN {
errorFile ← Segments.NewFile[errorName, Segments.Write];
Segments.LockFile[errorFile]};
errorStream ← Streams.CreateStream[errorFile, Segments.Write];
WriteHerald[errorStream, errorName];
CharIO.PutChar[errorStream, CharIO.CR];
errorName ← CommandUtil.FreeString[errorName]};
ErrorReset: PROC = INLINE {
IF errorFile # NIL
THEN {
Segments.UnlockFile[errorFile];
SELECT TRUE FROM
errorStream # NIL => {errorStream.destroy[errorStream]; errorStream ← NIL};
errorFile # NIL => Segments.DestroyFile[errorFile];
ENDCASE;
errorFile ← NIL}};
GetStream: PROC [id: CompilerOps.StreamId] RETURNS [s: Streams.Handle] = {
SELECT id FROM
source => s ← sourceStream;
object => {IF objectStream = NIL THEN ObjectInit[]; s ← objectStream};
log => {IF errorStream = NIL THEN ErrorInit[]; s ← errorStream};
ENDCASE => ERROR;
RETURN};
-- compiler sequencing
Initialize: PROC = {
IF log # NIL THEN Streams.Suspend[log];
IF commandStream # NIL THEN Streams.Suspend[commandStream];
moduleStartTime ← secondsClock.low};
Finalize: PROC [started: BOOLEAN] = {
ObjectReset[keep: ~started OR parms.nErrors = 0];
IF sourceStream # NIL
THEN {Streams.Destroy[sourceStream]; sourceStream ← NIL};
ErrorReset[];
IF commandStream # NIL THEN Streams.Restart[commandStream];
IF log # NIL THEN Streams.Restart[log]};
CopyFile: PROCEDURE [from, to: Segments.FHandle] =
BEGIN OPEN Streams;
bufSize: CARDINAL = 20;
buffer: POINTER TO PACKED ARRAY [0..bufSize*256*2) OF CHARACTER =
Storage.Pages[bufSize];
words: CARDINAL;
end, odd: BOOLEAN ← FALSE;
scratch, source: Streams.Handle;
scratch ← CreateStream[to, Segments.Write];
source ← CreateStream[from, Segments.Read];
UNTIL end DO
words ← GetBlock[source, buffer, bufSize*256];
IF (end ← Ended[source]) AND GetIndex[source] MOD 2 # 0 THEN {
odd ← TRUE; words ← words - 1};
[] ← PutBlock[scratch, buffer, words];
IF odd THEN PutChar[scratch, buffer[words*2]];
ENDLOOP;
Storage.FreePages[buffer];
Segments.SetFileTimes[file: to, create: Segments.GetFileTimes[file: from].create];
source.destroy[source];
scratch.destroy[scratch];
END;
WriteClosing: PROC = {
OPEN AltoDisplay, CharIO;
IF (CursorXY.y ← CursorXY.y+16) > MaxScanLines-64 THEN CursorXY.y ← 64;
PutString[log, sourceName]; PutString[log, " -- "L];
IF parms.nErrors # 0
THEN {
CursorXY.x ← MIN[MaxBitsPerLine-64, CursorXY.x+16];
errors ← TRUE; PutString[log, "aborted, "L];
PutDecimal[log, parms.nErrors]; PutString[log, " errors "L];
IF parms.nWarnings # 0
THEN {
warnings ← TRUE; PutString[log, "and "L];
PutDecimal[log, parms.nWarnings]; PutString[log, " warnings "L]};
PutString[log, "on "L];
PutString[log, rootName]; PutString[log, ".errlog"L]}
ELSE {
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 ~formatting AND parms.objectBytes # 0
THEN {
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]};
IF parms.nWarnings # 0
THEN {
warnings ← TRUE; NewLine[];
PutDecimal[log, parms.nWarnings]; PutString[log, " warnings on "L];
PutString[log, rootName]; PutString[log, ".errlog"L]}}};
StopCompiler: PROC [toRun: BOOLEAN ← FALSE] = {
IF moduleCount > 1
THEN {
NewLine[]; CharIO.PutString[log, "Total elapsed time: "L];
WriteTime[secondsClock.low-compilerStartTime]; NewLine[]};
Segments.UnlockFile[logRequest.file]; logRequest.file ← NIL;
Streams.Destroy[log];
Segments.UnlockFile[comCmRequest.file]; comCmRequest.file ← NIL;
Streams.Destroy[commandStream];
MiniDisplay.Finalize[];
IF fontSeg # NIL
THEN {
Segments.DeleteSegment[fontSeg]; fontSeg ← NIL;
Segments.UnlockFile[fontRequest.file]; fontRequest.file ← NIL};
IF SwitchDefaults['q] AND (~toRun OR errors OR warnings)
THEN { -- got here from Debugger
CoreSwapDefs.level ← -1;
MiscOps.AllocateDebuggerBitmap[MiscOps.BitmapPages];
MiscDefs.CallDebugger[SELECT TRUE FROM
errors => "Errors logged"L,
warnings => "Warnings logged"L,
ENDCASE => "Compilation complete"L]};
IF (errors OR warnings) AND SwitchDefaults['p]
THEN {
BlankCursor: AltoDisplay.CursorBits = ALL[0];
QueryCursor: AltoDisplay.CursorBits = [
2000b, 74000b, 140000b, 12767b, 12525b, 53566b, 111113b, 163100b,
0b, 0b, 154000b, 53520b, 62520b, 53360b, 155440b, 140b];
ReadKeys: PROC [p: POINTER TO KeyDefs.KeyBits] = {
p↑ ← KeyDefs.Keys↑;
LOOPHOLE[p, POINTER]↑ ← 0; -- mouse, keyset
p.LeftShift ← p.Ctrl ← p.Spare3 ← up};
savedKeys, newKeys: KeyDefs.KeyBits;
RTC: POINTER TO MACHINE DEPENDENT RECORD [high: [0..4096), low: [0..16)] =
LOOPHOLE[430B];
savedTime: CARDINAL;
state: {off, on1, on2};
ReadKeys[@savedKeys];
AltoDisplay.Cursor↑ ← BlankCursor; state ← off; savedTime ← RTC.high;
DO
IF RTC.high # savedTime
THEN {
SELECT state FROM
off => {AltoDisplay.Cursor↑ ← QueryCursor; state ← on1};
on1 => state ← on2;
on2 => {AltoDisplay.Cursor↑ ← BlankCursor; state ← off};
ENDCASE;
savedTime ← RTC.high};
ReadKeys[@newKeys];
IF newKeys # savedKeys THEN EXIT;
ENDLOOP}};
transaction: CompilerOps.Transaction;
parms: POINTER TO CompilerOps.Transaction = @transaction;
SwitchDefaults: PACKED ARRAY CHARACTER ['a..'z] OF BOOLEAN ← InitDefaults;
InitDefaults: 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, TRUE, FALSE, FALSE, FALSE, TRUE,
FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE,
FALSE, FALSE, TRUE, FALSE, FALSE, FALSE];
FindFiles: PROC [fp: Segments.FPHandle, s: STRING] RETURNS [BOOLEAN] = {
IF s.length = sourceName.length AND String.EquivalentString[sourceName, s] THEN {
sourceFile ← Segments.InsertFile[fp, Segments.Read];
Segments.LockFile[sourceFile]};
IF ~formatting AND s.length = objectName.length AND
String.EquivalentString[objectName, s] THEN {
objectFile ← Segments.InsertFile[fp, Segments.Write];
Segments.LockFile[objectFile]};
IF formatting AND formatterOverwrite AND s.length = ("Formatter.scratch$."L).length AND
String.EquivalentString["Formatter.scratch$."L, s] THEN {
scratchFile ← Segments.InsertFile[fp, Segments.Write];
Segments.LockFile[scratchFile]};
IF s.length = rootName.length + (".errlog."L).length THEN {
errorName: STRING ← [40];
String.AppendString[errorName, rootName];
String.AppendString[errorName, ".errlog."L];
IF String.EquivalentString[errorName, s] THEN {
errorFile ← Segments.InsertFile[fp, Segments.Write];
Segments.LockFile[errorFile]}};
RETURN [sourceFile # NIL AND errorFile # NIL AND (formatting OR objectFile # NIL)]};
errors, warnings: BOOLEAN;
formatterOverwrite: 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);
bitmapFrozen: BOOLEAN ← FALSE;
dcbSpace: ARRAY [0..SIZE[AltoDisplay.DCB]+1) OF UNSPECIFIED;
dcb, saveDCB: AltoDisplay.DCBHandle;
-- cursor management
L1: WORD = 147777b;
R1: WORD = 177763b;
M1: WORD = 177177b;
Two: WORD = 147763b;
ClearCursor: PROC = INLINE {AltoDisplay.Cursor↑ ← ALL[177777b]};
SetCursor: PROC [position: {upper, middle, lower}, row: WORD] = {
SELECT position FROM
upper => AltoDisplay.Cursor[2] ← AltoDisplay.Cursor[3] ← row;
middle => AltoDisplay.Cursor[7] ← AltoDisplay.Cursor[8] ← row;
lower => AltoDisplay.Cursor[12] ← AltoDisplay.Cursor[13] ← row;
ENDCASE};
UpdateCursor: PROC [pass: CARDINAL] RETURNS [goOn: BOOLEAN ← TRUE] = {
ClearCursor[];
IF errors THEN {AltoDisplay.Cursor[5] ← 125252b; AltoDisplay.Cursor[10] ← 052525b};
SELECT pass FROM
1 => SetCursor[middle, M1];
2 => {SetCursor[upper, L1]; SetCursor[lower, R1]};
3 => {SetCursor[upper, R1]; SetCursor[middle, M1]; SetCursor[lower, L1]};
4 => {SetCursor[upper, Two]; SetCursor[lower, Two]};
5 => {SetCursor[upper, Two]; SetCursor[middle, M1]; SetCursor[lower, Two]};
6 => {SetCursor[upper, Two]; SetCursor[middle, Two]; SetCursor[lower, Two]}
ENDCASE};
saveCursor: AltoDisplay.CursorBits;
saveCoordinate: AltoDisplay.Coordinate;
-- add cleanup procedure
IF image
THEN {
ImageDefs.AddFileRequest[@comCmRequest];
ImageDefs.AddFileRequest[@logRequest];
ImageDefs.AddFileRequest[@fontRequest]} -- wait for restart
ELSE {
fp: Segments.FP ← MiscDefs.CommandLineCFA[].fp;
comCmRequest.file ← Segments.InsertFile[@fp, Segments.Read];
Segments.LockFile[comCmRequest.file]};
STOP; -- wait for restart (noop unless image)
dcb ← @dcbSpace[0];
IF LOOPHOLE[dcb, CARDINAL] MOD 2 # 0 THEN dcb ← dcb + 1;
dcb↑ ← AltoDisplay.DCB[NIL, high, white, 0, 0, NIL, 0];
saveDCB ← AltoDisplay.DCBchainHead↑; AltoDisplay.DCBchainHead↑ ← dcb;
saveCoordinate ← AltoDisplay.CursorXY↑; saveCursor ← AltoDisplay.Cursor↑;
ClearCursor[]; AltoDisplay.CursorXY↑ ← [64,64];
IF fontRequest.file = NIL
THEN {
fontRequest.file ← Segments.NewFile[fontRequest.name, Segments.Read];
Segments.LockFile[fontRequest.file]};
fontSeg ← IF fontRequest.file # NIL
THEN Segments.NewSegment[fontRequest.file, 1, 0, Segments.Read]
ELSE NIL;
MiniDisplay.Initialize[fontSeg];
START CompilerOps.Sequencer[explicitSwapping, tableSegment];
-- do the compilation
SetCommandInput[]; SetTypescript[];
compilerStartTime ← secondsClock.low; moduleCount ← 0;
WriteHerald[log, NIL]; errors ← warnings ← formatterOverwrite ← FALSE;
WHILE TRUE
DO
SetRoot: PROC [root, s: STRING] = {
root.length ← 0;
FOR i: CARDINAL IN [0..s.length)
DO
IF s[i] = '. THEN EXIT;
String.AppendChar[root, s[i]];
ENDLOOP};
args, results: CommandUtil.PairList;
switches: STRING;
sense: BOOLEAN;
BEGIN OPEN CharIO;
ClearCursor[]; MiniDisplay.Clear[];
parms.op ← IF formatting THEN format ELSE compile;
parms.system ← alto;
parms.getStream ← GetStream; parms.startPass ← UpdateCursor;
parms.switches ← SwitchDefaults; parms.switches['p] ← FALSE;
parms.debugPass ← LAST[CARDINAL];
[sourceName, args, results, switches] ←
CommandUtil.Parse[
s: commandStream,
opX: 2+("mesa").length, resultX: 2+("bcd").length
! CommandUtil.Failed => GO TO badSyntax];
IF sourceName = NIL AND switches = NIL THEN EXIT;
NewLine[]; PutString[log, "Command: "];
CommandUtil.Echo[log, sourceName, args, results, switches];
IF CommandUtil.ListLength[results] > 1 THEN GO TO badSemantics;
IF sourceName = NIL THEN GO TO globalSwitches;
SetRoot[rootName, IF CommandUtil.ListLength[results] = 1
THEN CommandUtil.GetNth[results, 0] ELSE sourceName];
IF switches # NIL
THEN {
i: CARDINAL;
CompleteFileName: PROC RETURNS [fileName: STRING, bcpl: BOOLEAN] = {
OPEN String;
root: STRING ← [40];
extension: STRING ← [40];
SetRoot[root, sourceName];
IF root.length = sourceName.length
THEN AppendString[extension, "image"L]
ELSE
FOR j: CARDINAL IN [root.length+1 .. sourceName.length)
DO AppendChar[extension, sourceName[j]] ENDLOOP;
fileName ← CommandUtil.CopyString[root, 2+extension.length];
fileName ← CommandUtil.SetExtension[fileName, extension];
bcpl ← EquivalentString[extension, "run"L]; RETURN};
WriteCommandFile: PROC [fileName: STRING] = {
copy: Streams.Handle;
copy ← Streams.CreateStream[
Segments.NewFile["com.cm."L, Segments.Write],
Segments.Write];
FOR j: CARDINAL IN [0..fileName.length-1)
DO PutChar[copy, fileName[j]] ENDLOOP;
IF switches.length > i+1
THEN {
PutChar[copy, '/];
FOR j: CARDINAL IN (i..switches.length)
DO PutChar[copy, switches[j]] ENDLOOP};
IF Streams.Ended[commandStream]
THEN PutChar[copy, CR]
ELSE {
PutChar[copy, ' ];
UNTIL Streams.Ended[commandStream]
DO PutChar[copy, GetChar[commandStream]] ENDLOOP};
Streams.Destroy[copy]};
Run: PROC [fileName: STRING, bcpl: BOOLEAN] = {
IF bcpl
THEN {
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[]}
ELSE
ImageDefs.RunImage[Segments.NewSegment[
file: Segments.NewFile[fileName, Segments.Read],
base: 1, pages: 1,
access: Segments.Read]]};
i ← 0; sense ← TRUE;
WHILE i < switches.length
DO
c: CHARACTER = switches[i];
SELECT c FROM
'-, '~ => sense ← ~sense;
'r, 'R => {
fileName: STRING;
bcpl: BOOLEAN;
[fileName, bcpl] ← CompleteFileName[];
WriteCommandFile[fileName];
StopCompiler[TRUE];
Run[fileName, bcpl ! ANY => ImageDefs.AbortMesa]};
-- never returns
'o, 'O => {
[] ← CommandUtil.FreeString[headerComment]; GOTO headerLine};
IN ['a..'z] => {parms.switches[c] ← sense; sense ← TRUE};
IN ['A..'Z] => {
parms.switches[c+('a-'A)] ← sense; sense ← TRUE};
'! => {MiscDefs.CallDebugger[NIL]; bitmapFrozen ← TRUE};
IN ['1..'5] => {parms.debugPass ← c-'0; sense ← TRUE};
ENDCASE;
i ← i+1;
ENDLOOP;
switches ← CommandUtil.FreeString[switches]};
parms.sourceId ← sourceName ← CommandUtil.SetExtension[sourceName, "mesa"];
parms.fileMap ← args;
IF CommandUtil.ListLength[results] # 0
THEN {
IF ~formatting THEN
objectName ← CommandUtil.GetNth[list: results, n: 0, delete: TRUE];
results ← CommandUtil.FreePairList[results]}
ELSE IF ~formatting THEN
objectName ← CommandUtil.CopyString[rootName, 2+("bcd").length];
IF ~formatting THEN objectName ← CommandUtil.SetExtension[objectName, "bcd"];
parms.objectId ← IF formatting THEN NIL ELSE objectName;
formatterOverwrite ←
parms.switches['t] OR parms.switches['v] OR parms.switches['z];
BEGIN
ENABLE ANY => GO TO punt;
Segments.EnumerateDirectory[FindFiles];
IF formatting AND formatterOverwrite AND sourceFile # NIL THEN {
IF scratchFile = NIL THEN {
scratchFile ← Segments.NewFile["Formatter.scratch$."L, Segments.Write];
Segments.LockFile[scratchFile]};
CopyFile[from: sourceFile, to: scratchFile];
objectStream ← Streams.CreateStream[sourceFile, Segments.Write];
objectFile ← sourceFile; Segments.SetFileTimes[objectFile];
sourceFile ← scratchFile; scratchFile ← NIL};
IF sourceFile = NIL THEN GO TO noSource;
parms.sourceVersion ← [0, 0, Segments.GetFileTimes[sourceFile].create];
sourceStream ← Streams.CreateStream[sourceFile, Segments.Read];
Segments.UnlockFile[sourceFile]; sourceFile ← NIL;
END;
IF ~bitmapFrozen
THEN {
IF ~parms.switches['d] THEN MiscOps.ReleaseDebuggerBitmap[];
bitmapFrozen ← TRUE};
NewLine[];
moduleCount ← moduleCount + 1;
MiniDisplay.Append[IF formatting THEN "Formatting: "L ELSE "Compiling: "L];
MiniDisplay.Append[rootName];
BEGIN
cs: STRING ← [1];
first: BOOLEAN ← TRUE;
cs.length ← 1;
FOR c: CHARACTER IN ['a..'z] DO
sd: BOOLEAN = IF c = 'p THEN FALSE ELSE InitDefaults[c];
IF parms.switches[c] # sd THEN {
IF first THEN {first ← FALSE; MiniDisplay.Append["/"L]};
IF sd THEN MiniDisplay.Append["~"L];
cs[0] ← c;
MiniDisplay.Append[cs]};
ENDLOOP;
END;
Initialize[];
CompilerOps.CompileAction[parms ! CompilerOps.Punt => GO TO punt];
ClearCursor[];
MiniDisplay.Append[" -- "L];
MiniDisplay.Append[IF parms.nErrors=0 THEN "ok"L ELSE "failed"L];
Finalize[TRUE]; WriteClosing[];
EXITS
globalSwitches => {
objectName ← NIL; results ← CommandUtil.FreePairList[results];
sense ← TRUE;
FOR i: CARDINAL IN [0..switches.length)
DO
c: CHARACTER = switches[i];
SELECT c FROM
'-, '~ => sense ← ~sense;
'! => {MiscDefs.CallDebugger[NIL]; bitmapFrozen ← TRUE};
'o, 'O => headerComment ← CommandUtil.FreeString[headerComment];
IN ['a..'z] => {SwitchDefaults[c] ← sense; sense ← TRUE};
IN ['A..'Z] => {SwitchDefaults[c+('a-'A)] ← sense; sense ← TRUE};
ENDCASE => EXIT;
ENDLOOP;
switches ← CommandUtil.FreeString[switches]};
headerLine => {
headerComment ← sourceName; sourceName ← NIL;
objectName ← NIL; results ← CommandUtil.FreePairList[results];
switches ← CommandUtil.FreeString[switches]};
badSemantics => {
objectName ← NIL; results ← CommandUtil.FreePairList[results];
errors ← TRUE; PutString[log, " -- Illegal command"]};
noSource => {
Finalize[FALSE]; errors ← TRUE;
PutChar[log, CR]; PutString[log, sourceName]; PutString[log, " -- File error"]};
END;
sourceName ← CommandUtil.FreeString[sourceName];
IF ~formatting THEN objectName ← CommandUtil.FreeString[objectName];
args ← CommandUtil.FreePairList[args];
NewLine[];
IF (errors OR warnings) AND parms.switches['p] THEN GO TO truncateList;
REPEAT
badSyntax => {
NewLine[]; CharIO.PutString[log, "-- Illegal syntax"]; errors ← TRUE};
truncateList => SwitchDefaults['p] ← TRUE;
punt => {ClearCursor[]; Finalize[TRUE]; WriteClosing[]; NewLine[]};
ENDLOOP;
StopCompiler[];
AltoDisplay.CursorXY↑ ← saveCoordinate; AltoDisplay.Cursor↑ ← saveCursor;
AltoDisplay.DCBchainHead↑ ← saveDCB;
ImageDefs.StopMesa[];
END.