-- PPReader.Mesa
-- Ed Satterthwaite, January 12, 1981 4:55 PM
-- Russ Atkinson, August 17, 1982 5:08 pm

DIRECTORY
CBinary USING [MesaTab, DebugTab],
Convert USING [MapValue],
PPCommentTable USING [Reset],
PPOps USING [TableId],
PPUtil USING [PrettyPrint, PrintTree],
PPComData USING [Init],
PrintTV USING [NullPutClosure, PutClosure],
Process USING [GetCurrent],
Runtime USING [GetTableBase],
PPP1 USING [Parse],
PPTree USING [Link, Null],
PPTreeOps USING [Finalize, Initialize, PopTree],
Rope USING [Map, ROPE];

PPReader: CEDAR MONITOR
IMPORTS
CBinary, Convert, P1: PPP1, TreeOps: PPTreeOps, PPComData,
PPUtil, Process, Rope, Runtime, CT: PPCommentTable
EXPORTS PPOps, PPUtil =
BEGIN OPEN Tree: PPTree, PrintTV, Rope;

-- stream management

Source: ROPENIL;
GetSource: PUBLIC PROC RETURNS [ROPE] = {RETURN[Source]};
SetSource: PUBLIC PROC [source: ROPE] = {
Source ← source};

-- table segment management

TableHandle: PUBLIC TYPE = LONG POINTER;
tableSegment: ARRAY PPOps.TableId [parse..debug] OF TableHandle ← ALL[NIL];

AcquireTable: PUBLIC PROC [id: PPOps.TableId] RETURNS [TableHandle] = {
RETURN [tableSegment[id]]};

ReleaseTable: PUBLIC PROC [id: PPOps.TableId] = {
};

-- parsing sequencing

SetOutputFailed: ERROR = CODE;

ParseStream: PUBLIC PROC
[source: ROPE, errPut, prettyPut, debugPut: PutClosure ← NullPutClosure]
RETURNS [root: Tree.Link] = {
ENABLE ANY => MashOutput[]; -- to prevent lockup
IF errPut # NullPutClosure THEN
IF NOT SetOutput[errPut]
THEN ERROR SetOutputFailed;
Source ← source;

TreeOps.Initialize[];
CT.Reset[];
{complete: BOOLTRUE;
nTokens,nErrors: CARDINAL ← 0;
[complete, nTokens, nErrors] ← P1.Parse[];
root ← IF complete AND nErrors = 0
THEN TreeOps.PopTree[]
ELSE Tree.Null;
IF errPut # NullPutClosure THEN
IF NOT SetOutput[] THEN ERROR SetOutputFailed;
};

IF debugPut # NullPutClosure THEN
{IF NOT SetOutput[debugPut] THEN ERROR SetOutputFailed;
PPUtil.PrintTree[root, NullPutClosure];
IF NOT SetOutput[] THEN ERROR SetOutputFailed;
};

IF prettyPut # NullPutClosure THEN
{IF NOT SetOutput[prettyPut] THEN ERROR SetOutputFailed;
PPUtil.PrettyPrint[root];
IF NOT SetOutput[] THEN ERROR SetOutputFailed;
 };
TreeOps.Finalize[];
Source ← NIL;
};

-- Output Routines exported to BBBugOut

SetOutput: PUBLIC ENTRY PROC
[put: PutClosure ← NullPutClosure] RETURNS [success: BOOL] = {
-- sets output procedure for output
-- waits if already set, of course
-- returns FALSE if attempt to set to NIL is not made by owner
ENABLE UNWIND => outProc ← NullPutClosure;
RETURN [InternalSetOutput[put]];
};

InternalSetOutput: INTERNAL PROC
[put: PutClosure ← NullPutClosure] RETURNS [success: BOOL] = TRUSTED {
-- sets output procedure for output
-- waits if already set, of course
me: PROCESS;
TRUSTED {me ← LOOPHOLE[Process.GetCurrent[]]};
IF put = NullPutClosure THEN {
IF outProc = NullPutClosure OR owner = me THEN
  {outProc ← NullPutClosure;
BROADCAST outChanged;
RETURN [TRUE]};
RETURN [FALSE];
};
UNTIL outProc = NullPutClosure OR owner = me DO WAIT outChanged; ENDLOOP;
owner ← me;
outProc ← put;
BROADCAST outChanged;
RETURN [TRUE];
};

MashOutput: ENTRY PROC = {
-- for emergency reset of the output proc
outProc ← NullPutClosure; BROADCAST outChanged};

outChanged: CONDITION;
outProc: PutClosure ← NullPutClosure;
owner: PROCESS; -- only valid if outProc # NIL

ShowChar: PUBLIC PROC [c: CHAR] = {
outProc.proc[outProc.data, c]
};

ShowCharB: PUBLIC PROC [c: CHAR] RETURNS [BOOL] = {
outProc.proc[outProc.data, c];
RETURN [FALSE]
};

ShowCR: PUBLIC PROC = {
outProc.proc[outProc.data, 15C]
};

ShowDecimal: PUBLIC PROC [x: INT] = {
Convert.MapValue[ShowChar, [signed[x, 10]]]
};

ShowOctal: PUBLIC PROC [x: INT] = {
Convert.MapValue[ShowChar, [signed[x, 8]]]
};

ShowRope: PUBLIC PROC [r: ROPENIL] = {
IF r # NIL THEN [] ← Rope.Map[base: r, action: ShowCharB]
};

-- initialization code

TRUSTED
{tableSegment[parse] ← Runtime.GetTableBase[LOOPHOLE[CBinary.MesaTab]];
tableSegment[debug] ← Runtime.GetTableBase[LOOPHOLE[CBinary.DebugTab]]};

PPComData.Init[];

END.