NPGSLALR.mesa
Copyright Ó 1985, 1988 by Xerox Corporation. All rights reserved.
Satterthwaite, October 16, 1985 5:47:23 pm PDT
Maxwell, August 10, 1983 10:22 am
Wyatt, March 21, 1984 10:28:38 am PST
Russ Atkinson (RRA) March 14, 1988 5:00:54 pm PST
JKF February 6, 1989 11:50:29 am PST
DIRECTORY
NPGSConDefs,
NPGSTypes;
NPGSLALR: CEDAR PROGRAM
IMPORTS NPGSConDefs
EXPORTS NPGSConDefs = {
stateInfo: NPGSTypes.StateInfo;
table: NPGSTypes.Table;
lineWidth: CARDINAL;
lalrSuccess: BOOL;
entryLim: CARDINAL; -- index into table
six: CARDINAL; -- six, the current state; sLim in NPGScan the next state number allocated
hashHead: NPGSTypes.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: NPGSTypes.BackChain;
stack: NPGSTypes.Stack;
chainStack: NPGSTypes.ChainStack;
bitsInfo: NPGSTypes.BitsInfo;
bitString: NPGSTypes.BitString;
firstBits: NPGSTypes.BitString;
LALRGen: PUBLIC PROC [cusp: BOOL] RETURNS[BOOL] = {
i, j, k, totalShifts, totalReduces, oldEntries, firstOrCount: CARDINAL;
redEntries, maxRedEntries, defaultProd: CARDINAL;
conflictFlag, reduceFlag, messageFlag: BOOL;
conflicts: NPGSTypes.Table;
PrintHeader: PROC = {
j, p: CARDINAL;
NPGSConDefs.outeol[2];
FOR i: CARDINAL DECREASING IN (stateInfo[six+1].nucleus..stateInfo[six].nucleus] DO
[,j,p] ← table[i];
IF lineWidth = 0 THEN {
NPGSConDefs.outnum[six,4]; NPGSConDefs.outchar[' ,1]; lineWidth ← NPGSConDefs.tokenSize+5;
IF p>0 THEN NPGSConDefs.outchar[' ,NPGSConDefs.tokenSize-NPGSConDefs.OutToken[NPGSConDefs.rhsChar[NPGSConDefs.prodInfo[p].index+j-1]]]
};
IF lineWidth+9 > NPGSConDefs.outbufLim THEN {NPGSConDefs.outeol[1]; NPGSConDefs.outchar[' ,lineWidth ← NPGSConDefs.tokenSize+5]};
NPGSConDefs.outnum[p,4]; NPGSConDefs.outnum[j,3]; NPGSConDefs.outchar['/,1]; NPGSConDefs.outchar[' ,1];
ENDLOOP;
NPGSConDefs.outeol[1]
};
PrintEntry: PROC[
item: NPGSTypes.ItemRec, symmark: CARDINAL, sign: CHAR←'-] = {
i: INTEGER; p, j: CARDINAL;
IF item.tag = 2 THEN {
NPGSConDefs.outstring[" Reduce with "]; NPGSConDefs.outnum[item.pss,5,sign]; NPGSConDefs.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 ← NPGSConDefs.rhsChar[NPGSConDefs.prodInfo[p].index+j-1]
};
lineWidth ← lineWidth+NPGSConDefs.tokenSize+8;
IF lineWidth > NPGSConDefs.outbufLim THEN {NPGSConDefs.outeol[1]; lineWidth ← NPGSConDefs.tokenSize+8};
NPGSConDefs.outnum[i,5,sign]; NPGSConDefs.outchar[' ,1]; NPGSConDefs.outchar[' ,NPGSConDefs.tokenSize+2-NPGSConDefs.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; NPGSConDefs.seterrstream[]; NPGSConDefs.outstring["\nLALR(1) Tables\n"];
};
IF ~conflictFlag THEN {conflictFlag ← TRUE; lineWidth ← 0; PrintHeader[]}
};
lalrSuccess ← TRUE; NPGSConDefs.orCount ← 0;
make arrays with all entries zeroed
stateInfo ← NPGSConDefs.MakeStateInfo[NPGSConDefs.maxStateNum+2];
table ← NPGSConDefs.MakeTable[NPGSConDefs.maxTabEntries+1];
hashHead ← NEW[NPGSTypes.HashHeads ← ALL[0]];
stateInfo[0].nucleus←NPGSConDefs.maxTabEntries; table[NPGSConDefs.maxTabEntries] ← [0,1,0]; --final state
stateInfo[1].nucleus←NPGSConDefs.maxTabEntries-1; table[NPGSConDefs.maxTabEntries-1] ← [0,0,0];--initial state
stateInfo[2].nucleus←NPGSConDefs.maxTabEntries-2; NPGSConDefs.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 NPGSConDefs.flags[printLR] THEN {NPGSConDefs.setoutstream[".lr"]; NPGSConDefs.outstring["\nLR(0) TABLES"]};
FOR six ← 1, six+1 WHILE six < NPGSConDefs.sLim DO
ProcessState[]; stateInfo[six+1].entries ← entryLim;
IF NPGSConDefs.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 NPGSConDefs.flags[printLR] THEN NPGSConDefs.outeol[1];
NPGSConDefs.closeoutstream[];
IF ~NPGSConDefs.flags[lists] AND ~NPGSConDefs.flags[printLALR] THEN RETURN[FALSE];
now form inverse of shift transitions for the lookahead sets caculation
backChain ← NPGSConDefs.MakeBackChain[totalShifts+1];
FOR six IN [0..NPGSConDefs.sLim) DO stateInfo[six].link ← 0 ENDLOOP;
k ← 1;
FOR six IN [1..NPGSConDefs.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
NPGSConDefs.bitstrSize ← (NPGSConDefs.eofMark+NPGSConDefs.wordLength-1)/NPGSConDefs.wordLength;
firstBits ← NPGSConDefs.MakeBitString[(NPGSConDefs.totalTokens-NPGSConDefs.eofMark+1), NPGSConDefs.bitstrSize];
FirstSet[]; firstOrCount ← NPGSConDefs.orCount;
hashHead^ ← ALL[0]; -- used by find
bitsInfo ← NPGSConDefs.MakeBitsInfo[NPGSConDefs.maxContexts]; rlim ← 1;
bitString ← NPGSConDefs.MakeBitString[NPGSConDefs.maxContexts, NPGSConDefs.bitstrSize];
stack ← NPGSConDefs.MakeStack[30]; top ← 0;
chainStack ← NPGSConDefs.MakeStack[90];
conflicts ← NPGSConDefs.MakeTable[NPGSConDefs.totalTokens+1];
messageFlag ← FALSE;
NPGSConDefs.tEntries ← NPGSConDefs.ntEntries ← oldEntries ← 0;
IF NPGSConDefs.flags[lists] THEN NPGSConDefs.openwordstream[];
FOR six IN [1..NPGSConDefs.sLim) DO
FOR i IN [1..NPGSConDefs.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[NPGSConDefs.rhsChar[NPGSConDefs.prodInfo[p].index+j-1]] ← table[i]; i ← i+1;
NPGSConDefs.tEntries ← NPGSConDefs.tEntries+1
};
1 => {
j, p: CARDINAL;
[,j,p] ← table[i];
conflicts[NPGSConDefs.rhsChar[NPGSConDefs.prodInfo[p].index+j-1]] ← table[i]; i ← i+1;
NPGSConDefs.tEntries ← NPGSConDefs.tEntries+1
};
2 => i ← i+1;
3 => {conflicts[table[i].pss] ← table[i+1]; i ← i+2; NPGSConDefs.ntEntries ← NPGSConDefs.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]
};
bitString[k] points at the LALR(1) lookahead for this reduce
reduceFlag ← FALSE; redEntries ← 0;
FOR j IN [1..NPGSConDefs.eofMark] DO
IF NPGSConDefs.FindBit[bitString,k,j] THEN {
IF conflicts[j] = [0,0,0] THEN {
conflicts[j] ← table[i]; NPGSConDefs.tEntries ← NPGSConDefs.tEntries+1; redEntries ← redEntries+1
}
ELSE { --we have conflicts
LalrHeader[];
IF ~reduceFlag THEN {
reduceFlag ← TRUE; NPGSConDefs.outstring[" REDUCE with "];
NPGSConDefs.outnum[table[i].pss,4]; NPGSConDefs.outstring[" conflicts with "]; NPGSConDefs.outchar[' ,40];
NPGSConDefs.outchar['*,10]; lineWidth ← NPGSConDefs.outbufLim
};
IF (lineWidth ← lineWidth+NPGSConDefs.tokenSize+7) > NPGSConDefs.outbufLim THEN {
NPGSConDefs.outeol[1]; NPGSConDefs.outchar[' ,4]; lineWidth ← NPGSConDefs.tokenSize+11
};
NPGSConDefs.outchar[' ,NPGSConDefs.tokenSize-NPGSConDefs.OutToken[j]];
IF conflicts[j].tag # 2 THEN {
NPGSConDefs.outstring[" SCAN/ "]; NPGSConDefs.warningsLogged ← TRUE
}
ELSE {
NPGSConDefs.outnum[conflicts[j].pss,5]; NPGSConDefs.outstring["/ "]; lalrSuccess ← FALSE;
IF NPGSConDefs.flags[lists] THEN { -- turn off binary output
NPGSConDefs.flags[lists] ← FALSE; NPGSConDefs.closewordstream[]
}
}
}
};
ENDLOOP;
IF reduceFlag THEN NPGSConDefs.outeol[1];
IF redEntries > maxRedEntries THEN {
maxRedEntries ← redEntries; defaultProd ← table[i].pss
};
ENDLOOP;
IF NPGSConDefs.flags[printLALR] THEN LalrHeader[];
IF NPGSConDefs.flags[lists] THEN {
NPGSConDefs.outword[defaultProd]; NPGSConDefs.outword[NPGSConDefs.tEntries+NPGSConDefs.ntEntries-oldEntries];
oldEntries ← NPGSConDefs.tEntries+NPGSConDefs.ntEntries
};
lineWidth ← 0;
-- New for CUSP:
IF cusp THEN {
NPGSConDefs.CuspPreClearTokensUsedArray[];
[,j,k] ← table[stateInfo[six].nucleus];
IF k > 0 THEN NPGSConDefs.CuspPreSetHeaderUsed[NPGSConDefs.rhsChar[NPGSConDefs.prodInfo[k].index+j-1]];
};
-- end of new stuff
FOR j IN [1..NPGSConDefs.totalTokens] DO
IF conflicts[j] # [0,0,0] THEN {
item: NPGSTypes.ItemRec ← conflicts[j];
grab entries for tabgen here
IF NPGSConDefs.flags[lists] THEN {
NPGSConDefs.outword[j];
NPGSConDefs.outword[IF item.tag=0 THEN 0 ELSE 4*item.jf+item.tag]; NPGSConDefs.outword[item.pss]
};
IF NPGSConDefs.flags[printLALR] OR conflictFlag THEN {
IF item.tag = 2 THEN {item.tag ← 1; PrintEntry[item,j,'*]}
ELSE PrintEntry[item,j]
};
IF cusp THEN NPGSConDefs.CuspPreSetNextTokenUsed[j]; -- new for CUSP
};
ENDLOOP;
IF cusp THEN NPGSConDefs.CuspPreSetNextErrorMsgElement[six]; -- new for CUSP
ENDLOOP;
NPGSConDefs.seterrstream[]; NPGSConDefs.outstring["\nLALR(1) Statistics"];
NPGSConDefs.outstring["\nStates ="]; NPGSConDefs.outnum[NPGSConDefs.sLim-1, 4];
NPGSConDefs.outstring["\nTerminal entries ="]; NPGSConDefs.outnum[NPGSConDefs.tEntries, 5];
NPGSConDefs.outstring["\nNonterminal entries ="]; NPGSConDefs.outnum[NPGSConDefs.ntEntries, 5];
NPGSConDefs.outstring["\nFirst OR operation count ="]; NPGSConDefs.outnum[firstOrCount, 5];
NPGSConDefs.outstring["\nTotal OR operation count ="]; NPGSConDefs.outnum[NPGSConDefs.orCount, 5];
NPGSConDefs.outstring["\nMaximum number of contexts ="]; NPGSConDefs.outnum[rlim-1, 5];
NPGSConDefs.outeol[1];
conflicts ← NIL; chainStack ← NIL;
stack ← NIL; bitString ← NIL;
bitsInfo ← NIL; firstBits ← NIL;
backChain ← NIL;
table ← NIL; stateInfo ← NIL;
NPGSConDefs.rhsChar ← NIL; NPGSConDefs.tokenInfo ← NIL;
hashHead ← NIL;
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: NPGSTypes.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 = {
new: NPGSTypes.Table ~ NPGSConDefs.MakeTable[table.length+NPGSConDefs.tabExt];
FOR i: CARDINAL IN [0..entryLim) DO
new[i] ← table[i] ENDLOOP;
FOR i: CARDINAL IN (stateInfo[NPGSConDefs.sLim].nucleus..table.length) DO
new[i+NPGSConDefs.tabExt] ← table[i] ENDLOOP;
FOR i: CARDINAL IN [1..NPGSConDefs.sLim] DO
stateInfo[i].nucleus ← stateInfo[i].nucleus+NPGSConDefs.tabExt ENDLOOP;
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], CARD16]) MOD hashHead^.LENGTH;
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[NPGSConDefs.sLim].link ← hashHead[r]; hashHead[r] ← NPGSConDefs.sLim;
IF NPGSConDefs.sLim+1 = stateInfo.length THEN
stateInfo ← NPGSConDefs.ExpandStateInfo[stateInfo, NPGSConDefs.stateExt];
IF entryLim+n/2 > stateInfo[NPGSConDefs.sLim].nucleus THEN ExpandTable[];
insert new nucleus
r ← stateInfo[NPGSConDefs.sLim].nucleus;
FOR i ← index+1, i+2 WHILE i<index+n DO table[r] ← table[i]; r ← r-1 ENDLOOP;
NPGSConDefs.sLim ← NPGSConDefs.sLim+1; stateInfo[NPGSConDefs.sLim].nucleus ← r;
IF NPGSConDefs.sLim <= NPGSConDefs.pssLim+1 THEN RETURN[NPGSConDefs.sLim-1] ELSE {
NPGSConDefs.seterrstream[];
NPGSConDefs.outstring["\n\nERROR - Internal field will overflow - increase PSSLIM\n"];
ERROR NPGSConDefs.NPGSFail[]
}
};
end of local procedures
k1 ← stateInfo[six].nucleus;
IF (k1-stateInfo[six+1].nucleus)*2 > stateInfo[NPGSConDefs.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 # NPGSConDefs.prodInfo[p].count THEN { --not a reduce
sym ← NPGSConDefs.rhsChar[NPGSConDefs.prodInfo[p].index+j]; table[k2].pss ← sym;
IF sym>NPGSConDefs.eofMark THEN { -- nonterminal scan
t: NPGSTypes.TokenEntry = NPGSConDefs.tokenInfo[sym-NPGSConDefs.eofMark];
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[NPGSConDefs.sLim].nucleus THEN ExpandTable[];
table[entryLim+1] ← [0,0,p]; entryLim ← entryLim+2
};
ENDLOOP;
ENDLOOP
}
};
ENDLOOP;
Sort[stateInfo[six].entries];
IF NPGSConDefs.flags[chain] THEN { -- extend closure
k2 ← stateInfo[six].entries;
WHILE k2 < entryLim AND table[k2].pss <= NPGSConDefs.eofMark DO k2 ← k2+2 ENDLOOP;
IF k2 < entryLim THEN {
entrymark ← k2; --first nonterminal entry
WHILE k2 < entryLim DO
p ← table[k2+1].pss;
IF NPGSConDefs.prodInfo[p].chain THEN {
sym ← table[k2].pss; nsym ← NPGSConDefs.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[NPGSConDefs.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
jf: CARDINAL ← 0;
k2 ← entrymark+2;
WHILE k2 < entryLim AND table[k2].pss = table[entrymark].pss DO
jf ← table[k2+1].jf;
table[k2+1].jf ← jf+1;
k2 ← k2+2
ENDLOOP;
jf ← table[entrymark+1].jf;
table[entrymark+1].jf ← jf + 1;
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 # NPGSConDefs.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 > NPGSConDefs.eofMark 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: NPGSTypes.AttrVec;
t: NPGSTypes.TokenEntry;
p: NPGSTypes.ProdEntry;
First: PROC[nonterm: CARDINAL] = {
prix, chix, w: CARDINAL;
discrim[nonterm] ← top ← top+1; vertices[top] ← nonterm;
t ← NPGSConDefs.tokenInfo[nonterm];
FOR prix IN [t.index..t.index+t.count) DO
p ← NPGSConDefs.prodInfo[prix];
FOR chix IN [p.index..p.index+p.count) DO
w ← NPGSConDefs.rhsChar[chix];
IF w <= NPGSConDefs.eofMark THEN {NPGSConDefs.InsertBit[firstBits, nonterm, w]; EXIT};
w ← w-NPGSConDefs.eofMark; IF discrim[w] = 0 THEN First[w];
IF discrim[w] <= top THEN discrim[nonterm] ← MIN[discrim[nonterm], discrim[w]]
ELSE NPGSConDefs.OrBits[firstBits, vertices[discrim[w]], firstBits, nonterm];
IF ~NPGSConDefs.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
NPGSConDefs.OrBits[firstBits, w, firstBits, nonterm];
w ← vertices[top]; top ← top-1; discrim[w] ← listindex;
ENDLOOP;
vertices[listindex] ← nonterm
}
};
discrim ← NPGSConDefs.MakeAttrVec[NPGSConDefs.totalTokens-NPGSConDefs.eofMark+1];
vertices ← NPGSConDefs.MakeAttrVec[NPGSConDefs.totalTokens-NPGSConDefs.eofMark+1];
listindex ← NPGSConDefs.totalTokens-NPGSConDefs.eofMark+1; top ← 0; -- initialise stack and list of heads
FOR i IN [1..NPGSConDefs.totalTokens-NPGSConDefs.eofMark] DO IF discrim[i] = 0 THEN First[i] ENDLOOP;
FOR i IN [1..NPGSConDefs.totalTokens-NPGSConDefs.eofMark] DO -- copy head bitStrings to other scc vertices
IF i # vertices[discrim[i]] THEN
NPGSConDefs.OrBits[firstBits, vertices[discrim[i]], firstBits, i];
ENDLOOP;
discrim ← NIL; vertices ← NIL;
IF NPGSConDefs.flags[first] THEN {
NPGSConDefs.setoutstream[".first"]; NPGSConDefs.outstring["\nFIRST SETS\n\n"];
FOR i IN [1..NPGSConDefs.totalTokens-NPGSConDefs.eofMark] DO
[] ← NPGSConDefs.OutToken[i+NPGSConDefs.eofMark]; lineWidth ← NPGSConDefs.outbufLim;
FOR j IN [1..NPGSConDefs.eofMark] DO
IF NPGSConDefs.FindBit[firstBits,i,j] THEN {
IF (lineWidth ← lineWidth+NPGSConDefs.tokenSize+1) > NPGSConDefs.outbufLim THEN {
NPGSConDefs.outeol[1]; NPGSConDefs.outchar[' ,4]; lineWidth ← NPGSConDefs.tokenSize+5
};
NPGSConDefs.outchar[' ,NPGSConDefs.tokenSize+1-NPGSConDefs.OutToken[j]]
};
ENDLOOP;
NPGSConDefs.outeol[2];
ENDLOOP;
NPGSConDefs.closeoutstream[]
}
};
Find: PROC[state: CARDINAL, item: NPGSTypes.ItemRec] RETURNS[CARDINAL] = {
i, r: CARDINAL;
r ← (state + LOOPHOLE[item, CARD16]) MOD hashHead^.LENGTH; 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>=bitsInfo.length THEN {
bitsInfo ← NPGSConDefs.ExpandBitsInfo[bitsInfo, bitsInfo.length/8];
bitString ← NPGSConDefs.ExpandBitString[bitString, bitString.length/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] = {
jf: CARDINAL[0..15] ← 0;
pss: CARDINAL[0..NPGSTypes.pssLim] ← 0;
tempItem: NPGSTypes.ItemRec ← NPGSTypes.nullItemRec;
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 = stack.length THEN stack ← NPGSConDefs.ExpandStack[stack, 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] >= chainStack.length THEN chainStack ← NPGSConDefs.ExpandStack[chainStack, 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,NPGSConDefs.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 {
temp: CARDINAL ← table[i].pss;
k ← stateInfo[temp+1].nucleus;
i ← stateInfo[temp].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..NPGSConDefs.prodInfo[table[i].pss].count) DO --all v s.t. k+2<=v<= n[q]
IF (symbol ← NPGSConDefs.rhsChar[NPGSConDefs.prodInfo[table[i].pss].index+k]) <= NPGSConDefs.eofMark THEN {
X[q.v]<=eofMark
NPGSConDefs.InsertBit[bitString, index, symbol]; EXIT
}
ELSE {
symbol ← symbol-NPGSConDefs.eofMark;
NPGSConDefs.OrBits[firstBits, symbol, bitString, index];
IF ~NPGSConDefs.tokenInfo[symbol].empty THEN EXIT
};
now the core of the transitive closure algorithm
REPEAT FINISHED => {
jf ← table[i].jf;
jf ← jf-1;
pss ← table[i].pss;
tempItem ← [0, jf, pss];
k ← Find[predState, tempItem];
IF k = 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 NPGSConDefs.OrBits[bitString, k, bitString, index]
};
ENDLOOP;
ENDLOOP;
REPEAT quit => NULL
ENDLOOP;
IF index = stack[bitsInfo[index].status] THEN { --scc head
k ← top; i ← stack[top]; bitsInfo[i].status ← CARDINAL.LAST;
FOR top ← top-1, top-1 WHILE i#index DO
NPGSConDefs.OrBits[bitString, i, bitString, index];
i ← stack[top]; bitsInfo[i].status ← CARDINAL.LAST;
ENDLOOP;
FOR k IN [top+2..k] DO
NPGSConDefs.OrBits[bitString, index, bitString, stack[k]];
ENDLOOP
};
};
}.