errorStream: IO.STREAM ← NIL;
WriteChar: PROC [c: CHAR] = {IO.PutChar[errorStream, c]};
WriteRope: PROC [s: Rope.ROPE] = {IO.Put[errorStream, IO.rope[s]]};
WriteDecimal: 
PROC [n: 
INTEGER] = {
IO.Put[errorStream, IO.int[n]]};
 
NewLine: PROC = INLINE {WriteChar[IO.CR]};
Indent: 
PROC [n: 
CARDINAL] = {
NewLine[];
THROUGH [1..n/8] DO WriteChar[IO.TAB] ENDLOOP;
THROUGH [1..n MOD 8] DO WriteChar[' ] ENDLOOP};
 
errorStream, csrP and desc.base are set by Enter
csrP: DebugTable.CSRptr;
ss: SubString;
LockStringTable: 
PROC = 
INLINE {
csrP ← CompilerUtil.AcquireTable[debug];
ss.base ← @csrP[csrP.stringOffset]};
 
UnlockStringTable: PROC = INLINE {CompilerUtil.ReleaseTable[debug]; csrP ← NIL};
Enter: 
PROC [table: Alloc.Handle] = {
table.AddNotify[DebugNotify];
errorStream ← CompilerUtil.AcquireStream[log];  LockStringTable[]};
 
Exit: 
PROC [table: Alloc.Handle] = {
UnlockStringTable[];  CompilerUtil.ReleaseStream[log]; errorStream ← NIL;
table.DropNotify[DebugNotify]};
 
WriteSubString: 
PROC [ss: SubString] = {
FOR i: 
CARDINAL 
IN [ss.offset..ss.offset+ss.length) 
DO
WriteChar[ss.base[i]] ENDLOOP};
 
 
tree printing
PrintLiteral: 
PROC [t: Tree.Link.literal] = {
WITH t.index 
SELECT 
FROM
string => {
s: LONG STRING = LiteralOps.StringValue[sti];
WriteChar['"];
FOR i: CARDINAL IN [0..s.length) DO WriteChar[s[i]] ENDLOOP;
WriteChar['"];
IF sti # LiteralOps.MasterString[sti] THEN WriteChar['L]};
 
word => {
desc: Literals.LitDescriptor = LiteralOps.DescriptorValue[lti];
v: WORD;
IF desc.length # 1 THEN WriteChar['[];
FOR i: 
CARDINAL 
IN [0 .. desc.length) 
DO
IF (v ← ltb[desc.offset][i]) < 1000 THEN WriteDecimal[v]
ELSE IO.PutF[errorStream, "%b", IO.int[v]]; -- octal
IF i+1 # desc.length THEN WriteChar[',];
ENDLOOP;
 
IF desc.length # 1 THEN WriteChar[']]};
 
ENDCASE};
 
 
WriteNodeName: 
PROC [n: Tree.NodeName] = {
ss.offset ← csrP.NodePrintName[n].offset; ss.length ← csrP.NodePrintName[n].length;
WriteSubString[ss]};
 
PrintSubTree: 
PROC [t: Tree.Link, nBlanks: 
CARDINAL] = {
OPEN Tree;
Printer: Tree.Scan = {
Indent[nBlanks];
WITH s: t 
SELECT 
FROM
hash => PrintName[s.index];
symbol => {PrintSei[s.index]; WriteChar['[]; PrintIndex[s.index]; WriteChar[']]};
literal => PrintLiteral[s];
subtree => {
node: Tree.Index = s.index;
IF node = Tree.NullIndex THEN WriteRope["<empty>"]
ELSE {
OPEN tb[node];
WriteNodeName[name];
WriteChar['[];  PrintIndex[node];  WriteRope["] "];
IF info # 0 THEN {WriteRope["  info="]; PrintIndex[info]};
IF attr1 
OR attr2 
OR attr3 
THEN {
IF info = 0 THEN WriteChar[' ];
WriteChar['(];
IF attr1 THEN WriteChar['1];
IF attr2 THEN WriteChar['2];
IF attr3 THEN WriteChar['3];
WriteChar[')]};
 
nBlanks ← nBlanks + 2;
IF name # thread THEN TreeOps.ScanSons[s, Printer]
ELSE {
WriteRope[" link="]; PrintIndex[TreeOps.GetNode[son[2]]];
Printer[son[1]]};
 
nBlanks ← nBlanks - 2}};
 
 
ENDCASE};
 
 
Printer[t]};
 
PrintTree: 
PUBLIC 
PROC [table: Alloc.Handle, root: Tree.Link] = {
Enter[table];
PrintSubTree[root, 0];  NewLine[];  NewLine[];
Exit[table]};
 
PrintBodies: 
PUBLIC 
PROC [table: Alloc.Handle] = {
Enter[table];
[] ← SymbolOps.EnumerateBodies[RootBti, PrintBody];  NewLine[];
Exit[table]};
 
PrintBody: 
PROC [bti: BTIndex] 
RETURNS [
BOOL] = {
OPEN body: bb[bti];
WriteRope["Body: "];
WITH b: body 
SELECT 
FROM
Callable => {
PrintSei[b.id];
IF b.inline THEN WriteRope[" [inline]"]
ELSE {
WriteRope[", ep: "];  WriteDecimal[b.entryIndex];
WITH b 
SELECT 
FROM
Inner => {WriteRope[", frame addr: "]; WriteDecimal[frameOffset]};
ENDCASE};
 
 
WriteRope[", attrs: "];
WriteChar[IF ~b.noXfers THEN 'x ELSE '-];
WriteChar[IF b.hints.safe THEN 's ELSE '-];
WriteChar[IF b.hints.nameSafe THEN 'n ELSE '-];
IF ~b.hints.noStrings THEN {Indent[2]; WriteRope["string literals"]}};
 
ENDCASE => WriteRope["(anon)"];
 
Indent[2];
WriteRope["context: "];  PrintIndex[body.localCtx];
WriteRope[", level: "];  WriteDecimal[body.level];
WITH body.info 
SELECT 
FROM
Internal => {
WriteRope[", frame size: "];  WriteDecimal[frameSize];
IF body.kind = Callable THEN PrintSubTree[[subtree[index: bodyTree]], 0]
ELSE {WriteRope[", tree root: "]; PrintIndex[bodyTree]}};
 
ENDCASE;
 
NewLine[];  NewLine[];  RETURN [FALSE]};
 
PrintSymbols: 
PUBLIC 
PROC [table: Alloc.Handle, definitions: 
BOOL] = {
ctx: CTXIndex;
limit: CTXIndex;
Enter[table];
definitionsOnly ← definitions;
limit ← table.Top[Symbols.ctxType];
ctx ← CTXIndex.FIRST + CTXRecord.nil.SIZE;
UNTIL ctx = limit 
DO
PrintContext[ctx];  NewLine[];  NewLine[];
ctx ← ctx + (
WITH ctxb[ctx] 
SELECT 
FROM
included => CTXRecord.included.SIZE,
imported => CTXRecord.imported.SIZE,
ENDCASE => CTXRecord.simple.SIZE);
 
ENDLOOP;
 
NewLine[];
Exit[table]};
 
PrintContext: 
PROC [ctx: CTXIndex] = {
sei, root: ISEIndex;
WriteRope["Context: "];  PrintIndex[ctx];
IF ctxb[ctx].level # lZ THEN {WriteRope[", level: "]; WriteDecimal[ctxb[ctx].level]};
WITH c: ctxb[ctx] 
SELECT 
FROM
included => {
WriteRope[", copied from: "]; PrintName[mdb[c.module].moduleId];
WriteRope[" ["]; PrintName[mdb[c.module].fileId];
WriteRope[", "]; PrintVersion[mdb[c.module].stamp];
WriteRope["], context: "];  PrintIndex[c.map]};
 
imported => {
WriteRope[", imported from: "]; PrintName[mdb[ctxb[c.includeLink].module].moduleId]};
 
ENDCASE;
 
root ← sei ← ctxb[ctx].seList;
DO
IF sei = SENull THEN EXIT;
PrintSE[sei, 2];
IF (sei ← SymbolOps.NextSe[sei]) = root THEN EXIT;
ENDLOOP};
 
 
PrintSE: 
PROC [sei: ISEIndex, nBlanks: 
CARDINAL] = {
OPEN seb[sei];
typeSei: SEIndex;
Indent[nBlanks];
PrintSei[sei];
WriteRope[" ["];  PrintIndex[sei];  WriteChar[']];
IF public THEN WriteRope[" [public]"];
IF mark3 
THEN {
WriteRope[", type = "];
IF idType = typeTYPE 
THEN {
typeSei ← idInfo;
WriteRope["TYPE, equated to: "];
PrintType[typeSei];
IF ctxb[idCtx].level = lZ 
AND SymbolOps.TypeLink[sei] # SENull 
THEN {
WriteRope[", tag code: "]; WriteDecimal[idValue]}}
 
ELSE {
typeSei ← idType;  PrintType[typeSei];
SELECT 
TRUE 
FROM
constant => WriteRope[" [const]"];
immutable => WriteRope[" [init only]"];
ENDCASE;
 
IF ~mark4 THEN {WriteRope[", # refs: "]; WriteDecimal[idInfo]}
ELSE
SELECT 
TRUE 
FROM
constant =>
IF ~ extended 
THEN {
WriteRope[", value: "];
SELECT SymbolOps.XferMode[typeSei] 
FROM
proc, program, signal, error => PrintLink[idValue];
ENDCASE =>
IF LOOPHOLE[idValue, CARDINAL] < 1000 THEN WriteDecimal[idValue]
ELSE IO.PutF[errorStream, "%b", IO.card[LOOPHOLE[idValue, CARDINAL]]]}; -- octal
 
 
 
 
(definitionsOnly 
AND ctxb[idCtx].level = lG) => {
WriteRope[", index: "]; WriteDecimal[idValue]};
 
ENDCASE => {
addr: BitAddress = idValue;
WriteRope[", address: "];
WriteDecimal[addr.wd];  WriteChar[' ];
WriteChar['[];  WriteDecimal[addr.bd];
WriteChar[':];  WriteDecimal[idInfo];  WriteChar[']];
IF linkSpace THEN WriteChar['*]}};
 
 
 
 
PrintTypeInfo[typeSei, nBlanks+2];
IF extended THEN PrintSubTree[SymbolOps.FindExtension[sei].tree, nBlanks+4]}};
 
 
 
PrintName: 
PROC [name: Name] = {
s: SubString;
IF name = nullName THEN WriteRope["(anon)"]
ELSE {s ← SymbolOps.SubStringForName[name]; WriteSubString[s]}};
 
PrintSei: PROC [sei: ISEIndex] = {PrintName[SymbolOps.NameForSe[sei]]};
WriteTypeName: 
PROC [n: TypeClass] = {
ss.offset ← csrP.TypePrintName[n].offset;  ss.length ← csrP.TypePrintName[n].length;
WriteSubString[ss]};
 
WriteModeName: 
PROC [n: TransferMode] = {
ss.offset ← csrP.ModePrintName[n].offset;  ss.length ← csrP.ModePrintName[n].length;
WriteSubString[ss]};
 
PrintType: 
PROC [sei: SEIndex] = {
tSei: SEIndex;
IF sei = SENull THEN WriteChar['?]
ELSE
WITH t: seb[sei] 
SELECT 
FROM
cons =>
WITH t 
SELECT 
FROM
transfer => WriteModeName[mode];
ENDCASE => WriteTypeName[t.typeTag];
 
 
id =>
FOR tSei ← sei, SymbolOps.TypeLink[tSei] 
UNTIL tSei = SENull 
DO
WITH seb[tSei] 
SELECT 
FROM
id => {
IF sei # tSei THEN WriteChar[' ];
PrintSei[LOOPHOLE[tSei, ISEIndex]];
IF ~mark3 OR ctxb[idCtx].level # lZ THEN EXIT};
 
ENDCASE;
 
ENDLOOP;
 
 
ENDCASE;
 
 
WriteRope[" ["];  PrintIndex[sei];  WriteChar[']]};
 
PrintTypeInfo: 
PROC [sei: SEIndex, nBlanks: 
CARDINAL] = {
IF sei # SENull 
THEN
WITH s: seb[sei] 
SELECT 
FROM
cons => {
Indent[nBlanks];
WriteChar['[];  PrintIndex[sei];  WriteRope["] "];
WITH s 
SELECT 
FROM
transfer => WriteModeName[mode];
ENDCASE => WriteTypeName[s.typeTag];
 
WITH t: s 
SELECT 
FROM
basic => NULL;
enumerated => {
IF t.machineDep THEN WriteRope[" (md)"]
ELSE IF t.unpainted THEN WriteRope[" (~painted)"];
WriteRope[", value ctx: "];  PrintIndex[t.valueCtx]};
 
record => {
IF t.machineDep THEN WriteRope[" (md)"];
IF t.monitored THEN WriteRope[" (monitored)"];
IF t.hints.variant THEN WriteRope[" (variant)"];
OutCtx[", field", t.fieldCtx];
WITH ctxb[t.fieldCtx] 
SELECT 
FROM
included => IF ~complete THEN WriteRope[" [partial]"];
imported => WriteRope[" [partial]"];
ENDCASE;
 
WITH t 
SELECT 
FROM
linked => {WriteRope[", link: "]; PrintType[linkType]};
ENDCASE};
 
 
ref => {
SELECT 
TRUE 
FROM
t.counted => WriteRope[" (counted)"];
t.var => WriteRope[" (var)"];
ENDCASE;
 
IF t.ordered THEN WriteRope[" (ordered)"];
IF t.basing THEN WriteRope[" (base)"];
WriteRope[", to: "]; PrintType[t.refType];
IF t.readOnly THEN WriteRope[" (readonly)"];
PrintTypeInfo[t.refType, nBlanks+2]};
 
array => {
IF t.packed THEN WriteRope[" (packed)"];
WriteRope[", index type: "]; PrintType[t.indexType];
WriteRope[", component type: "]; PrintType[t.componentType];
PrintTypeInfo[t.indexType, nBlanks+2];
PrintTypeInfo[t.componentType, nBlanks+2]};
 
arraydesc => {
WriteRope[", described type: "]; PrintType[t.describedType];
IF t.readOnly THEN WriteRope[" (readonly)"];
PrintTypeInfo[t.describedType, nBlanks+2]};
 
transfer => {
IF t.safe THEN WriteRope[" (safe)"];
OutArgType[", input", t.typeIn];
OutArgType[", output", t.typeOut]};
 
definition => {
WriteRope[", ctx: "];  PrintIndex[t.defCtx];
WriteRope[", ngfi: "];  WriteDecimal[t.nGfi]};
 
union => {
IF t.overlaid THEN WriteRope[" (overlaid)"];
IF t.controlled THEN {WriteRope[", tag: "]; PrintSei[t.tagSei]};
WriteRope[", tag type: "];
PrintType[seb[t.tagSei].idType];
WriteRope[", case ctx: "];  PrintIndex[t.caseCtx];
IF t.controlled THEN PrintSE[t.tagSei, nBlanks+2]};
 
sequence => {
IF t.packed THEN WriteRope[" (packed)"];
IF t.controlled THEN {WriteRope[", tag: "]; PrintSei[t.tagSei]}
ELSE {WriteRope[", index type: "];  PrintType[seb[t.tagSei].idType]};
WriteRope[", component type: "]; PrintType[t.componentType];
IF t.controlled THEN PrintSE[t.tagSei, nBlanks+2]
ELSE PrintTypeInfo[seb[t.tagSei].idType, nBlanks+2];
PrintTypeInfo[t.componentType, nBlanks+2]};
 
relative => {
WriteRope[", base type: "]; PrintType[t.baseType];
WriteRope[", offset type: "]; PrintType[t.offsetType];
PrintTypeInfo[t.baseType, nBlanks+2];
PrintTypeInfo[t.offsetType, nBlanks+2]};
 
opaque => {
WriteRope[", id: "]; PrintSei[t.id];
IF t.lengthKnown THEN {WriteRope[", size: "]; WriteDecimal[t.length]}};
 
zone => {
IF t.counted THEN WriteRope[" (counted)"];
IF t.mds THEN WriteRope[" (mds)"]};
 
subrange => {
WriteRope[" of: "];  PrintType[t.rangeType];
IF t.filled 
THEN {
WriteRope[" origin: "];  WriteDecimal[t.origin];
WriteRope[", range: "];  WriteDecimal[t.range]};
 
PrintTypeInfo[t.rangeType, nBlanks+2]};
 
long, real => {
WriteRope[" of: "];  PrintType[t.rangeType];
PrintTypeInfo[t.rangeType, nBlanks+2]};
 
ENDCASE};
 
 
ENDCASE};
 
 
 
OutCtx: 
PROC [message: Rope.
ROPE, ctx: CTXIndex] = {
WriteRope[message]; WriteRope[" ctx: "];
IF ctx = CTXNull THEN WriteRope["NIL"] ELSE PrintIndex[ctx]};
 
OutArgType: 
PROC [message: Rope.
ROPE, sei: CSEIndex] = {
IF sei = SENull THEN {WriteRope[message]; WriteRope[": NIL"]}
ELSE
WITH t: seb[sei] 
SELECT 
FROM
record => OutCtx[message, t.fieldCtx];
any => {WriteRope[message]; WriteRope[": ANY"]};
ENDCASE};
 
 
 
PrintIndex: PROC [v: UNSPECIFIED] = LOOPHOLE[WriteDecimal];
PrintLink: 
PROC [link: BcdDefs.Link] = {
SELECT 
TRUE 
FROM
link.proc => {
WriteRope["proc["]; WriteDecimal[link.gfi]; WriteChar[',]; WriteDecimal[link.ep]};
 
link.type => {WriteRope["type["]; PrintIndex[link.typeID]};
ENDCASE => {
WriteRope["var["]; WriteDecimal[link.gfi]; WriteChar[',]; WriteDecimal[link.var]};
 
 
WriteChar[']]};
 
PrintVersion: 
PROC [stamp: BcdDefs.VersionStamp] = {
stampWords: CARDINAL = BcdDefs.VersionStamp.SIZE;
str: PACKED ARRAY [0..4*stampWords) OF [0..16) = LOOPHOLE[stamp];
digit: STRING = "0123456789abcdef"L;
FOR i: NAT IN [0..4*stampWords) DO WriteChar[digit[str[i]]] ENDLOOP};
 
}.