MPParser.mesa
Copyright Ó 1985, 1986, 1987, 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
derived from Compiler>Parser.Mesa
Satterthwaite, January 12, 1981 12:58 PM
Russ Atkinson (RRA) January 19, 1987 7:48:58 pm PST
JKF May 24, 1990 9:18:48 am PDT
Michael Plass, September 5, 1991 11:44 pm PDT
DIRECTORY
IO USING [Put1, PutRope, PutChar, STREAM],
MPP1 USING [Token, Value, ValueSeq, ValueStack, nullValue, nullToken, INTSeq, ActionEntrySeq, AssignDescriptors, Atom, ErrorContext, ProcessQueue, ResetScanIndex, ScanInit, ScanReset],
MPParseTable USING [ActionEntry, ActionTag, defaultMarker, endMarker, finalState, IndexTableRef, initialState, initialSymbol, InitIndexTable, InitNActions, InitNLengths, InitNStarts, InitNSymbols, InitNTDefaults, InitProdData, InitTActions, InitTLengths, InitTStarts, InitTSymbols, InitVocabulary, NActionsRef, NLengthsRef, NStartsRef, NSymbolsRef, NTDefaultsRef, NTIndex, NTState, NTSymbol, ProdDataRef, State, TActionsRef, TIndex, TLengthsRef, TStartsRef, TSymbol, TSymbolsRef, VocabularyRef],
Rope USING [ROPE];
MPParser: PROGRAM
IMPORTS IO, MPP1, MPParseTable
EXPORTS MPP1 = {
OPEN MPParseTable;
globals
ErrorLimit: CARDINAL = 10;
Scan: ActionTag = [FALSE, 0];
inputSymbol: TSymbol;
input: PROC [errPut: IO.STREAM] RETURNS [token: MPP1.Token];
inputLoc: INT ¬ 0;
inputValue: MPP1.Value ¬ MPP1.nullValue;
lastToken: MPP1.Token ¬ MPP1.nullToken;
NullSymbol: TSymbol = 0;
firstInit: BOOL ¬ TRUE;
s: REF StateSeq ¬ NIL;
StateSeq: TYPE = RECORD[SEQUENCE length: CARDINAL OF State];
l: REF MPP1.INTSeq ¬ NIL;
v: MPP1.ValueStack ¬ NIL;
top: CARDINAL ¬ 0;
q: REF MPP1.ActionEntrySeq ¬ NIL;
qI: CARDINAL;
transition tables for terminal input symbols
vocabIndex: IndexTableRef ¬ NIL;
vocabBody: VocabularyRef ¬ NIL;
transition tables for terminal input symbols
tStart: TStartsRef ¬ NIL;
tLength: TLengthsRef ¬ NIL;
tSymbol: TSymbolsRef ¬ NIL;
tAction: TActionsRef ¬ NIL;
transition tables for nonterminal input symbols
nStart: NStartsRef ¬ NIL;
nLength: NLengthsRef ¬ NIL;
nSymbol: NSymbolsRef ¬ NIL;
nAction: NActionsRef ¬ NIL;
ntDefaults: NTDefaultsRef ¬ NIL;
production information
prodData: ProdDataRef ¬ NIL;
initialization/termination
ParseInit: PROC [source: Rope.ROPE] = {
IF vocabIndex = NIL THEN [vocabIndex, vocabBody] ¬ MPP1.ScanInit[source];
IF prodData = NIL THEN {
tStart ¬ InitTStarts[];
tLength ¬ InitTLengths[];
tSymbol ¬ InitTSymbols[];
tAction ¬ InitTActions[];
nStart ¬ InitNStarts[];
nLength ¬ InitNLengths[];
nSymbol ¬ InitNSymbols[];
nAction ¬ InitNActions[];
ntDefaults ¬ InitNTDefaults[];
prodData ¬ InitProdData[];
};
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.ROPE, errPut: IO.STREAM] RETURNS [complete: BOOL, nTokens, nErrors: CARDINAL] = TRUSTED {
currentState: State;
i, valid, m: CARDINAL; -- stack pointers
action: ActionEntry;
ParseInit[source]; input ¬ MPP1.Atom;
nErrors ¬ 0; complete ¬ TRUE;
i ¬ top ¬ valid ¬ 0; qI ¬ 0;
s[0] ¬ currentState ¬ initialState; lastToken.class ¬ NullSymbol;
inputSymbol ¬ initialSymbol; inputValue ¬ MPP1.nullValue; inputLoc ¬ 0;
WHILE currentState # finalState DO
{
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;
MPP1.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)];
{
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];
EXITS
nFound => NULL;
};
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};
};
ENDLOOP;
MPP1.ProcessQueue[qI, top];
{n: CARDINAL; [nTokens, n] ¬ MPP1.ScanReset[]; nErrors ¬ nErrors + n};
RETURN};
ExpandStack: PROC [delta: CARDINAL] = {
newS: REF StateSeq;
newL: REF MPP1.INTSeq;
newV: MPP1.ValueStack ¬ NIL;
newSize: CARDINAL = (IF s = NIL THEN 0 ELSE s.length) + delta;
newS ¬ NEW[StateSeq[newSize]];
newL ¬ NEW[MPP1.INTSeq[newSize]];
newV ¬ IF v # NIL AND v.length >= newSize
THEN v
ELSE NEW[MPP1.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;
MPP1.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 MPP1.ActionEntrySeq ¬ NEW[MPP1.ActionEntrySeq[newSize]];
IF q # NIL THEN FOR i: CARDINAL IN [0..q.length) DO newQ[i] ¬ q[i] ENDLOOP;
q ¬ newQ;
MPP1.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.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 ¬ 0;
maxNode: NodeIndex ¬ 0;
treeLimit: CARDINAL ¬ 0;
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 ¬ Checking;
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 MPP1.Token;
newText: REF Insert;
insertCount: CARDINAL ¬ 0;
Buffer: TYPE =
ARRAY [0 .. 1 + DiscardLimit + (MaxScanLimit+InsertLimit)) OF MPP1.Token;
sourceText: REF Buffer;
scanBase, scanLimit: CARDINAL ¬ 0;
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: MPP1.Token ¬ MPP1.nullToken] = {
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 ¬ MPP1.Atom}};
RETURN};
acceptance checking
best: RECORD [
nAccepted: CARDINAL ¬ 0,
nPassed: [0..1] ¬ 0,
node: NodeIndex ¬ 0,
mode: ParsingMode ¬ Checking,
nDiscards: CARDINAL ¬ 0];
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 ¬ TSymbol.FIRST;
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: ARRAY Position OF ARRAY Length OF NodeIndex ¬ [ALL[0], ALL[0]];
levelEnd: ARRAY Position OF ARRAY Length OF NodeIndex ¬ [ALL[0], ALL[0]];
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] ¬ MPP1.Token[s, MPP1.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 ¬ MPP1.ResetScanIndex[sourceText[scanBase+best.nAccepted].index]
ELSE success ¬ TRUE;
scanLimit ¬ scanBase + best.nAccepted;
input ¬ RecoverInput};
TypeSym: PROC [sym: TSymbol, put: IO.STREAM] = {
put.PutChar[' ];
IF sym IN [1..endMarker)
THEN {
IF vocabIndex = NIL THEN vocabIndex ¬ InitIndexTable[];
IF vocabBody = NIL THEN vocabBody ¬ InitVocabulary[];
FOR i: NAT IN [vocabIndex[sym-1]..vocabIndex[sym]) DO
put.PutChar[vocabBody[i]];
ENDLOOP;
}
ELSE put.Put1[[integer[sym]]];
};
stack node indices
rTop: NodeIndex ¬ 0;
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] ¬ MPP1.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 {
MPP1.ErrorContext["Syntax Error", inputLoc, put];
put.PutRope["... Parse abandoned."]; put.PutChar['\n];
success ¬ FALSE}
ELSE {
sourceText ¬ NEW[Buffer ¬ ALL[MPP1.nullToken]];
newText ¬ NEW[Insert ¬ ALL[MPP1.nullToken]];
tree ¬ NEW[ARRAY [0..TreeSize) OF StackNode];
hashTable ¬ NEW[ARRAY [0..HashSize) OF NodeIndex];
Recover[put ! TreeFull => CONTINUE];
hashTable ¬ NIL;
MPP1.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;
vocabIndex ¬ NIL;
put.PutChar['\n]};
put.PutChar['\n];
RETURN};
}.