PPParser.Mesa
derived from Compiler>Parser.Mesa
Satterthwaite, January 12, 1981 12:58 PM
Russ Atkinson, November 12, 1982 2:44 pm
Paul Rovner, August 25, 1983 4:50 pm
DIRECTORY
IO USING [int, Put, PutRope, PutChar, STREAM],
PPP1
USING [
Token, Value, ValueSeq, ValueStack, NullValue, INTSeq, ActionEntrySeq,
AssignDescriptors, Atom, ErrorContext, ProcessQueue, ResetScanIndex,
ScanInit, ScanReset],
PPParseTable
USING [
ActionEntry, ActionTag, Handle, NTIndex, NTState, NTSymbol,
ProdDataHandle, State, TIndex, TSymbol,
DefaultMarker, EndMarker, InitialState, FinalState, InitialSymbol],
Rope USING [ROPE];
PPParser:
PROGRAM
IMPORTS IO, P1: PPP1
EXPORTS PPP1 =
BEGIN OPEN PPParseTable, Rope;
ErrorLimit: CARDINAL = 10;
Scan: ActionTag = [FALSE, 0];
inputSymbol: TSymbol;
input: PROC [errPut: IO.STREAM] RETURNS [token: P1.Token];
inputLoc: INT;
inputValue: P1.Value;
lastToken: P1.Token;
NullSymbol: TSymbol = 0;
firstInit: BOOL ← TRUE;
s: REF StateSeq ← NIL;
StateSeq: TYPE = RECORD[SEQUENCE length: CARDINAL OF State];
l: REF P1.INTSeq ← NIL;
v: P1.ValueStack ← NIL;
top: CARDINAL ← 0;
q: REF P1.ActionEntrySeq ← NIL;
qI: CARDINAL;
tablePtr: Handle;
transition tables for terminal input symbols
tStart: LONG POINTER TO ARRAY State OF TIndex ← NIL;
tLength: LONG POINTER TO ARRAY State OF CARDINAL ← NIL;
tSymbol: LONG POINTER TO ARRAY TIndex OF TSymbol ← NIL;
tAction: LONG POINTER TO ARRAY TIndex OF ActionEntry ← NIL;
transition tables for nonterminal input symbols
nStart: LONG POINTER TO ARRAY NTState OF NTIndex ← NIL;
nLength: LONG POINTER TO ARRAY NTState OF CARDINAL ← NIL;
nSymbol: LONG POINTER TO ARRAY NTIndex OF NTSymbol ← NIL;
nAction: LONG POINTER TO ARRAY NTIndex OF ActionEntry ← NIL;
ntDefaults: LONG POINTER TO ARRAY NTSymbol OF ActionEntry ← NIL;
production information
prodData: ProdDataHandle ← NIL;
initialization/termination
ParseInit:
PROC [source:
ROPE, pth: Handle] = {
tablePtr ← pth;
P1.ScanInit[tablePtr, source];
tStart ← @tablePtr.parseTable.tStart;
tLength ← @tablePtr.parseTable.tLength;
tSymbol ← @tablePtr.parseTable.tSymbol;
tAction ← @tablePtr.parseTable.tAction;
nStart ← @tablePtr.parseTable.nStart;
nLength ← @tablePtr.parseTable.nLength;
nSymbol ← @tablePtr.parseTable.nSymbol;
nAction ← @tablePtr.parseTable.nAction;
ntDefaults ← @tablePtr.parseTable.ntDefaults;
prodData ← @tablePtr.parseTable.prodData;
IF firstInit
THEN {
ExpandStack[64];
ExpandQueue[64];
firstInit ← FALSE;
};
};
InputLoc: PUBLIC SAFE PROC RETURNS [INT] = TRUSTED {RETURN [inputLoc]};
-- * * * * Main Parsing Procedures * * * * --
Parse:
PUBLIC
SAFE
PROC [source:
ROPE, pth: Handle, errPut:
IO.
STREAM]
RETURNS [complete: BOOL, nTokens, nErrors: CARDINAL] = TRUSTED {
currentState: State;
i, valid, m: CARDINAL; -- stack pointers
action: ActionEntry;
ParseInit[source, pth]; input ← P1.Atom;
nErrors ← 0; complete ← TRUE;
i ← top ← valid ← 0; qI ← 0;
s[0] ← currentState ← InitialState; lastToken.class ← NullSymbol;
inputSymbol ← InitialSymbol; inputValue ← P1.NullValue; inputLoc ← 0;
WHILE currentState # FinalState
DO
BEGIN
tI: TIndex ← tStart[currentState];
FOR tI
IN [tI .. tI + tLength[currentState])
DO
SELECT tSymbol[tI] FROM inputSymbol, DefaultMarker => EXIT ENDCASE;
REPEAT
FINISHED => GOTO syntaxError;
ENDLOOP;
action ← tAction[tI];
IF ~action.tag.reduce
-- scan or scan reduce entry
THEN {
IF qI > 0
THEN {
FOR k: CARDINAL IN (valid..i] DO s[k] ← s[top+(k-valid)] ENDLOOP;
P1.ProcessQueue[qI, top]; qI ← 0};
IF (top ← valid ← i ← i+1) >= s.length THEN ExpandStack[64];
lastToken.class ← inputSymbol; v[i] ← inputValue; l[i] ← inputLoc;
[[inputSymbol, inputValue, inputLoc]] ← input[errPut]};
WHILE action.tag # Scan
DO
IF qI >= q.length THEN ExpandQueue[64];
q[qI] ← action; qI ← qI + 1;
i ← i-action.tag.pLength;
currentState ← s[
IF i > valid
THEN top+(i-valid)
ELSE (valid ← i)];
BEGIN
lhs: NTSymbol = prodData[action.transition].lhs;
IF currentState <=
LAST[NTState]
THEN {
nI: NTIndex ← nStart[currentState];
FOR nI
IN [nI..nI+nLength[currentState])
DO
IF lhs = nSymbol[nI] THEN {action ← nAction[nI]; GO TO nFound};
ENDLOOP};
action ← ntDefaults[lhs];
END;
i ← i+1;
ENDLOOP;
IF (m ← top+(i-valid)) >= s.length THEN ExpandStack[64];
s[m] ← currentState ← action.transition;
EXITS
syntaxError => {
lastToken.value ← v[top]; lastToken.index ← l[top];
top ← top - 1;
complete ← SyntaxError[(nErrors←nErrors+1)>ErrorLimit, errPut];
i ← valid ← top; qI ← 0; lastToken.class ← NullSymbol;
currentState ← s[i];
[[inputSymbol, inputValue, inputLoc]] ← input[errPut];
IF ~complete THEN EXIT};
END;
ENDLOOP;
P1.ProcessQueue[qI, top];
{n: CARDINAL; [nTokens, n] ← P1.ScanReset[]; nErrors ← nErrors + n};
RETURN};
ExpandStack:
PROC [delta:
CARDINAL] = {
newS: REF StateSeq;
newL: REF P1.INTSeq;
newV: P1.ValueStack ← NIL;
newSize: CARDINAL = (IF s = NIL THEN 0 ELSE s.length) + delta;
newS ← NEW[StateSeq[newSize]];
newL ← NEW[P1.INTSeq[newSize]];
newV ←
IF v #
NIL
AND v.length >= newSize
THEN v
ELSE NEW[P1.ValueSeq[newSize]];
IF s #
NIL
THEN
FOR i:
CARDINAL
IN [0..s.length)
DO newS[i] ← s[i]; newL[i] ← l[i]; newV[i] ← v[i] ENDLOOP;
s ← newS; l ← newL; v ← newV;
P1.AssignDescriptors[qd:q, vd:v, ld:l, pp:prodData]};
ExpandQueue:
PROC [delta:
CARDINAL] = {
newSize: CARDINAL = (IF q = NIL THEN 0 ELSE q.length) + delta;
newQ: REF P1.ActionEntrySeq ← NEW[P1.ActionEntrySeq[newSize]];
IF q # NIL THEN FOR i: CARDINAL IN [0..q.length) DO newQ[i] ← q[i] ENDLOOP;
q ← newQ;
P1.AssignDescriptors[qd:q, vd:v, ld:l, pp:prodData]};
-- * * * * Error Recovery Section * * * * --
parameters of error recovery
MinScanLimit: CARDINAL = 4;
MaxScanLimit: CARDINAL = 12;
InsertLimit: CARDINAL = 2;
DiscardLimit: CARDINAL = 10;
TreeSize: CARDINAL = 256;
CheckSize: CARDINAL = MaxScanLimit+InsertLimit+2;
debugging
ParserID: PUBLIC SAFE PROC RETURNS [ROPE] = TRUSTED {RETURN ["Flako!"]};
tree management
NodeIndex: TYPE = CARDINAL [0..TreeSize);
NullIndex: NodeIndex = 0;
StackNode:
TYPE =
RECORD[
father: NodeIndex,
last: NodeIndex,
state: State,
symbol: TSymbol,
aLeaf, bLeaf: BOOLEAN,
link: NodeIndex];
tree: REF ARRAY [0..TreeSize) OF StackNode;
nextNode: NodeIndex;
maxNode: NodeIndex;
treeLimit: CARDINAL;
TreeFull: SIGNAL = CODE;
Allocate:
PROC [parent, pred: NodeIndex, terminal: TSymbol, stateNo: State]
RETURNS [index: NodeIndex] = {
IF (index ← nextNode) >= treeLimit THEN SIGNAL TreeFull;
maxNode ← MAX[index, maxNode];
tree[index] ← StackNode[
father: parent,
last: pred,
state: stateNo,
symbol: terminal,
aLeaf: FALSE, bLeaf: FALSE,
link: NullIndex];
nextNode ← nextNode+1; RETURN};
HashSize: INTEGER = 64; -- should depend on state count ?
hashTable: REF ARRAY [0..HashSize) OF NodeIndex;
ParsingMode: TYPE = {ATree, BTree, Checking};
parseMode: ParsingMode;
LinkHash:
PROC [n: NodeIndex] = {
htIndex: [0..HashSize) = tree[n].state MOD HashSize;
tree[n].link ← hashTable[htIndex]; hashTable[htIndex] ← n};
ExistingConfiguration:
PROC [stack: StackRep]
RETURNS [NodeIndex] = {
n, n1, n2: NodeIndex;
s1, s2: State;
htIndex: [0..HashSize);
aTree: BOOLEAN;
SELECT parseMode
FROM
ATree => aTree ← TRUE;
BTree => aTree ← FALSE;
ENDCASE => RETURN [NullIndex];
htIndex ← stack.extension MOD HashSize;
FOR n ← hashTable[htIndex], tree[n].link
UNTIL n = NullIndex
DO
IF (
IF aTree
THEN tree[n].aLeaf
ELSE tree[n].bLeaf)
THEN {
s1 ← stack.extension; s2 ← tree[n].state;
n1 ← stack.leaf; n2 ← tree[n].father;
DO
IF s1 # s2 THEN EXIT;
IF n1 = n2 THEN RETURN [n];
s1 ← tree[n1].state; s2 ← tree[n2].state;
n1 ← tree[n1].father; n2 ← tree[n2].father;
ENDLOOP};
ENDLOOP;
RETURN [NullIndex]};
FindNode:
PROC [parent, pred: NodeIndex, stateNo: State]
RETURNS [index: NodeIndex] = {
index ← ExistingConfiguration[[leaf:parent, extension:stateNo]];
IF index = NullIndex
THEN {
index ← Allocate[parent, pred, 0, stateNo];
SELECT parseMode
FROM
ATree => {tree[index].aLeaf ← TRUE; LinkHash[index]};
BTree => {tree[index].bLeaf ← TRUE; LinkHash[index]};
ENDCASE => NULL};
RETURN};
parsing simulation
ExtState: TYPE = [FIRST[State] .. LAST[State]+1];
NullState: ExtState = LAST[ExtState];
StackRep:
TYPE =
RECORD[
leaf: NodeIndex,
extension: ExtState];
GetNTEntry:
PROC [state: State, lhs: NTSymbol]
RETURNS [ActionEntry] = {
IF state <=
LAST[NTState]
THEN {
nI: NTIndex ← nStart[state];
FOR nI
IN [nI..nI+nLength[state])
DO IF lhs = nSymbol[nI] THEN RETURN [nAction[nI]] ENDLOOP};
RETURN [ntDefaults[lhs]]};
ActOnStack:
PROC [stack: StackRep, action: ActionEntry, nScanned: [0..1]]
RETURNS [StackRep] = {
currentNode, thread: NodeIndex ← stack.leaf;
count: CARDINAL ← nScanned;
currentState: State;
IF stack.extension = NullState
THEN currentState ← tree[currentNode].state
ELSE {currentState ← stack.extension; count ← count + 1};
UNTIL action.tag = Scan
DO
IF count > action.tag.pLength
-- can be one greater
THEN {
currentNode ← FindNode[currentNode, thread, currentState];
count ← count - 1};
UNTIL count = action.tag.pLength
DO currentNode ← tree[currentNode].father; count ← count + 1 ENDLOOP;
currentState ← tree[currentNode].state; count ← 1;
action ← GetNTEntry[currentState, prodData[action.transition].lhs];
ENDLOOP;
IF count > 1
THEN currentNode ← FindNode[currentNode, thread, currentState];
stack.leaf ← currentNode; stack.extension ← action.transition;
RETURN [stack]};
ParseStep:
PROC [stack: StackRep, tSmb: TSymbol]
RETURNS [StackRep] = {
currentState: State ←
IF stack.extension = NullState
THEN tree[stack.leaf].state
ELSE stack.extension;
scanned: BOOLEAN ← FALSE;
WHILE ~scanned
DO
action: ActionEntry;
count: [0..1];
tI: TIndex ← tStart[currentState];
FOR tI
IN [tI..tI+tLength[currentState])
DO
SELECT tSymbol[tI] FROM tSmb, DefaultMarker => EXIT ENDCASE;
REPEAT
FINISHED => RETURN [[NullIndex, NullState]];
ENDLOOP;
action ← tAction[tI];
IF ~action.tag.reduce
THEN {count ← 1; scanned ← TRUE} -- shift or shift reduce
ELSE count ← 0;
stack ← ActOnStack[stack, action, count];
currentState ← stack.extension;
ENDLOOP;
RETURN [stack]};
text buffer management
Insert: TYPE = ARRAY [0 .. 1+InsertLimit) OF P1.Token;
newText: REF Insert;
insertCount: CARDINAL;
Buffer:
TYPE =
ARRAY [0 .. 1 + DiscardLimit + (MaxScanLimit+InsertLimit)) OF P1.Token;
sourceText: REF Buffer;
scanBase, scanLimit: CARDINAL;
Advance:
PROC [errPut:
IO.
STREAM] =
{sourceText[scanLimit] ← input[errPut]; scanLimit ← scanLimit+1};
Discard: PROC = {scanBase ← scanBase+1};
UnDiscard: PROC = {scanBase ← scanBase-1};
RecoverInput:
PROC [errPut:
IO.
STREAM]
RETURNS [token: P1.Token] = {
IF insertCount <= InsertLimit
THEN {
token ← newText[insertCount];
IF (insertCount ← insertCount+1) > InsertLimit
THEN newText ← NIL}
ELSE {
token ← sourceText[scanBase];
IF (scanBase ← scanBase+1) = scanLimit
THEN {sourceText ← NIL; input ← P1.Atom}};
RETURN};
acceptance checking
best:
RECORD [
nAccepted: CARDINAL,
nPassed: [0..1],
node: NodeIndex,
mode: ParsingMode,
nDiscards: CARDINAL];
RightScan:
PROC [node: NodeIndex]
RETURNS [stop:
BOOLEAN] = {
savedNextNode: NodeIndex = nextNode;
savedMode: ParsingMode = parseMode;
savedLimit: CARDINAL = treeLimit;
stack: StackRep ← [leaf:node, extension:NullState];
state: State ← tree[node].state;
nAccepted: CARDINAL ← 0;
parseMode ← Checking; treeLimit ← TreeSize;
FOR i:
CARDINAL
IN [scanBase .. scanLimit)
DO
IF state = FinalState
THEN {
nAccepted ←
IF (sourceText[i].class = EndMarker)
THEN scanLimit-scanBase
ELSE 0;
EXIT};
stack ← ParseStep[stack, sourceText[i].class];
IF stack.leaf = NullIndex THEN EXIT;
nAccepted ← nAccepted + 1; state ← stack.extension;
ENDLOOP;
nextNode ← savedNextNode; treeLimit ← savedLimit;
SELECT (parseMode ← savedMode)
FROM
ATree =>
IF nAccepted + 1 > best.nAccepted + best.nPassed
THEN best ← [nAccepted, 1, node, ATree, scanBase-1];
BTree =>
IF nAccepted > best.nAccepted + best.nPassed
THEN best ← [nAccepted, 0, node, BTree, scanBase];
ENDCASE;
RETURN [nAccepted >= MaxScanLimit]};
strategy management
RowRecord:
TYPE =
RECORD [
index, limit: CARDINAL,
stack: StackRep,
next: RowHandle];
RowHandle: TYPE = REF RowRecord;
NextRow:
PROC [list: RowHandle]
RETURNS [row: RowHandle] = {
t: TSymbol;
row ← NIL;
FOR r: RowHandle ← list, r.next
UNTIL r =
NIL
DO
IF r.index < r.limit
THEN {
s: TSymbol = tSymbol[r.index];
IF row = NIL OR s < t THEN {row ← r; t ← s}};
ENDLOOP;
RETURN};
Position: TYPE = {after, before};
Length: TYPE = CARDINAL [0..InsertLimit];
levelStart, levelEnd: ARRAY Position OF ARRAY Length OF NodeIndex;
AddLeaf:
PROC [stack: StackRep, s: TSymbol, thread: NodeIndex]
RETURNS [stop: BOOLEAN] = {
saveNextNode: NodeIndex = nextNode;
stack ← ParseStep[stack, s];
IF stack.leaf = NullIndex
OR ExistingConfiguration[stack] # NullIndex
THEN {nextNode ← saveNextNode; stop ← FALSE}
ELSE {
newLeaf: NodeIndex = Allocate[stack.leaf, thread, s, stack.extension];
SELECT parseMode
FROM
ATree => tree[newLeaf].aLeaf ← TRUE;
BTree => tree[newLeaf].bLeaf ← TRUE;
ENDCASE => ERROR;
LinkHash[newLeaf];
stop ← RightScan[newLeaf]};
RETURN};
GrowTree:
PROC [p: Position, n: Length]
RETURNS [stop:
BOOLEAN] = {
tI, tLimit: TIndex;
stack: StackRep;
state: State;
rowList, r: RowHandle;
rowList ← NIL;
FOR i: NodeIndex
IN [levelStart[p][n-1] .. levelEnd[p][n-1])
DO
IF tree[i].symbol # 0
OR n = 1
THEN {
rowList ← NIL;
stack ← [leaf:i, extension:NullState]; state ← tree[i].state;
DO
tI ← tStart[state]; tLimit ← tI + tLength[state];
r ← NEW[RowRecord ← [index: tI, limit: tLimit, stack: stack, next: rowList]];
rowList ← r;
IF tI = tLimit OR tSymbol[tLimit-1] # DefaultMarker THEN EXIT;
r.limit ← r.limit - 1;
stack ← ActOnStack[stack, tAction[tLimit-1], 0];
state ← stack.extension;
ENDLOOP;
UNTIL (r ← NextRow[rowList]) =
NIL
DO
IF AddLeaf[r.stack, tSymbol[r.index], i] THEN GO TO found;
r.index ← r.index + 1;
ENDLOOP};
REPEAT
found => stop ← TRUE;
FINISHED => stop ← FALSE;
ENDLOOP;
rowList ← NIL;
RETURN};
CheckTree:
PROC [p: Position, n: Length]
RETURNS [stop:
BOOLEAN] = {
FOR i: NodeIndex
IN [levelStart[p][n] .. levelEnd[p][n])
DO
ENABLE TreeFull => CONTINUE;
IF RightScan[i] THEN GO TO found;
REPEAT
found => stop ← TRUE;
FINISHED => stop ← FALSE;
ENDLOOP;
RETURN};
Accept:
PROC [put:
IO.
STREAM]
RETURNS [success:
BOOL] = {
s: TSymbol;
discardBase: CARDINAL = best.nPassed;
insertCount ← 1+InsertLimit;
FOR p: NodeIndex ← best.node, tree[p].last
WHILE p > rTop
DO
IF (s ← tree[p].symbol) # 0
THEN {
insertCount ← insertCount-1;
newText[insertCount] ← P1.Token[s, P1.NullValue, inputLoc]};
ENDLOOP;
scanBase ← discardBase;
IF best.nDiscards # 0
THEN {
put.PutRope["Text deleted is: "];
FOR j:
CARDINAL
IN [1 .. best.nDiscards]
DO
TypeSym[sourceText[scanBase].class, put]; scanBase ← scanBase + 1;
ENDLOOP};
IF insertCount <= InsertLimit
THEN {
IF scanBase # discardBase THEN put.PutChar['\n];
put.PutRope["Text inserted is: "];
FOR j:
CARDINAL
IN [insertCount .. InsertLimit]
DO TypeSym[newText[j].class, put] ENDLOOP};
IF discardBase = 1
THEN {insertCount ← insertCount-1; newText[insertCount] ← sourceText[0]};
IF insertCount > InsertLimit THEN newText ← NIL;
IF scanBase + best.nAccepted < scanLimit
THEN success ← P1.ResetScanIndex[sourceText[scanBase+best.nAccepted].index]
ELSE success ← TRUE;
scanLimit ← scanBase + best.nAccepted;
input ← RecoverInput};
TypeSym:
PROC [sym: TSymbol, put:
IO.
STREAM] = {
OPEN tablePtr.scanTable;
vocab: LONG STRING = LOOPHOLE[@vocabBody];
put.PutChar[' ];
IF sym
NOT
IN [1..EndMarker)
THEN put.Put[IO.int[sym]]
ELSE
FOR i:
CARDINAL
IN [vocabIndex[sym-1]..vocabIndex[sym])
DO put.PutChar[vocab[i]] ENDLOOP};
stack node indices
rTop: NodeIndex;
Recover:
PROC [errPut:
IO.
STREAM] = {
ModeMap: ARRAY Position OF ParsingMode = [ATree, BTree];
stack: StackRep;
treeLimit ← TreeSize - CheckSize;
hashTable^ ← ALL[NullIndex];
rTop ← NullIndex; nextNode ← maxNode ← 1;
best.nAccepted ← 0; best.nPassed ← 1; best.mode ← ATree;
sourceText[0] ← lastToken;
sourceText[1] ← P1.Token[inputSymbol, inputValue, inputLoc];
scanBase ← 1; scanLimit ← 2;
THROUGH [1 .. MaxScanLimit) DO Advance[errPut] ENDLOOP;
FOR i:
CARDINAL
IN [0 .. top)
DO rTop ← Allocate[rTop, rTop, 0, s[i]] ENDLOOP;
parseMode ← BTree;
levelStart[before][0] ← rTop ← FindNode[rTop, rTop, s[top]];
tree[rTop].bLeaf ← TRUE;
levelEnd[before][0] ← nextNode;
parseMode ← ATree;
stack ← ParseStep[[leaf:rTop, extension:NullState], lastToken.class];
rTop ← FindNode[stack.leaf, rTop, stack.extension];
tree[rTop].symbol ← lastToken.class;
tree[rTop].aLeaf ← tree[rTop].bLeaf ← TRUE;
levelStart[after][0] ← rTop; levelEnd[after][0] ← nextNode;
FOR level: Length
IN [1 ..
LAST[Length]]
DO
FOR place: Position
IN Position
DO
parseMode ← ModeMap[place];
IF place = before THEN UnDiscard[];
try simple insertion (inserts=level)
levelStart[place][level] ← nextNode;
IF GrowTree[place, level !TreeFull => CONTINUE] THEN GO TO found;
levelEnd[place][level] ← nextNode;
try discards followed by 0 or more insertions
THROUGH [1 .. level)
DO
Discard[]; IF CheckTree[place, level] THEN GO TO found;
ENDLOOP;
Discard[];
IF place = after THEN Advance[errPut];
FOR inserts:
CARDINAL
IN [0 .. level]
DO IF CheckTree[place, inserts] THEN GO TO found ENDLOOP;
undo discards at this level
THROUGH [1..level] DO UnDiscard[] ENDLOOP;
IF place = before THEN Discard[];
ENDLOOP;
REPEAT
found => NULL;
FINISHED => {
threshold: CARDINAL ← (MinScanLimit+MaxScanLimit)/2;
THROUGH [1..LAST[Length]] DO Discard[]; Advance[errPut] ENDLOOP;
UNTIL scanBase > DiscardLimit
DO
IF best.nAccepted >= threshold THEN GO TO found;
Discard[];
FOR inserts:
CARDINAL
IN Length
DO
FOR place: Position
IN Position
DO
parseMode ← ModeMap[place];
IF place = before THEN UnDiscard[];
IF CheckTree[place, inserts] THEN GO TO found;
IF place = before THEN Discard[];
ENDLOOP;
ENDLOOP;
Advance[errPut];
threshold ← IF threshold > MinScanLimit THEN threshold-1 ELSE MinScanLimit;
REPEAT
found => NULL;
FINISHED =>
IF best.nAccepted < MinScanLimit
THEN {best.mode ← ATree; best.nPassed ← 1};
ENDLOOP};
ENDLOOP};
SyntaxError:
PROC [abort:
BOOL, put:
IO.
STREAM]
RETURNS [success:
BOOL] = {
IF abort
THEN {
P1.ErrorContext["Syntax Error", inputLoc, put];
put.PutRope["... Parse abandoned."]; put.PutChar['\n];
success ← FALSE}
ELSE {
sourceText ← NEW[Buffer];
newText ← NEW[Insert];
tree ← NEW[ARRAY [0..TreeSize) OF StackNode];
hashTable ← NEW[ARRAY [0..HashSize) OF NodeIndex];
Recover[put ! TreeFull => CONTINUE];
hashTable ← NIL;
P1.ErrorContext["Syntax Error",
sourceText[IF best.mode=BTree THEN 0 ELSE 1].index, put];
IF ~(success ← best.nAccepted >= MinScanLimit)
OR ~Accept[put]
THEN {
put.PutRope["No recovery found."];
newText ← NIL; sourceText ← NIL};
tree ← NIL;
put.PutChar['\n]};
put.PutChar['\n];
RETURN};
END.