-- file PGSLALR.mesa -- last modified by Satterthwaite, June 23, 1982 10:10 am DIRECTORY PGSConDefs: TYPE USING [ maxContexts, maxTabEntries, maxStateNum, outbufLim, pssLim, stateExt, tabExt, tokenSize, wordLength, bitstrsize, eofile, flags, ntentries, orCount, prodinfo, rhschar, slim, tentries, tokeninfo, totalTokens, warningsLogged, AcquireZone, closeoutstream, closewordstream, Expand, FindBit, FreeArray, InsertBit, MakeArray, openwordstream, OrBits, outchar, outeol, outnum, outstring, OutToken, outword, ReleaseZone, seterrstream, setoutstream, PGSFail], PGSTypes: TYPE USING [ AttrVec, BackChain, BitsInfo, BitString, ChainRec, ChainStack, ContextRec, FirstBits, HashHeads, HashHeadsRef, ItemRec, LongDes, ProdEntry, Stack, StateInfo, StateInfoRec, Table, TokenEntry]; PGSLALR: PROGRAM IMPORTS PGSConDefs EXPORTS PGSConDefs = { OPEN PGSConDefs; stateInfo: PGSTypes.StateInfo; table: PGSTypes.Table; lineWidth: CARDINAL; lalrSuccess: BOOL; entryLim: CARDINAL; -- index into table six: CARDINAL; -- six, the current state; slim in PGScon the next state number allocated hashHead: PGSTypes.HashHeadsRef; -- variables of the lookahead set calculation top, rlim: CARDINAL; -- global to all incarnations of the recursive procedure context predState, symbol: CARDINAL; -- local variables of context shared by all incarnations backChain: PGSTypes.BackChain; stack: PGSTypes.Stack; chainStack: PGSTypes.ChainStack; bitsInfo: PGSTypes.BitsInfo; bitString: PGSTypes.BitString; firstBits: PGSTypes.FirstBits; LALRGen: PUBLIC PROC RETURNS [BOOL] = { zone: UNCOUNTED ZONE ← AcquireZone[]; i, j, k, totalShifts, totalReduces, oldEntries, firstOrCount: CARDINAL; redEntries, maxRedEntries, defaultProd: CARDINAL; conflictFlag, reduceFlag, messageFlag: BOOL; conflicts: PGSTypes.Table; PrintHeader: PROC = { j, p: CARDINAL; outeol[2]; FOR i: CARDINAL DECREASING IN (stateInfo[six+1].nucleus..stateInfo[six].nucleus] DO [,j,p] ← table[i]; IF lineWidth = 0 THEN { outnum[six,4]; outchar[' ,1]; lineWidth ← tokenSize+5; IF p>0 THEN outchar[' ,tokenSize-OutToken[rhschar[prodinfo[p].index+j-1]]]}; IF lineWidth+9 > outbufLim THEN {outeol[1]; outchar[' ,lineWidth ← tokenSize+5]}; outnum[p,4]; outnum[j,3]; outchar['/,1]; outchar[' ,1]; ENDLOOP; outeol[1]}; PrintEntry: PROC [ item: PGSTypes.ItemRec, symmark: CARDINAL, sign: CHAR←'-] = { i: INTEGER; p, j: CARDINAL; IF item.tag = 2 THEN { outstring[" Reduce with "L]; outnum[item.pss,5,sign]; outeol[1]} ELSE { i ← item.pss; IF item.tag # 0 THEN i ← -i; IF symmark = 0 THEN { [,j,p] ← IF item.tag=0 THEN table[stateInfo[item.pss].nucleus] ELSE item; symmark ← rhschar[prodinfo[p].index+j-1]}; lineWidth ← lineWidth+tokenSize+8; IF lineWidth > outbufLim THEN {outeol[1]; lineWidth ← tokenSize+8}; outnum[i,5,sign]; outchar[' ,1]; outchar[' ,tokenSize+2-OutToken[symmark]]}}; PrintState: PROC = { i, j: CARDINAL; lineWidth ← 0; PrintHeader[]; lineWidth ← 0; i ← stateInfo[six].entries; WHILE i <stateInfo[six+1].entries DO IF table[i].tag # 3 THEN {PrintEntry[table[i],0]; i ← i+1} ELSE { FOR j ← i+1, j+1 WHILE table[j].tag = 3 DO NULL ENDLOOP; FOR k: CARDINAL IN [i..j) DO PrintEntry[table[j], table[k].pss] ENDLOOP; i ← j+1}; ENDLOOP}; LalrHeader: PROC = { IF ~messageFlag THEN { messageFlag ← TRUE; seterrstream[]; outstring["\nLALR(1) Tables\n"L];}; IF ~conflictFlag THEN {conflictFlag ← TRUE; lineWidth ← 0; PrintHeader[]}}; lalrSuccess ← TRUE; orCount ← 0; -- make arrays with all entries zeroed stateInfo ← LOOPHOLE[MakeArray[maxStateNum+2,SIZE[PGSTypes.StateInfoRec]]]; table ← LOOPHOLE[MakeArray[maxTabEntries+1,SIZE[PGSTypes.ItemRec]]]; hashHead ← zone.NEW[PGSTypes.HashHeads ← ALL[0]]; stateInfo[0].nucleus←maxTabEntries; table[maxTabEntries] ← [0,1,0]; --final state stateInfo[1].nucleus←maxTabEntries-1; table[maxTabEntries-1] ← [0,0,0];--initial state stateInfo[2].nucleus←maxTabEntries-2; slim ← 2; -- the sets of p,j components defining the LR(0) states are built at the end of table; -- the nucleus field of each state indexes the appropriate set. -- the entries for states 1,2,... are built at the beginning of table stateInfo[1].entries ← entryLim ← totalShifts ← totalReduces ← 0; IF flags[printLR] THEN {setoutstream[".lr"L]; outstring["\nLR(0) TABLES"L]}; FOR six ← 1, six+1 WHILE six < slim DO ProcessState[]; stateInfo[six+1].entries ← entryLim; IF flags[printLR] THEN PrintState[]; -- LR(0) tables are only a testing aid FOR i IN [stateInfo[six].entries..stateInfo[six+1].entries) DO SELECT table[i].tag FROM 0 => totalShifts ← totalShifts+1; 2 => totalReduces ← totalReduces+1; ENDCASE; ENDLOOP ENDLOOP; IF flags[printLR] THEN outeol[1]; closeoutstream[]; IF ~flags[lists] AND ~flags[printLALR] THEN RETURN [FALSE]; -- now form inverse of shift transitions for the lookahead sets caculation backChain ← LOOPHOLE[MakeArray[totalShifts+1, SIZE[PGSTypes.ChainRec]]]; FOR six IN [0..slim) DO stateInfo[six].link ← 0 ENDLOOP; k ← 1; FOR six IN [1..slim) DO FOR i IN [stateInfo[six].entries..stateInfo[six+1].entries) DO IF table[i].tag = 0 THEN { -- transition from six to table[i].pss backChain[k].state ← six; backChain[k].link ← stateInfo[table[i].pss].link; stateInfo[table[i].pss].link ← k; k ← k+1}; ENDLOOP; ENDLOOP; -- LALR(1) calculation begins here bitstrsize ← (eofile+wordLength-1)/wordLength; firstBits ← LOOPHOLE[MakeArray[totalTokens-eofile+1,bitstrsize]]; FirstSet[]; firstOrCount ← orCount; hashHead↑ ← ALL[0]; -- used by find bitsInfo ← LOOPHOLE[MakeArray[maxContexts, SIZE[PGSTypes.ContextRec]]]; rlim ← 1; bitString ← LOOPHOLE[MakeArray[maxContexts, bitstrsize]]; stack ← LOOPHOLE[MakeArray[30,SIZE[CARDINAL]]]; top ← 0; chainStack ← LOOPHOLE[MakeArray[90,SIZE[CARDINAL]]]; conflicts ← LOOPHOLE[MakeArray[totalTokens+1,SIZE[PGSTypes.ItemRec]]]; messageFlag ← FALSE; tentries ← ntentries ← oldEntries ← 0; IF flags[lists] THEN openwordstream[]; FOR six IN [1..slim) DO FOR i IN [1..totalTokens] DO conflicts[i] ← [0,0,0] ENDLOOP; i ← stateInfo[six].entries; WHILE i < stateInfo[six+1].entries DO -- insert scan and scan reduce entries in conflicts array SELECT table[i].tag FROM 0 => { j, p: CARDINAL; [,j,p] ← table[stateInfo[table[i].pss].nucleus]; conflicts[rhschar[prodinfo[p].index+j-1]] ← table[i]; i ← i+1; tentries ← tentries+1}; 1 => { j, p: CARDINAL; [,j,p] ← table[i]; conflicts[rhschar[prodinfo[p].index+j-1]] ← table[i]; i ← i+1; tentries ← tentries+1}; 2 => i ← i+1; 3 => {conflicts[table[i].pss] ← table[i+1]; i ← i+2; ntentries ← ntentries+1}; ENDCASE; ENDLOOP; -- compute lookaheads, insert reduce entries and output as necessary conflictFlag ← FALSE; maxRedEntries ← defaultProd ← 0; FOR i IN [stateInfo[six].entries..stateInfo[six+1].entries) WHILE table[i].tag = 2 DO IF (k ← Find[six,[0,table[i].jf,table[i].pss]]) = rlim THEN { rlim ← rlim +1; Context[k,1]}; k ← k*bitstrsize; -- @bitString[k] points at the LALR(1) lookahead for this reduce reduceFlag ← FALSE; redEntries ← 0; FOR j IN [1..eofile] DO IF FindBit[j,@bitString[k]] THEN { IF conflicts[j] = [0,0,0] THEN { conflicts[j] ← table[i]; tentries ← tentries+1; redEntries ← redEntries+1} ELSE { --we have conflicts LalrHeader[]; IF ~reduceFlag THEN { reduceFlag ← TRUE; outstring[" REDUCE with "L]; outnum[table[i].pss,4]; outstring[" conflicts with "L]; outchar[' ,40]; outchar['*,10]; lineWidth ← outbufLim}; IF (lineWidth ← lineWidth+tokenSize+7) > outbufLim THEN { outeol[1]; outchar[' ,4]; lineWidth ← tokenSize+11}; outchar[' ,tokenSize-OutToken[j]]; IF conflicts[j].tag # 2 THEN { outstring[" SCAN/ "L]; warningsLogged ← TRUE} ELSE { outnum[conflicts[j].pss,5]; outstring["/ "L]; lalrSuccess ← FALSE; IF flags[lists] THEN { -- turn off binary output flags[lists] ← FALSE; closewordstream[]}}}}; ENDLOOP; IF reduceFlag THEN outeol[1]; IF redEntries > maxRedEntries THEN { maxRedEntries ← redEntries; defaultProd ← table[i].pss}; ENDLOOP; IF flags[printLALR] THEN LalrHeader[]; IF flags[lists] THEN { outword[defaultProd]; outword[tentries+ntentries-oldEntries]; oldEntries ← tentries+ntentries}; lineWidth ← 0; FOR j IN [1..totalTokens] DO IF conflicts[j] # [0,0,0] THEN { item: PGSTypes.ItemRec ← conflicts[j]; -- grab entries for tabgen here IF flags[lists] THEN { outword[j]; outword[IF item.tag=0 THEN 0 ELSE 4*item.jf+item.tag]; outword[item.pss]}; IF flags[printLALR] OR conflictFlag THEN { IF item.tag = 2 THEN {item.tag ← 1; PrintEntry[item,j,'*]} ELSE PrintEntry[item,j]}}; ENDLOOP; ENDLOOP; seterrstream[]; outstring["\nLALR(1) Statistics"L]; outstring["\nStates ="L]; outnum[slim-1, 4]; outstring["\nTerminal entries ="L]; outnum[tentries, 5]; outstring["\nNonterminal entries ="L]; outnum[ntentries, 5]; outstring["\nFirst OR operation count ="L]; outnum[firstOrCount, 5]; outstring["\nTotal OR operation count ="L]; outnum[orCount, 5]; outstring["\nMaximum number of contexts ="L]; outnum[rlim-1, 5]; outeol[1]; FreeArray[conflicts]; FreeArray[chainStack]; FreeArray[stack]; FreeArray[bitString]; FreeArray[bitsInfo]; FreeArray[firstBits]; FreeArray[backChain]; FreeArray[table]; FreeArray[stateInfo]; FreeArray[rhschar]; FreeArray[tokeninfo]; zone.FREE[@hashHead]; ReleaseZone[zone]; RETURN [lalrSuccess]}; ProcessState: PROC = { k1, k2, nmark, entrymark: CARDINAL; -- indexes into table p, j, n: CARDINAL; sym, nsym: CARDINAL; -- procedures called by ProcessState Sort: PROC [index: CARDINAL] = { k1, k2: CARDINAL; item: PGSTypes.ItemRec; noswap: BOOL; Compare: PROC RETURNS [BOOL] = INLINE { RETURN [table[k1+1].pss > table[k1+3].pss OR (table[k1+1].pss = table[k1+3].pss AND table[k1+1].jf > table[k1+3].jf)]}; FOR k2 ← entryLim-2, k2-2 WHILE k2>=index DO noswap ← TRUE; FOR k1 ← index, k1+2 WHILE k1<k2 DO IF (table[k1].pss > table[k1+2].pss OR table[k1].pss = table[k1+2].pss AND Compare[]) THEN { item ← table[k1]; table[k1] ← table[k1+2]; table[k1+2] ← item; item ← table[k1+1]; table[k1+1] ← table[k1+3]; table[k1+3] ← item; noswap ← FALSE}; ENDLOOP; IF noswap THEN RETURN; ENDLOOP}; ExpandTable: PROC = { i: CARDINAL; new: PGSTypes.LongDes; new ← LOOPHOLE[MakeArray[LENGTH[table]+tabExt,SIZE[PGSTypes.ItemRec]]]; FOR i IN [0..entryLim) DO new[i] ← table[i] ENDLOOP; FOR i IN (stateInfo[slim].nucleus..LENGTH[table]) DO new[i+tabExt] ← table[i] ENDLOOP; FOR i IN [1..slim] DO stateInfo[i].nucleus ← stateInfo[i].nucleus+tabExt ENDLOOP; FreeArray[table]; table ← new}; LocateState: PROC [index, n: CARDINAL] RETURNS [CARDINAL] = { i, j, k, r: CARDINAL; IF table[index+1] = [0,1,0] THEN RETURN [0]; -- final state, n=2 in this case r ← (63*n+LOOPHOLE[table[index+1],CARDINAL]) MOD LENGTH[hashHead↑]; FOR i ← hashHead[r], stateInfo[i].link WHILE i # 0 DO IF n = 2*(stateInfo[i].nucleus-stateInfo[i+1].nucleus) THEN { k ← index+1; FOR j DECREASING IN (stateInfo[i+1].nucleus..stateInfo[i].nucleus] DO IF table[j] # table[k] THEN EXIT; k ← k+2; REPEAT FINISHED => RETURN [i] ENDLOOP}; ENDLOOP; -- a new state IF hashHead[r] # 0 THEN stateInfo[slim].link ← hashHead[r]; hashHead[r] ← slim; IF slim+1 = LENGTH[stateInfo] THEN stateInfo ← LOOPHOLE[Expand[stateInfo, SIZE[PGSTypes.StateInfoRec], stateExt]]; IF entryLim+n/2 > stateInfo[slim].nucleus THEN ExpandTable[]; -- insert new nucleus r ← stateInfo[slim].nucleus; FOR i ← index+1, i+2 WHILE i<index+n DO table[r] ← table[i]; r ← r-1 ENDLOOP; slim ← slim+1; stateInfo[slim].nucleus ← r; IF slim <= pssLim+1 THEN RETURN [slim-1] ELSE { seterrstream[]; outstring["\n\nERROR - Internal field will overflow - increase PSSLIM\n"L]; ERROR PGSFail[]}}; -- end of local procedures k1 ← stateInfo[six].nucleus; IF (k1-stateInfo[six+1].nucleus)*2 > stateInfo[slim].nucleus-entryLim+1 THEN ExpandTable[]; -- copy nucleus to entries FOR k1 DECREASING IN (stateInfo[six+1].nucleus..k1] DO table[entryLim+1] ← table[k1]; entryLim ← entryLim+2 ENDLOOP; -- compute closure entrymark ← entryLim; FOR k2 ← stateInfo[six].entries, k2+2 WHILE k2<entryLim DO p ← table[k2+1].pss; j ← table[k2+1].jf; table[k2] ← [0,0,0]; IF j # prodinfo[p].count THEN { --not a reduce sym ← rhschar[prodinfo[p].index+j]; table[k2].pss ← sym; IF sym>eofile THEN { -- nonterminal scan t: PGSTypes.TokenEntry = tokeninfo[sym-eofile]; FOR p IN [t.index..t.index+t.count) DO FOR k1 ← entrymark, k1+2 WHILE k1<entryLim DO IF table[k1+1] = [0,0,p] THEN EXIT REPEAT FINISHED => { IF entryLim+2 > stateInfo[slim].nucleus THEN ExpandTable[]; table[entryLim+1] ← [0,0,p]; entryLim ← entryLim+2}; ENDLOOP; ENDLOOP}}; ENDLOOP; Sort[stateInfo[six].entries]; IF flags[chain] THEN { -- extend closure k2 ← stateInfo[six].entries; WHILE k2 < entryLim AND table[k2].pss <= eofile DO k2 ← k2+2 ENDLOOP; IF k2 < entryLim THEN { entrymark ← k2; --first nonterminal entry WHILE k2 < entryLim DO p ← table[k2+1].pss; IF prodinfo[p].chain THEN { sym ← table[k2].pss; nsym ← prodinfo[p].lhs; -- now search for lhs entry k1 ← entrymark; WHILE nsym # table[k1].pss DO k1 ← k1+2 ENDLOOP; -- now overwrite chain entry with first chained entry table[k2+1] ← table[k1+1]; k2 ← k2-2; -- back up k2 in case first chained entry is also a chain entry -- now append the other chained entries FOR k1 ← k1+2, k1+2 WHILE k1 < entryLim DO IF nsym = table[k1].pss THEN { IF entryLim+2 > stateInfo[slim].nucleus THEN ExpandTable[]; table[entryLim].pss ← sym; table[entryLim+1] ← table[k1+1]; entryLim ← entryLim+2}; ENDLOOP}; k2 ← k2+2; ENDLOOP; Sort[entrymark]}}; -- pack up reduce entries k1 ← k2 ← stateInfo[six].entries; WHILE k2 < entryLim AND table[k2].pss = 0 DO table[k1] ← table[k2+1]; table[k1].tag ← 2; k1 ← k1+1; k2 ← k2+2 ENDLOOP; -- form new states and pack up entries entrymark ← k2; nmark ← 0; WHILE entrymark < entryLim DO k2 ← entrymark+2; WHILE k2 < entryLim AND table[k2].pss = table[entrymark].pss DO table[k2+1].jf ← table[k2+1].jf+1; k2 ← k2+2 ENDLOOP; table[entrymark+1].jf ← table[entrymark+1].jf+1; n ← k2-entrymark; -- 2*number of elements in this state IF n#2 OR table[entrymark+1].jf # prodinfo[table[entrymark+1].pss].count THEN table[entrymark+1] ← [0,1,LocateState[entrymark,n]] -- make shift ELSE table[entrymark+1].tag ← 1; -- make scan reduce IF table[entrymark].pss > eofile THEN { -- insert symbol IF nmark = 0 THEN nmark ← k1; table[k1] ← [3,0,table[entrymark].pss]; k1 ← k1+1}; table[k1] ← table[entrymark+1]; k1 ← k1+1; --insert shift or scan reduce entrymark ← k2; ENDLOOP; entryLim ← k1}; -- entryLim-1 => last entry, nmark => first nonterminal entry or is 0 FirstSet: PROC = { i, j, top, listindex: CARDINAL; discrim, vertices: PGSTypes.AttrVec; t: PGSTypes.TokenEntry; p: PGSTypes.ProdEntry; First: PROC [nonterm: CARDINAL] = { prix, chix, w: CARDINAL; discrim[nonterm] ← top ← top+1; vertices[top] ← nonterm; t ← tokeninfo[nonterm]; FOR prix IN [t.index..t.index+t.count) DO p ← prodinfo[prix]; FOR chix IN [p.index..p.index+p.count) DO w ← rhschar[chix]; IF w <= eofile THEN {InsertBit[w,@firstBits[nonterm*bitstrsize]]; EXIT}; w ← w-eofile; IF discrim[w] = 0 THEN First[w]; IF discrim[w] <= top THEN discrim[nonterm] ← MIN[discrim[nonterm], discrim[w]] ELSE OrBits[@firstBits[vertices[discrim[w]]*bitstrsize], @firstBits[nonterm*bitstrsize]]; IF ~tokeninfo[w].empty THEN EXIT; ENDLOOP; ENDLOOP; IF nonterm = vertices[discrim[nonterm]] THEN { listindex ← listindex-1; w ← vertices[top]; top ← top-1; discrim[w] ← listindex; WHILE w # nonterm DO OrBits[@firstBits[w*bitstrsize], @firstBits[nonterm*bitstrsize]]; w ← vertices[top]; top ← top-1; discrim[w] ← listindex; ENDLOOP; vertices[listindex] ← nonterm}}; discrim ← LOOPHOLE[MakeArray[totalTokens-eofile+1, SIZE[CARDINAL]]]; vertices ← LOOPHOLE[MakeArray[totalTokens-eofile+1, SIZE[CARDINAL]]]; listindex ← totalTokens-eofile+1; top ← 0; -- initialise stack and list of heads FOR i IN [1..totalTokens-eofile] DO IF discrim[i] = 0 THEN First[i] ENDLOOP; FOR i IN [1..totalTokens-eofile] DO -- copy head bitStrings to other scc vertices IF i # vertices[discrim[i]] THEN OrBits[@firstBits[vertices[discrim[i]]*bitstrsize], @firstBits[i*bitstrsize]]; ENDLOOP; FreeArray[discrim]; FreeArray[vertices]; IF flags[first] THEN { setoutstream[".first"L]; outstring["\nFIRST SETS\n\n"L]; FOR i IN [1..totalTokens-eofile] DO [] ← OutToken[i+eofile]; lineWidth ← outbufLim; FOR j IN [1..eofile] DO IF FindBit[j,@firstBits[i*bitstrsize]] THEN { IF (lineWidth ← lineWidth+tokenSize+1) > outbufLim THEN { outeol[1]; outchar[' ,4]; lineWidth ← tokenSize+5}; outchar[' ,tokenSize+1-OutToken[j]]}; ENDLOOP; outeol[2]; ENDLOOP; closeoutstream[]}}; Find: PROC [state: CARDINAL, item: PGSTypes.ItemRec] RETURNS [CARDINAL] = { i, r: CARDINAL; r ← (state + LOOPHOLE[item,CARDINAL]) MOD LENGTH[hashHead↑]; i ← hashHead[r]; WHILE i # 0 DO IF state = bitsInfo[i].state AND item = bitsInfo[i].item THEN RETURN [i]; i ← bitsInfo[i].link; ENDLOOP; -- new context IF rlim>=LENGTH[bitsInfo] THEN { bitsInfo ← LOOPHOLE[Expand[bitsInfo,SIZE[PGSTypes.ContextRec],LENGTH[bitsInfo]/8]]; bitString ← LOOPHOLE[Expand[bitString,bitstrsize,LENGTH[bitString]/8]]}; IF hashHead[r] # 0 THEN bitsInfo[rlim].link ← hashHead[r]; hashHead[r] ← rlim; bitsInfo[rlim].state ← state; bitsInfo[rlim].item ← item; RETURN [rlim]}; Context: PROC [index, base: CARDINAL] = { cj, j: CARDINAL; -- displacements relative to base into chainStack i: CARDINAL; -- used locally but also indexes current (q,k+1) across recursive calls k: CARDINAL; -- used locally but also indexes current state across recursive calls top ← top+1; IF top = LENGTH[stack] THEN stack ← LOOPHOLE[Expand[stack,SIZE[CARDINAL],15]]; bitsInfo[index].status ← top; stack[top] ← index; -- initialise for transitive closure j ← bitsInfo[index].item.jf; -- want the jth predecessor state IF base+MAX[1,j] >= LENGTH[chainStack] THEN chainStack ← LOOPHOLE[Expand[chainStack,SIZE[CARDINAL],45]]; cj ← 1; chainStack[base+cj] ← stateInfo[bitsInfo[index].state].link; --index 1st predec DO -- for each jth predecessor state IF j=0 THEN { predState ← bitsInfo[index].state; -- zeroth predecessor j ← 1; chainStack[base+cj] ← 0} --ensure no more zeroth predecessors ELSE DO IF chainStack[base+cj] = 0 THEN { IF (cj ← cj-1) =0 THEN GOTO quit} -- no more jth predecessors ELSE { [predState, chainStack[base+cj]] ← backChain[chainStack[base+cj]]; IF cj=j THEN EXIT; cj ← cj+1; chainStack[base+cj] ← stateInfo[predState].link}; ENDLOOP; -- locate the (q,k+1) in each jth predecessor state FOR i IN [stateInfo[predState].entries..stateInfo[predState+1].entries) DO IF table[i] = [3,0,prodinfo[bitsInfo[index].item.pss].lhs] THEN EXIT; REPEAT FINISHED => ERROR -- nonterminal not found ENDLOOP; i ← i+1; -- index the associated item IF table[i].tag # 0 THEN k ← i-1 ELSE { k ← stateInfo[table[i].pss+1].nucleus; i ← stateInfo[table[i].pss].nucleus}; FOR i DECREASING IN (k..i] DO --select each (q,k+1) s.t. X[q,k+1] = A[p] FOR k IN [table[i].jf..prodinfo[table[i].pss].count) DO --all v s.t. k+2<=v<= n[q] IF (symbol ← rhschar[prodinfo[table[i].pss].index+k]) <= eofile THEN { -- X[q.v]<=eofile InsertBit[symbol, @bitString[index*bitstrsize] ]; EXIT} ELSE { symbol ← symbol-eofile; OrBits[ @firstBits[symbol*bitstrsize], @bitString[index*bitstrsize] ]; IF ~tokeninfo[symbol].empty THEN EXIT}; -- now the core of the transitive closure algorithm REPEAT FINISHED => { IF (k ← Find[predState, [0,table[i].jf-1,table[i].pss]]) = rlim THEN { rlim ← rlim+1; Context[k,base+j]}; IF bitsInfo[k].status <= top THEN bitsInfo[index].status ← MIN[bitsInfo[index].status,bitsInfo[k].status] ELSE OrBits[ @bitString[k*bitstrsize], @bitString[index*bitstrsize] ]}; ENDLOOP; ENDLOOP; REPEAT quit => NULL ENDLOOP; IF index = stack[bitsInfo[index].status] THEN { --scc head k ← top; i ← stack[top]; bitsInfo[i].status ← LAST[CARDINAL]; FOR top ← top-1, top-1 WHILE i#index DO OrBits[ @bitString[i*bitstrsize], @bitString[index*bitstrsize] ]; i ← stack[top]; bitsInfo[i].status ← LAST[CARDINAL]; ENDLOOP; FOR k IN [top+2..k] DO OrBits[ @bitString[index*bitstrsize], @bitString[stack[k]*bitstrsize] ]; ENDLOOP}}; }.