-- file LogPack.Mesa -- last modified by Satterthwaite, September 9, 1982 1:00 pm DIRECTORY Alloc: TYPE USING [Bounds], CharIO: TYPE USING [ ControlZ, CR, SP, GetChar, PutChar, PutDecimal, PutNumber, PutString, PutSubString], ComData: TYPE USING [ bodyIndex, nErrors, nWarnings, switches, table, textIndex], CompilerUtil: TYPE USING [ AcquireStream, AcquireTable, ReleaseStream, ReleaseTable], ErrorTable: TYPE USING [CSRptr], FileStream: TYPE USING [FileByteIndex, EndOf, SetIndex], LiteralOps: TYPE USING [Value, StringValue], Log: TYPE USING [ErrorCode], Stream: TYPE USING [Handle], Strings: TYPE USING [String, SubString, SubStringDescriptor], Symbols: TYPE USING [seType, bodyType, HTIndex, ISEIndex, HTNull, SENull, BTNull], SymbolOps: TYPE USING [SubStringForHash], Tree: TYPE USING [Base, Index, Link, NodeName, Scan, Null, treeType], TreeOps: TYPE USING [ScanList]; LogPack: PROGRAM IMPORTS Alloc, CharIO, CompilerUtil, FileStream, LiteralOps, SymbolOps, TreeOps, dataPtr: ComData EXPORTS Log = { OPEN Symbols; ErrorCode: TYPE = Log.ErrorCode; SubString: TYPE = Strings.SubString; -- public interface Error: PUBLIC PROC [code: ErrorCode] = { Enter[]; ErrorLog[code, TRUE]; Exit[]}; ErrorHti: PUBLIC PROC [code: ErrorCode, hti: HTIndex] = { ErrorTree[code, [hash[hti]]]}; ErrorN: PUBLIC PROC [code: ErrorCode, n: INTEGER] = { Enter[]; CharIO.PutDecimal[errorStream, n]; CharIO.PutChar[errorStream, ' ]; ErrorLog[code, TRUE]; Exit[]}; ErrorNode: PUBLIC PROC [code: ErrorCode, node: Tree.Index] = { ErrorTree[code, [subtree[node]]]}; ErrorSei: PUBLIC PROC [code: ErrorCode, sei: ISEIndex] = { ErrorTree[code, [symbol[sei]]]}; ErrorTree: PUBLIC PROC [code: ErrorCode, t: Tree.Link] = { Enter[]; PrintOperand[t, 0, 0]; CharIO.PutString[errorStream, " "L]; ErrorLog[code, TRUE]; Exit[]}; Warning: PUBLIC PROC [code: ErrorCode] = { IF dataPtr.switches['w] THEN { Enter[]; CharIO.PutString[errorStream, "warning: "L]; ErrorLog[code, FALSE]; Exit[]}}; WarningNode: PUBLIC PROC [code: ErrorCode, node: Tree.Index] = { WarningTree[code, [subtree[node]]]}; WarningSei: PUBLIC PROC [code: ErrorCode, sei: ISEIndex] = { WarningTree[code, [symbol[sei]]]}; WarningSubString: PUBLIC PROC [code: ErrorCode, s: Strings.SubString] = { IF dataPtr.switches['w] THEN { Enter[]; CharIO.PutSubString[errorStream, s]; CharIO.PutChar[errorStream, ' ]; ErrorLog[code, FALSE]; Exit[]}}; WarningTree: PUBLIC PROC [code: ErrorCode, t: Tree.Link] = { IF dataPtr.switches['w] THEN { Enter[]; CharIO.PutString[errorStream, "warning: "L]; PrintOperand[t, 0, 0]; CharIO.PutString[errorStream, " "L]; ErrorLog[code, FALSE]; Exit[]}}; -- source printing PrintTextLine: PROC [i: CARDINAL] = { OPEN CharIO; start, lineIndex: FileStream.FileByteIndex; char: CHARACTER; n: [1..100]; sourceStream: Stream.Handle ← CompilerUtil.AcquireStream[source]; start ← lineIndex ← i; FOR n IN [1..100] UNTIL lineIndex = 0 DO lineIndex ← lineIndex - 1; FileStream.SetIndex[sourceStream, lineIndex]; IF CharIO.GetChar[sourceStream] = CR THEN EXIT; start ← lineIndex; ENDLOOP; FileStream.SetIndex[sourceStream, start]; FOR n IN [1..100] WHILE ~FileStream.EndOf[sourceStream] DO SELECT (char ← CharIO.GetChar[sourceStream]) FROM CR, ControlZ => EXIT; ENDCASE => PutChar[errorStream, char]; ENDLOOP; NewLine[]; CompilerUtil.ReleaseStream[source]}; -- errorStream, CSRp and desc.base are set by Enter errorStream: Stream.Handle ← NIL; CSRp: ErrorTable.CSRptr; desc: Strings.SubStringDescriptor; ss: SubString = @desc; Enter: PROC = { errorStream ← CompilerUtil.AcquireStream[log]; CSRp ← CompilerUtil.AcquireTable[error]; ss.base ← @CSRp[CSRp.stringOffset]}; Exit: PROC = { CompilerUtil.ReleaseTable[error]; CompilerUtil.ReleaseStream[log]; errorStream ← NIL}; WriteErrorString: PROC [n: ErrorCode] = { ss.offset ← CSRp.ErrorMessages[n].offset; ss.length ← CSRp.ErrorMessages[n].length; CharIO.PutSubString[errorStream, ss]}; WriteHti: PROC [hti: HTIndex] = { OPEN CharIO; desc: Strings.SubStringDescriptor; s: SubString = @desc; IF hti = HTNull THEN PutString[errorStream, "(anonymous)"L] ELSE {SymbolOps.SubStringForHash[s, hti]; PutSubString[errorStream, s]}}; WriteSei: PROC [sei: ISEIndex] = { WriteHti[IF sei=SENull THEN HTNull ELSE ((dataPtr.table).Bounds[seType].base)[sei].hash]}; WriteLti: PROC [t: literal Tree.Link] = { WITH t.info SELECT FROM word => CharIO.PutDecimal[errorStream, LiteralOps.Value[index]]; string => { s: Strings.String = LiteralOps.StringValue[index]; CharIO.PutChar[errorStream, '"]; FOR i: CARDINAL IN [0..s.length) DO CharIO.PutChar[errorStream, s[i]] ENDLOOP; CharIO.PutChar[errorStream, '"]}; ENDCASE}; -- tables used for printing trees -- OpName: ARRAY Tree.NodeName[assignx..uparrow] OF STRING ← [ -- "←", -- " OR ", " AND ", "=", "#", "<", ">=", ">", "<=", " IN ", " ~IN ", -- "+", "-", "*", "/", " MOD ", -- ".", ".", ".", -- " NEW ", "~", "-", "@", "↑"]; WriteOpName: PROC[n: Tree.NodeName[assignx..uparrow]] = { ss.offset ← CSRp.OpName[n].offset; ss.length ← CSRp.OpName[n].length; CharIO.PutSubString[errorStream, ss]}; OpPrec: ARRAY Tree.NodeName[assignx..uparrow] OF CARDINAL = [ 1, 1, 2, 3, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 10, 10, 10, 1, 4, 8, 9, 10]; -- FnName: ARRAY Tree.NodeName[min..loophole] OF STRING ← [ -- "MIN", "MAX", "LONG", "ABS", "ALL", "SIZE", "FIRST", "LAST", -- "DESCRIPTOR", "LENGTH", "BASE", "LOOPHOLE", "NIL"]; WriteFnName: PROC[n: Tree.NodeName[min..nil]] = { ss.offset ← CSRp.FnName[n].offset; ss.length ← CSRp.FnName[n].length; CharIO.PutSubString[errorStream, ss]}; Cutoff: CARDINAL = 3; PrintOperand: PROC [t: Tree.Link, tPrec, depth: CARDINAL] = { IF t = Tree.Null THEN RETURN; WITH e: t SELECT FROM hash => WriteHti[e.index]; symbol => WriteSei[e.index]; literal => WriteLti[e]; subtree => { OPEN CharIO; node: Tree.Index = e.index; tb: Tree.Base ← (dataPtr.table).Bounds[Tree.treeType].base; op: Tree.NodeName = tb[node].name; IF depth > Cutoff THEN {PutString[errorStream, "..."L]; RETURN}; SELECT op FROM syserror, syserrorx => PutString[errorStream, "ERROR"L]; lengthen, --abs,-- IN [first..succ], IN [length..base], nil => { PrintOperand[tb[node].son[1], OpPrec[dot], depth+1]; PutChar[errorStream, '.]; WriteFnName[op]}; IN [call .. rowcons], stringinit, IN [min .. nil] => { OPEN tb[node]; args: Tree.Link; SELECT op FROM IN [call .. rowcons], stringinit => { IF son[1] # Tree.Null THEN PrintOperand[son[1], 0, depth]; args ← son[2]}; IN [min .. nil] => {WriteFnName[op]; args ← son[1]}; ENDCASE; IF args # Tree.Null OR op # nil THEN { PutChar[errorStream, '[]; IF depth = Cutoff AND args.tag = subtree THEN PutString[errorStream, "..."L] ELSE PrintOperandList[args, depth+1]; IF op IN [call .. joinx] AND nSons > 2 THEN PutString[errorStream, " !..."L]; PutChar[errorStream, ']]}}; IN [assignx .. uparrow] => { OPEN tb[node]; prec: CARDINAL = OpPrec[op]; IF prec < tPrec THEN PutChar[errorStream, '(]; SELECT op FROM IN [create .. addr] => {WriteOpName[op]; PrintOperand[son[1], prec, depth]}; IN [assignx .. dollar] => { PrintOperand[son[1], prec, depth+1]; WriteOpName[op]; PrintOperand[son[2], prec+1, depth+1]}; uparrow => { PrintOperand[son[1], prec, depth]; PutChar[errorStream, '↑]}; ENDCASE => PutChar[errorStream, '?]; IF prec < tPrec THEN PutChar[errorStream, ')]}; IN [intOO .. intCC] => { OPEN tb[node]; PutChar[errorStream, IF op = intOO OR op = intOC THEN '( ELSE '[]; PrintOperand[son[1], 0, depth]; PutString[errorStream, ".."L]; PrintOperand[son[2], 0, depth]; PutChar[errorStream, IF op = intOO OR op = intCO THEN ') ELSE ']]}; clit => { c: CHARACTER = WITH e1: tb[node].son[1] SELECT FROM literal => WITH e1.info SELECT FROM word => LiteralOps.Value[index]+0C, ENDCASE => ERROR, ENDCASE => ERROR; IF c >= SP THEN {PutChar[errorStream, '']; PutChar[errorStream, c]} ELSE { PutNumber[errorStream, c-0C, [base:8, zerofill:FALSE, unsigned:TRUE, columns:0]]; PutChar[errorStream, 'c]}}; new, cons, listcons => { IF tb[node].son[1] # Tree.Null THEN { PrintOperand[tb[node].son[1], OpPrec[dot], depth+1]; PutChar[errorStream, '.]}; PutString[errorStream, SELECT op FROM new => "NEW"L, cons => "CONS"L, ENDCASE => "LIST"L]; PutChar[errorStream, '[]; IF depth = Cutoff THEN PutString[errorStream, "..."L] ELSE PrintOperandList[tb[node].son[2], depth+1]; PutChar[errorStream, ']]}; atom => { PutChar[errorStream, '$]; WITH e1: tb[node].son[1] SELECT FROM hash => WriteHti[e1.index]; ENDCASE}; llit, IN [cast .. openx], thread => PrintOperand[tb[node].son[1], tPrec, depth]; item => PrintOperand[tb[node].son[2], tPrec, depth]; ENDCASE => PutString[errorStream, "..."L]}; ENDCASE}; PrintOperandList: PROC [t: Tree.Link, depth: CARDINAL] = { firstSon: BOOLEAN ← TRUE; PrintItem: Tree.Scan = { IF ~firstSon THEN CharIO.PutString[errorStream, ", "L]; firstSon ← FALSE; IF t # Tree.Null THEN PrintOperand[t, 0, depth]}; TreeOps.ScanList[t, PrintItem]}; -- error-handling routines NewLine: PROC = {CharIO.PutChar[errorStream, CharIO.CR]}; ErrorLog: PROC [code: ErrorCode, error: BOOLEAN] = { OPEN CharIO; bodyId: ISEIndex; index: CARDINAL = dataPtr.textIndex; WriteErrorString[code]; IF error THEN dataPtr.nErrors ← dataPtr.nErrors + 1 ELSE dataPtr.nWarnings ← dataPtr.nWarnings + 1; PutString[errorStream, ", at "L]; IF dataPtr.bodyIndex # BTNull THEN { bodyId ← ((dataPtr.table).Bounds[Symbols.bodyType]).base[dataPtr.bodyIndex].id; IF bodyId # SENull THEN WriteSei[bodyId]}; IF index # LAST[CARDINAL] THEN { PutChar[errorStream, '[]; PutNumber[errorStream, index, [base:10, zerofill:FALSE, unsigned:TRUE, columns:0]]; PutChar[errorStream, ']]}; PutChar[errorStream, ':]; NewLine[]; IF index # LAST[CARDINAL] THEN PrintTextLine[index] ELSE {PutString[errorStream, "(source from inline)"L]; NewLine[]}; NewLine[]}; }.