DIRECTORY IO: TYPE USING [char, int, Put, PutChar, PutRope, rope, STREAM, TAB], P1: TYPE USING [ ActionSeq, LinkSeq, StateSeq, Token, Value, ValueSeq, nullValue, AssignDescriptors, Atom, ErrorContext, InstallScanTable, ProcessQueue, ResetScanIndex, ScanInit, ScanReset, TokenValue], ParseTable: TYPE USING [ ActionEntry, ActionTag, NActionsRef, NLengthsRef, NStartsRef, NSymbolsRef, NTDefaultsRef, NTIndex, NTState, NTSymbol, ProdDataRef, State, TableRef, TActionsRef, TIndex, TLengthsRef, TStartsRef, TSymbol, TSymbolsRef, defaultMarker, endMarker, initialState, finalState, initialSymbol], Rope: TYPE USING [ROPE]; Parser: PROGRAM IMPORTS IO, P1 EXPORTS P1 = { OPEN ParseTable; tablePtr: ParseTable.TableRef; tStart: TStartsRef; tLength: TLengthsRef; tSymbol: TSymbolsRef; tAction: TActionsRef; nStart: NStartsRef; nLength: NLengthsRef; nSymbol: NSymbolsRef; nAction: NActionsRef; ntDefaults: NTDefaultsRef; prodData: ProdDataRef; InstallParseTable: PUBLIC PROC [base: ParseTable.TableRef] = { tablePtr _ base; tStart _ @tablePtr[tablePtr.parseTable.tStart]; tLength _ @tablePtr[tablePtr.parseTable.tLength]; tSymbol _ @tablePtr[tablePtr.parseTable.tSymbol]; tAction _ @tablePtr[tablePtr.parseTable.tAction]; nStart _ @tablePtr[tablePtr.parseTable.nStart]; nLength _ @tablePtr[tablePtr.parseTable.nLength]; nSymbol _ @tablePtr[tablePtr.parseTable.nSymbol]; nAction _ @tablePtr[tablePtr.parseTable.nAction]; ntDefaults _ @tablePtr[tablePtr.parseTable.ntDefaults]; prodData _ @tablePtr[tablePtr.parseTable.prodData]; P1.InstallScanTable[base]}; errorLimit: NAT = 25; scanTag: ActionTag = [FALSE, 0]; inputSymbol: TSymbol; Input: PROC RETURNS [token: P1.Token]; inputLoc: CARDINAL; inputValue: P1.Value; lastToken: P1.Token; nullSymbol: TSymbol = 0; s: REF P1.StateSeq; l: LONG POINTER TO P1.LinkSeq; lREF: REF P1.LinkSeq; -- NOTE sharing with l v: LONG POINTER TO P1.ValueSeq; vREF: REF P1.ValueSeq; -- NOTE sharing with v top: CARDINAL; q: LONG POINTER TO P1.ActionSeq; qREF: REF P1.ActionSeq; -- NOTE sharing with q qI: CARDINAL; ParseInit: PROC = INLINE { s _ NIL; q _ NIL; qREF _ NIL; q _ NIL; ExpandStack[500]; ExpandQueue[250]; scanBuffer _ NIL}; ParseReset: PROC = INLINE { qREF _ NIL; q _ NIL; EraseStack[]; scanBuffer _ NIL}; InputLoc: PUBLIC PROC RETURNS [CARDINAL] = {RETURN [inputLoc]}; -- * * * * Main Parsing Procedures * * * * -- Parse: PUBLIC PROC [ source: IO.STREAM, logger: PROC [PROC [log: IO.STREAM]]] RETURNS [complete: BOOL, nTokens, nErrors: NAT] = { currentState: State; i, valid, m: CARDINAL; -- stack pointers action: ActionEntry; ParseInit[]; P1.ScanInit[source, logger]; 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 => GO TO SyntaxError; ENDLOOP; action _ tAction[tI]; IF ~action.tag.reduce THEN { -- scan or scan reduce entry 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[256]; lastToken.class _ inputSymbol; v[i] _ inputValue; l[i] _ inputLoc; [[inputSymbol, inputValue, inputLoc]] _ Input[]}; WHILE action.tag # scanTag DO IF qI >= q.length THEN ExpandQueue[256]; 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 <= NTState.LAST 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; END; i _ i+1; ENDLOOP; IF (m _ top+(i-valid)) >= s.length THEN ExpandStack[256]; s[m] _ currentState _ action.transition; EXITS SyntaxError => { lastToken.value _ v[top]; lastToken.index _ l[top]; top _ top - 1; complete _ SyntaxError[logger, (nErrors_nErrors+1)>errorLimit]; i _ valid _ top; qI _ 0; lastToken.class _ nullSymbol; currentState _ s[i]; [[inputSymbol, inputValue, inputLoc]] _ Input[]; IF ~complete THEN EXIT}; END; ENDLOOP; P1.ProcessQueue[qI, top]; nErrors _ nErrors + ([nTokens: nTokens] _ P1.ScanReset[]).nErrors; ParseReset[]; RETURN}; ExpandStack: PROC [delta: NAT] = { oldSize: NAT = IF s = NIL THEN 0 ELSE s.length; newSize: NAT = oldSize + delta; newS: REF P1.StateSeq = NEW[P1.StateSeq[newSize]]; newL: REF P1.LinkSeq = NEW[P1.LinkSeq[newSize]]; newV: REF P1.ValueSeq = NEW[P1.ValueSeq[newSize]]; FOR i: NAT IN [0..oldSize) DO newS[i] _ s[i]; newL[i] _ l[i]; newV[i] _ v[i] ENDLOOP; EraseStack[]; s _ newS; lREF _ newL; l _ LOOPHOLE[lREF, LONG POINTER TO P1.LinkSeq]; vREF _ newV; v _ LOOPHOLE[vREF, LONG POINTER TO P1.ValueSeq]; P1.AssignDescriptors[qd:q, vd:v, ld:l, pp:prodData]}; EraseStack: PROC = { IF s # NIL THEN {vREF _ NIL; v _ NIL; lREF _ NIL; l _ NIL; s _ NIL}}; ExpandQueue: PROC [delta: NAT] = { oldSize: NAT = IF q = NIL THEN 0 ELSE q.length; newSize: NAT = oldSize + delta; newQ: REF P1.ActionSeq = NEW[P1.ActionSeq[newSize]]; FOR i: NAT IN [0..oldSize) DO newQ[i] _ q[i] ENDLOOP; qREF _ newQ; q _ LOOPHOLE[qREF, LONG POINTER TO P1.ActionSeq]; P1.AssignDescriptors[qd:q, vd:v, ld:l, pp:prodData]; }; -- * * * * Error Recovery Section * * * * -- errorStream: IO.STREAM _ NIL; minScanLimit: NAT = 4; maxScanLimit: NAT = 12; insertLimit: NAT = 2; discardLimit: NAT = 10; treeSize: NAT = 250; checkSize: NAT = maxScanLimit+insertLimit+2; ParserID: PUBLIC PROC RETURNS [Rope.ROPE] = {RETURN [NIL]}; track: BOOL = FALSE; DisplayNode: PROC [n: NodeIndex] = { IF track THEN { OPEN IO; PutRope[errorStream, "::new node::"]; Put[errorStream, IO.char[IO.TAB], IO.int[n]]; Put[errorStream, IO.char[IO.TAB], IO.int[tree[n].father]]; Put[errorStream, IO.char[IO.TAB], IO.int[tree[n].last]]; Put[errorStream, IO.char[IO.TAB], IO.int[tree[n].state]]; Put[errorStream, IO.char[IO.TAB]]; TypeSym[tree[n].symbol]; NewLine[]}}; NodeIndex: TYPE = NAT [0..treeSize); nullIndex: NodeIndex = 0; StackNode: TYPE = RECORD[ father: NodeIndex, last: NodeIndex, state: State, symbol: TSymbol, aLeaf, bLeaf: BOOL, link: NodeIndex]; TreeSpace: TYPE = ARRAY [0..treeSize) OF StackNode; tree: REF TreeSpace; nextNode: NAT [0..treeSize]; maxNode: NodeIndex; treeLimit: NAT [0..treeSize]; TreeFull: ERROR = CODE; Allocate: PROC [parent, pred: NodeIndex, terminal: TSymbol, stateNo: State] RETURNS [index: NodeIndex] = { IF (index _ nextNode) >= treeLimit THEN ERROR 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: NAT = 250; -- should depend on state count ? HashIndex: TYPE = [0..hashSize); HashSpace: TYPE = ARRAY HashIndex OF NodeIndex; hashTable: REF HashSpace; HashValue: PROC [s: State] RETURNS [HashIndex] = INLINE { RETURN [s MOD hashSize]}; ParsingMode: TYPE = {aTree, bTree, checking}; parseMode: ParsingMode; LinkHash: PROC [n: NodeIndex] = { htIndex: HashIndex = HashValue[tree[n].state]; tree[n].link _ hashTable[htIndex]; hashTable[htIndex] _ n}; DelinkHash: PROC [n: NodeIndex] = { htIndex: HashIndex = HashValue[tree[n].state]; p: NodeIndex _ nullIndex; FOR i: NodeIndex _ hashTable[htIndex], tree[i].link UNTIL i = nullIndex DO IF i = n THEN GO TO delete; p _ i; REPEAT delete => IF p = nullIndex THEN hashTable[htIndex] _ tree[n].link ELSE tree[p].link _ tree[n].link; ENDLOOP}; ExistingConfiguration: PROC [stack: StackRep] RETURNS [NodeIndex] = { htIndex: HashIndex; aTree: BOOL; SELECT parseMode FROM $aTree => aTree _ TRUE; $bTree => aTree _ FALSE; ENDCASE => RETURN [nullIndex]; htIndex _ HashValue[stack.extension]; FOR i: NodeIndex _ hashTable[htIndex], tree[i].link UNTIL i = nullIndex DO IF (IF aTree THEN tree[i].aLeaf ELSE tree[i].bLeaf) THEN { s1: State _ stack.extension; s2: State _ tree[i].state; n1: NodeIndex _ stack.leaf; n2: NodeIndex _ tree[i].father; DO IF s1 # s2 THEN EXIT; IF n1 = n2 THEN RETURN [i]; 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}; TrimTree: PROC [newNext: NodeIndex] = { WHILE nextNode > newNext DO nextNode _ nextNode-1; DelinkHash[nextNode] ENDLOOP}; ExtState: TYPE = [State.FIRST .. State.LAST+1]; nullState: ExtState = ExtState.LAST; StackRep: TYPE = RECORD[ leaf: NodeIndex, extension: ExtState]; GetNTEntry: PROC [state: State, lhs: NTSymbol] RETURNS [ActionEntry] = { IF state <= NTState.LAST 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: NAT _ nScanned; currentState: State; IF stack.extension = nullState THEN currentState _ tree[currentNode].state ELSE {currentState _ stack.extension; count _ count + 1}; UNTIL action.tag = scanTag DO IF count > action.tag.pLength THEN { -- can be one greater 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, input: TSymbol] RETURNS [StackRep] = { currentState: State _ IF stack.extension = nullState THEN tree[stack.leaf].state ELSE stack.extension; scanned: BOOL _ 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 input, 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]}; Insert: TYPE = ARRAY [0 .. 1+insertLimit) OF P1.Token; newText: REF Insert; insertCount: NAT; Buffer: TYPE = ARRAY [0 .. 1+discardLimit+(maxScanLimit+insertLimit)) OF P1.Token; scanBuffer: REF Buffer; scanBase, scanLimit: NAT; Advance: PROC = {scanBuffer[scanLimit] _ Input[]; scanLimit _ scanLimit+1}; Discard: PROC = { IF track THEN { IO.PutRope[errorStream, "::discarding symbol: "]; TypeSym[scanBuffer[scanBase].class]; NewLine[]}; scanBase _ scanBase+1}; UnDiscard: PROC = { scanBase _ scanBase-1; IF track THEN { IO.PutRope[errorStream, "::recovering symbol: "]; TypeSym[scanBuffer[scanBase].class]; NewLine[]}}; RecoverInput: PROC RETURNS [token: P1.Token] = { IF insertCount <= insertLimit THEN { token _ newText[insertCount]; IF (insertCount _ insertCount+1) > insertLimit THEN newText _ NIL} ELSE { token _ scanBuffer[scanBase]; IF (scanBase _ scanBase+1) = scanLimit THEN { scanBuffer _ NIL; Input _ P1.Atom}}; RETURN}; best: RECORD [ nAccepted: NAT, nPassed: [0..1], node: NodeIndex, mode: ParsingMode, nDiscards: NAT]; RightScan: PROC [node: NodeIndex] RETURNS [stop: BOOL] = { savedNextNode: NodeIndex = nextNode; savedMode: ParsingMode = parseMode; savedLimit: NAT = treeLimit; stack: StackRep _ [leaf:node, extension:nullState]; state: State _ tree[node].state; nAccepted: NAT _ 0; parseMode _ $checking; treeLimit _ treeSize; FOR i: NAT IN [scanBase .. scanLimit) DO IF state = finalState THEN { nAccepted _ IF (scanBuffer[i].class = endMarker) THEN scanLimit-scanBase ELSE 0; EXIT}; stack _ ParseStep[stack, scanBuffer[i].class]; IF stack.leaf = nullIndex THEN EXIT; nAccepted _ nAccepted + 1; state _ stack.extension; ENDLOOP; TrimTree[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]}; RowRecord: TYPE = RECORD [ index, limit: NAT, 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 = NAT [0..insertLimit]; levelStart, levelEnd: ARRAY Position OF ARRAY Length OF NodeIndex; AddLeaf: PROC [stack: StackRep, s: TSymbol, thread: NodeIndex] RETURNS [stop: BOOL] = { saveNextNode: NodeIndex = nextNode; stack _ ParseStep[stack, s]; IF stack.leaf = nullIndex OR ExistingConfiguration[stack] # nullIndex THEN { TrimTree[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]; IF track THEN DisplayNode[newLeaf]; stop _ RightScan[newLeaf]}; RETURN}; GrowTree: PROC [p: Position, n: Length] RETURNS [stop: BOOL] = { rowList: RowHandle _ NIL; IF track THEN { IO.Put[errorStream, IO.rope["::generating length: "], IO.int[n]]; IO.PutChar[errorStream, IF p = $before THEN 'B ELSE 'A]; NewLine[]}; FOR i: NodeIndex IN [levelStart[p][n-1] .. levelEnd[p][n-1]) DO IF tree[i].symbol # 0 OR n = 1 THEN { ENABLE UNWIND => {rowList _ NIL}; stack: StackRep _ [leaf:i, extension:nullState]; state: State _ tree[i].state; r: RowHandle; DO tI: TIndex = tStart[state]; tLimit: NAT = tI + tLength[state]; r _ NEW[RowRecord]; r^ _ 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; rowList _ NIL}; REPEAT found => stop _ TRUE; FINISHED => stop _ FALSE; ENDLOOP; rowList _ NIL; RETURN}; CheckTree: PROC [p: Position, n: Length] RETURNS [stop: BOOL] = { IF track THEN { IO.Put[errorStream, IO.rope["::checking length: "], IO.int[n]]; IO.PutChar[errorStream, IF p = $before THEN 'B ELSE 'A]; NewLine[]}; 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 RETURNS [success: BOOL] = { s: TSymbol; discardBase: NAT = 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.TokenValue[s], inputLoc]}; ENDLOOP; scanBase _ discardBase; IF best.nDiscards # 0 THEN { IO.PutRope[errorStream, "Text deleted is: "]; FOR j: NAT IN [1 .. best.nDiscards] DO TypeSym[scanBuffer[scanBase].class]; scanBase _ scanBase + 1; ENDLOOP}; IF insertCount <= insertLimit THEN { IF scanBase # discardBase THEN NewLine[]; IO.PutRope[errorStream, "Text inserted is: "]; FOR j: NAT IN [insertCount .. insertLimit] DO TypeSym[newText[j].class] ENDLOOP}; IF discardBase = 1 THEN {insertCount _ insertCount-1; newText[insertCount] _ scanBuffer[0]}; IF insertCount > insertLimit THEN newText _ NIL; IF scanBase + best.nAccepted < scanLimit THEN success _ P1.ResetScanIndex[scanBuffer[scanBase+best.nAccepted].index] ELSE success _ TRUE; scanLimit _ scanBase + best.nAccepted; Input _ RecoverInput}; TypeSym: PROC [sym: TSymbol] = { OPEN IO, t: tablePtr.scanTable; vocab: LONG STRING = LOOPHOLE[@tablePtr[t.vocabBody]]; PutChar[errorStream, ' ]; IF sym IN [1..endMarker) THEN FOR i: NAT IN [tablePtr[t.vocabIndex][sym-1]..tablePtr[t.vocabIndex][sym]) DO PutChar[errorStream, vocab[i]] ENDLOOP ELSE Put[errorStream, IO.int[sym]]}; rTop: NodeIndex; Recover: PROC = { 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; scanBuffer[0] _ lastToken; scanBuffer[1] _ P1.Token[inputSymbol, inputValue, inputLoc]; scanBase _ 1; scanLimit _ 2; THROUGH [1 .. maxScanLimit) DO Advance[] ENDLOOP; FOR i: NAT IN [0 .. top) DO rTop _ Allocate[rTop, rTop, 0, s[i]]; IF track THEN DisplayNode[rTop]; 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; IF track THEN DisplayNode[rTop]; FOR level: Length IN [1 .. Length.LAST] DO FOR place: Position IN Position DO parseMode _ ModeMap[place]; IF place = $before THEN UnDiscard[]; levelStart[place][level] _ nextNode; IF GrowTree[place, level ! TreeFull => {CONTINUE}] THEN GO TO found; levelEnd[place][level] _ nextNode; THROUGH [1 .. level) DO Discard[]; IF CheckTree[place, level] THEN GO TO found ENDLOOP; Discard[]; IF place = $after THEN Advance[]; FOR inserts: NAT IN [0 .. level] DO IF CheckTree[place, inserts] THEN GO TO found ENDLOOP; THROUGH [1..level] DO UnDiscard[] ENDLOOP; IF place = $before THEN Discard[]; ENDLOOP; REPEAT found => NULL; FINISHED => { threshold: NAT _ (minScanLimit+maxScanLimit)/2; THROUGH [1..Length.LAST] DO Discard[]; Advance[] ENDLOOP; UNTIL scanBase > discardLimit DO IF best.nAccepted >= threshold THEN GO TO found; Discard[]; FOR inserts: NAT 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[]; 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 [ logger: PROC [PROC [IO.STREAM]], abort: BOOL] RETURNS [success: BOOL] = { Inner: PROC [log: IO.STREAM] = { errorStream _ log; IF abort THEN { P1.ErrorContext[errorStream, "Syntax Error", inputLoc]; IO.PutRope[errorStream, "... Parse abandoned."]; NewLine[]; success _ FALSE} ELSE { scanBuffer _ NEW[Buffer]; newText _ NEW[Insert]; tree _ NEW[TreeSpace]; hashTable _ NEW[HashSpace]; Recover[ ! TreeFull => {CONTINUE}]; hashTable _ NIL; P1.ErrorContext[errorStream, "Syntax Error", scanBuffer[IF best.mode=$bTree THEN 0 ELSE 1].index]; IF ~(success _ best.nAccepted >= minScanLimit AND Accept[]) THEN { IO.PutRope[errorStream, "No recovery found."]; newText _ NIL; scanBuffer _ NIL}; tree _ NIL; NewLine[]}; NewLine[]; errorStream _ NIL; RETURN}; logger[Inner]; RETURN}; NewLine: PROC = {IO.PutChar[errorStream, '\n]}; }. œfile ProtoParser.mesa last modified by Satterthwaite, January 7, 1983 4:50 pm Last Edited by: Maxwell, August 11, 1983 2:02 pm Last Edited by: Paul Rovner, September 7, 1983 3:20 pm Cedar/Mesa parser with error recovery table installation transition tables for terminal input symbols transition tables for nonterminal input symbols production information parser state initialization/termination parameters of error recovery debugging tree management parsing simulation text buffer management acceptance checking strategy management stack node indices try simple insertion (inserts=level) try discards followed by 0 or more insertions undo discards at this level ʘJšœ™Jšœ7™7J™0J™6J˜šÏk ˜ Jš œœœ*œœ˜Ešœœœ˜J˜$J˜J˜FJ˜1—šœ œœ˜J˜JJ˜HJ˜CJšœC˜C—Jšœœœœ˜J˜—šœ˜Jšœœ˜Jšœ˜Jšœ%™%Jšœ ˜J˜—Jšœ™˜J˜J˜Jšœ,™,J˜J˜J˜J˜J˜J˜Jšœ/™/J˜J˜J˜J˜J˜J˜J˜Jšœ™J˜J˜J˜J˜šÏnœœœ ˜>J˜J˜/J˜1J˜1J˜1J˜/J˜1J˜1J˜1J˜7J˜3J˜J˜J˜——Jšœ ™ ˜Jšœ œ˜J˜Jšœœ˜ J˜J˜J˜Jšžœœœ˜&Jšœ œ˜J˜J˜J˜J˜J˜J˜J˜Jšœœœœ ˜JšœœÏc˜-J˜Jšœœœœ˜ JšœœŸ˜.J˜Jšœœ˜J˜Jšœœœœ˜ JšœœŸ˜/J˜Jšœœ˜ J˜J˜—Jšœ™˜šž œœœ˜Jš œœœ œœ'˜OJšœ œ˜J˜J˜—šž œœœ˜Jšœœœ˜$Jšœ œ˜J˜J˜—Jš žœœœœœœ ˜?J˜J˜—JšŸ.˜.˜šžœœœ˜Jšœœœ˜Jš œœœœœ˜%Jšœ œœ˜3J˜Jšœ œŸ˜)J˜J˜J˜ J˜.Jšœœ˜J˜J˜BJ˜GJ˜šœ˜"Jš˜J˜"šœœ$˜/Jšœ œœœ˜Cš˜Jšœœœ ˜—Jšœ˜J˜—J˜šœœŸ˜9šœœ˜Jš œœœ œœ˜AJ˜#—Jšœ%œ˜=J˜BJ˜2J˜—šœ˜Jšœœ˜(J˜J˜šœœ œœ˜CJš˜J˜0šœœœ˜&J˜#šœœ ˜+Jšœœœœ ˜?Jšœ˜ ——J˜š˜Jšœ œ˜—Jšœ˜—J˜Jšœ˜—Jšœ!œ˜9J˜(š˜˜J˜4J˜J˜@J˜8J˜J˜0Jšœ œœ˜——Jšœ˜—Jšœ˜J˜J˜J˜BJ˜ Jšœ˜J˜J˜—šž œœ œ˜"Jš œ œœœœœ ˜/Jšœ œ˜Jšœœœ˜2Jšœœœ˜0Jšœœœ˜2šœœœ˜Jšœ/œ˜7—J˜ Jšœ ˜ Jš œœœœœ ˜=Jš œœœœœ˜>J˜5J˜—šž œœ˜Jšœœœ œœ œœœ˜HJ˜—šž œœ œ˜"Jš œ œœœœœ ˜/Jšœ œ˜Jšœœœ˜4Jš œœœœœ˜5Jšœ ˜ Jš œœœœœ˜1J˜4J˜J˜—J˜—JšŸ,˜,˜Jšœ™˜Jšœ œœœ˜J˜Jšœœ˜Jšœœ˜Jšœ œ˜Jšœœ˜Jšœ œ˜Jšœ œ˜,J˜J˜—Jšœ ™ ˜Jšžœœœœœœœ˜;J˜Jšœœœ˜J˜šž œœ˜$šœœ˜Jšœœ˜J˜%Jš œœœœœ ˜-Jš œœœœœ˜;Jš œœœœœ˜8Jš œœœœœ˜9Jšœœœœ)˜HJ˜J˜———Jšœ™˜Jšœ œœ˜$J˜J˜šœ œœ˜J˜J˜J˜J˜Jšœœ˜J˜J˜—Jšœ œœœ ˜3Jšœœ ˜Jšœ œ˜J˜Jšœ œ˜Jšœ œœ˜J˜J˜šžœœ=˜KJšœ˜Jšœ!œœ ˜9Jšœ œ˜˜J˜J˜ J˜J˜Jšœœ œ˜J˜—Jšœœ˜ J˜J˜—Jšœ œŸ!˜6Jšœ œ˜ Jšœ œœ œ ˜/Jšœ œ ˜J˜šž œœ œœ˜9Jšœœ ˜J˜—Jšœ œ˜-J˜J˜šžœœ˜!J˜.J˜˜KJ˜šžœœ˜šœœ˜Jšœ/˜1J˜1—J˜J˜—šž œœ˜J˜šœœ˜Jšœ/˜1J˜2J˜——šž œœœ˜0šœœ˜$J˜Jšœ-œ˜B—šœ˜J˜šœ%œ˜-Jšœ œ˜$——Jšœ˜J˜J˜——Jšœ™˜šœœ˜Jšœ œ˜J˜J˜J˜Jšœ œ˜J˜—šž œœœœ˜:J˜$J˜#Jšœ œ ˜J˜3J˜ Jšœ œ˜J˜-šœœœ˜(šœœ˜šœ œ"˜0Jšœ˜Jšœ˜—Jšœ˜—J˜.Jšœœœ˜$J˜4Jšœ˜—J˜1šœ˜#˜ šœ/˜5J˜0——˜ šœ+˜1J˜.——Jšœ˜—Jšœ˜$J˜J˜——Jšœ™˜šœ œœ˜Jšœœ˜J˜J˜J˜—Jšœ œœ ˜ J˜šžœœœ˜Jšœœ˜J˜#J˜šœœ*œ˜LJšœœ˜&—šœ˜J˜Fšœ ˜Jšœ œ˜%Jšœ œ˜%Jšœœ˜—J˜Jšœœ˜#J˜—Jšœ˜J˜J˜—šžœœœœ˜@Jšœœ˜šœœ˜Jšœœ œ ˜AJšœœ œœ˜E—šœœ*˜?šœœœ˜%Jšœœ˜!J˜0J˜J˜ š˜J˜Jšœœ˜"Jšœœ ˜J˜BJ˜ Jšœ œ#œœ˜>J˜J˜0J˜Jšœ˜—šœœ˜%Jšœ'œœœ˜:J˜Jšœ˜—J˜—š˜Jšœœ˜Jšœ œ˜—Jšœ˜—Jšœœ˜J˜—šž œœœœ˜Ašœœ˜Jšœœœ ˜?Jšœœ œœ˜E—šœœ&˜;Jšœœ˜Jšœœœœ˜!š˜Jšœœ˜Jšœ œ˜—Jšœ˜—Jšœ˜J˜J˜—šžœœœ œ˜(J˜ Jšœ œ˜ J˜šœ(œ ˜<šœœ˜"J˜J˜@—Jšœ˜—J˜šœœ˜Jšœ+˜-šœœœ˜&J˜>Jšœ˜ ——šœœ˜$Jšœœ ˜)Jšœ,˜.šœœœ˜-Jšœœ˜#——JšœœE˜\Jšœœ˜0šœ'˜-J˜F—Jšœ œ˜J˜&J˜J˜—šžœœ˜ Jšœœ˜Jšœœœœ˜6J˜šœœ˜šœœœ>˜MJšœ˜&——Jšœœ ˜$J˜J˜———šœ™J˜J˜J˜šžœœ˜Jšœ œ œ ˜:J˜J˜J˜!Jšœ œ ˜J˜*J˜J˜;J˜J˜Jšœœ˜ J˜šœœœ˜*šœœ ˜"J˜Jšœœ ˜$Jšœ$™$J˜$Jš œ&œœœœ˜DJ˜"Jšœ-™-šœ˜Jš œ œœœœœ˜?—J˜ Jšœœ ˜!šœ œœ˜#Jš œœœœœ˜6—Jšœ™Jšœ œ œ˜*Jšœœ ˜"Jšœ˜—š˜Jšœ œ˜šœ˜ Jšœ œ!˜/Jšœ œœœ˜9šœ˜ Jšœœœœ˜0J˜ šœ œœ˜šœœ ˜"J˜Jšœœ ˜$Jšœœœœ˜.Jšœœ ˜"Jšœ˜—Jšœ˜—J˜ Jšœ œœ œ˜Kš˜Jšœ œ˜šœ˜ Jšœœ(˜M——Jšœ˜ ———Jšœ˜ J˜——šž œœ˜Jšœœœœœ œœ œ˜IJ˜šžœœœœ˜ J˜šœœ˜J˜7Jšœ:˜