-- file PGSTab.mesa -- last modified by Satterthwaite, January 7, 1983 12:27 pm DIRECTORY PGSConDefs: TYPE USING [ cpw, defaultMarker, maxCharCode, outbufLim, pssLim, rhsLim, tokenSize, aliases, eofMark, flags, nextAlias, numProd, numRules, ntEntries, prodInfo, sLim, sourceName, symInfo, symTab, tEntries, totalTokens, closewordstream, MakeArray, FreeArray, inword, openwordstream, outblock, outchar, outeol, outnum, outstring, outtime, OutToken, outword], PGSTypes: TYPE USING [ Column, ColumnRec, HashTab, HashTabRec, ItemRec, NTab, NTDefaultRec, NTDefaults, Renumber, StateData, StateDataRec, TabRec, TTab, VocabIndex], Strings: TYPE USING [String]; PGSTab: PROGRAM IMPORTS PGSConDefs EXPORTS PGSConDefs = { OPEN PGSConDefs; linewidth, hashval, lastntstate, vocabspace, nlim, tlim: CARDINAL; offset: CARDINAL; hashtab: PGSTypes.HashTab; ttab: PGSTypes.TTab; ntab: PGSTypes.NTab; packedProdInfo: BOOL; statedata: PGSTypes.StateData; ntdefaults: PGSTypes.NTDefaults; column: PGSTypes.Column; renumber: PGSTypes.Renumber; vocabindex: PGSTypes.VocabIndex; scantab: ARRAY [40b..177b] OF CARDINAL; TabGen: PUBLIC PROC [prefix, suffix: PROC] RETURNS [success: BOOL_TRUE] = { Error: PROC [sel: CARDINAL] = { outstring["\nFAIL - "L]; outstring[SELECT sel FROM 1 => "more than 255 terminal symbols"L, 2 => "more than 254 nonterminal symbols"L, 3 => "more than 2047 states or productions"L, 4 => "more than 15 symbols in a production right part"L, ENDCASE => "PGS error"L]; outeol[1]; success _ FALSE}; IF eofMark > 255 THEN Error[1]; IF totalTokens-eofMark+1 > 255 THEN Error[2]; IF pssLim > 2047 THEN Error[3]; IF rhsLim > 15 THEN Error[4]; IF ~success THEN RETURN [success]; ntab _ LOOPHOLE[MakeArray[ntEntries, PGSTypes.TabRec.SIZE]]; ttab _ LOOPHOLE[MakeArray[tEntries, PGSTypes.TabRec.SIZE]]; packedProdInfo _ (numRules <= 255); statedata _ LOOPHOLE[MakeArray[sLim, PGSTypes.StateDataRec.SIZE]]; ntdefaults _ LOOPHOLE[MakeArray[totalTokens-eofMark+2, PGSTypes.NTDefaultRec.SIZE]]; column _ LOOPHOLE[MakeArray[ntEntries+1, PGSTypes.ColumnRec.SIZE]]; TableSetup[]; closewordstream[]; SquashNTab[]; outstring["\nParse Table Data\n"L]; IF flags[printLALR] THEN {PrintNDef[]; TableOverlays[]}; vocabindex _ LOOPHOLE[MakeArray[eofMark+1, CARDINAL.SIZE]]; hashval _ 3*eofMark/2; hashval _ MIN[251, IF hashval MOD 2 = 0 THEN hashval+1 ELSE hashval]; hashtab _ LOOPHOLE[MakeArray[hashval+1, PGSTypes.HashTabRec.SIZE]]; HashTabSetup[]; -- start output file openwordstream[scratch:FALSE]; IF prefix # NIL THEN prefix[]; -- output scanner table relative offsets (see table output below) offset _ 14; -- number of tables outword[offset]; offset _ offset + 96; outword[offset]; offset _ offset + (hashval+1); outword[offset]; offset _ offset + (eofMark+1); outword[offset]; offset _ offset + (2 + (vocabspace+cpw-1)/cpw); -- output parser table relative offsets (see table output below) StatePartition[]; -- compute lastntstate outword[offset]; offset _ offset + (numProd+1)*(IF packedProdInfo THEN 1 ELSE 2); outword[offset]; offset _ offset + (lastntstate+1); outword[offset]; offset _ offset + (lastntstate+1); outword[offset]; offset _ offset + nlim; outword[offset]; offset _ offset + nlim; outword[offset]; offset _ offset + (totalTokens-eofMark+2); outword[offset]; offset _ offset + sLim; outword[offset]; offset _ offset + sLim; outword[offset]; offset _ offset + tlim; outword[offset]; -- output scanner tables outblock[scantab.BASE, 96]; outblock[hashtab.BASE, hashval+1]; outblock[vocabindex.BASE, eofMark+1]; outword[vocabspace]; outword[vocabspace]; outblock[symTab.BASE, (vocabspace+cpw-1)/cpw]; FreeArray[hashtab]; FreeArray[vocabindex]; FreeArray[symInfo]; renumber _ LOOPHOLE[MakeArray[sLim, CARDINAL.SIZE]]; StateRenumber[]; --now output parser tables OutArray[1,numProd, IF packedProdInfo THEN ProdDataItem1 ELSE ProdDataItem2]; OutArray[1,lastntstate, NStateItem]; OutArray[1,lastntstate, NLenItem]; OutArray[0,nlim-1, NSymItem]; OutArray[0,nlim-1, NActionItem]; OutArray[2,totalTokens-eofMark+1, NTDefaultItem]; OutArray[1,sLim-1, TStateItem]; OutArray[1,sLim-1, TLenItem]; OutArray[0,tlim-1, TSymItem]; OutArray[0,tlim-1, TActionItem]; FreeArray[prodInfo]; FreeArray[ntab]; FreeArray[ntdefaults]; FreeArray[renumber]; FreeArray[statedata]; FreeArray[ttab]; IF suffix # NIL THEN suffix[]}; TableSetup: PROC = { defaultitem, item: PGSTypes.ItemRec; defaultprod, i, j, k, symbol, ttix, ntix, six, index, ptr: CARDINAL; ColumnEntry: PROC = { j: INTEGER; lastptr: CARDINAL; lastptr _ 0; ptr _ ntdefaults[symbol].count; DO IF ptr=0 THEN GOTO insert; j _ item.jf-column[ptr].item.jf; IF j=0 THEN j _ item.pss-column[ptr].item.pss; IF j=0 THEN GOTO countup; IF j<0 THEN GOTO insert; lastptr _ ptr; ptr _ column[ptr].link; REPEAT countup => column[ptr].count _ column[ptr].count+1; insert => { column[index].item _ item; IF lastptr=0 THEN { --head of list for column "symbol" column[index].link _ ntdefaults[symbol].count; ntdefaults[symbol].count _ index} ELSE { column[index].link _ column[lastptr].link; column[lastptr].link _ index}; index _ index+1}; ENDLOOP}; ntix _ ttix _ 0; index _ 1; statedata[1] _ [0,0,0,0]; FOR six IN [1..sLim) DO defaultprod _ inword[]; statedata[six] _ [ttix,ntix,0,0]; THROUGH [1..inword[]] DO --set up entries for state six in ttab and ntab symbol _ inword[]; k _ inword[]; item _ [k MOD 4, k/4, inword[]]; IF item.tag=2 AND item.pss=defaultprod THEN defaultitem _ item ELSE IF symbol<=eofMark THEN {ttab[ttix] _ [symbol, item]; ttix _ ttix+1} ELSE { symbol _ symbol-eofMark+1; ntab[ntix] _ [symbol, item]; ntix _ ntix+1; ColumnEntry[]}; ENDLOOP; IF defaultprod # 0 THEN { ttab[ttix] _ [defaultMarker, defaultitem]; ttix _ ttix+1}; statedata[six].tLink _ ttix-statedata[six].tIndex; --length statedata[six].ntLink _ ntix-statedata[six].ntIndex; --length -- now see if these terminal entries match those of an existing state FOR i IN [1..six) DO k _ statedata[six].tIndex-statedata[i].tIndex; IF statedata[six].tLink=statedata[i].tLink THEN -- same length FOR j IN [statedata[i].tIndex..statedata[i].tIndex+statedata[i].tLink) DO IF ttab[j]#ttab[j+k] THEN EXIT; REPEAT FINISHED => { --there is a matching set of entries statedata[six].tLink _ -i; -- point state six at state i ttix _ statedata[six].tIndex; -- back up index EXIT}; ENDLOOP; ENDLOOP; ENDLOOP; tlim _ ttix; --ttab contains terminal entries; statedata[i].tindex indexes state i entries if --statedata[i].link>0, otherwise statedata[-statedata[i].link].tindex indexes them. --the following code leaves the most frequently occurring item in column "symbol" --of the lalr tables in the appropriate entry of ntdefaults FOR symbol IN [0..totalTokens-eofMark+1] DO IF (ptr _ ntdefaults[symbol].count)=0 THEN LOOP; k _ 0; ntdefaults[symbol].item _ column[ptr].item; WHILE ptr#0 DO IF column[ptr].count>k THEN { k _ column[ptr].count; ntdefaults[symbol].item _ column[ptr].item}; ptr _ column[ptr].link; ENDLOOP; ntdefaults[symbol].count _ k; ENDLOOP}; SquashNTab: PROC = { i, j, k, six, ntix: CARDINAL; nlim _ 0; FOR six IN [1..sLim) DO k _ nlim; FOR ntix IN [statedata[six].ntIndex..statedata[six].ntIndex+statedata[six].ntLink) DO IF ntab[ntix].item # ntdefaults[ntab[ntix].symbol].item THEN { ntab[nlim] _ ntab[ntix]; nlim _ nlim+1}; ENDLOOP; statedata[six].ntIndex _ k; k _ nlim-k; statedata[six].ntLink _ k; IF k#0 THEN FOR i IN [1..six) DO --do these entries match those of an existing state k _ statedata[six].ntIndex-statedata[i].ntIndex; IF statedata[six].ntLink=statedata[i].ntLink THEN -- same length FOR j IN [statedata[i].ntIndex..statedata[i].ntIndex+statedata[i].ntLink) DO IF ntab[j]#ntab[j+k] THEN EXIT; REPEAT FINISHED => { --there is a matching set of entries statedata[six].ntLink _ -i; -- point state six at state i nlim _ statedata[six].ntIndex; -- back up index EXIT}; ENDLOOP; ENDLOOP; ENDLOOP}; PrintNDef: PROC = { j: CARDINAL; item: PGSTypes.ItemRec; outstring["\nNonterminal Default Actions\n"L]; linewidth _ 0; j _ 0; FOR i: CARDINAL IN [2..totalTokens-eofMark+1] DO IF (linewidth _ linewidth+tokenSize+8)>outbufLim THEN { outeol[1]; linewidth _ tokenSize+8}; item _ ntdefaults[i].item; j _ j+ntdefaults[i].count; outnum[IF item.tag=0 THEN item.pss ELSE -item.pss, 5]; outchar[' ,1]; outchar[' , tokenSize+2-OutToken[i+eofMark-1]]; ENDLOOP; outstring["\nEntries removed = "L]; outnum[j,5]; outeol[1]}; TableOverlays: PROC = { j, k: INTEGER; outstring["\nTable Overlays\n row ttab ntab\n"L]; FOR i: CARDINAL IN [1..sLim) DO j _ statedata[i].tLink; k _ statedata[i].ntLink; IF j<0 OR k<0 THEN { outnum[i,4]; IF j<0 THEN outnum[-j, 5] ELSE outchar[' ,5]; IF k<0 THEN outnum[-k, 5]; outeol[1]}; ENDLOOP}; HashTabSetup: PROC = { i, j, k, h, p, count, freeptr, code: CARDINAL; null: CHAR = '\000; outstring["\nScanner hashtable probe counts (terminal symbol, probecount, hashcode)\n"L]; vocabspace _ vocabindex[0] _ 0; freeptr _ hashval; linewidth _ 0; scantab _ ALL[0]; FOR i IN [1..eofMark] DO -- strip quotes, Repack, build vocabindex, scantab and hashtab p _ i*tokenSize; k _ symInfo[i].length; IF k=2 AND symTab[p]='' THEN {p _ p+1; k _ 1} ELSE IF k>2 AND symTab[p]='" AND symTab[p+k-1]='" THEN {p_p+1; k_k-2}; IF k=1 AND ~(symTab[p] IN ['a..'z] OR symTab[p] IN ['A..'Z]) THEN { scantab[CARDINAL[symTab[p]-null]] _ i; -- the next two statements are redundant, they keep the new tables identical to the old symTab[vocabspace] _ symTab[p]; vocabspace _ vocabspace+1; vocabindex[i] _ vocabspace} ELSE { FOR j IN [0..k) DO symTab[vocabspace] _ symTab[p+j]; vocabspace _ vocabspace+1; ENDLOOP; vocabindex[i] _ vocabspace; IF i=eofMark THEN LOOP; count _ 1; code _ h _ (((symTab[p]-null)*127+(symTab[p+k-1]-null)) MOD hashval) + 1; IF hashtab[h].symPtr#0 THEN { WHILE h#0 DO j _ h; h _ hashtab[h].link; count _ count+1 ENDLOOP; WHILE hashtab[freeptr].symPtr#0 DO freeptr _ freeptr-1 ENDLOOP; hashtab[j].link _ h _ freeptr}; hashtab[h].symPtr _ i; IF (linewidth _ linewidth+tokenSize+8)>outbufLim THEN { outeol[1]; linewidth _ tokenSize+8}; FOR j IN [vocabindex[i-1]..vocabindex[i]) DO outchar[symTab[j],1] ENDLOOP; outchar[' ,tokenSize-k]; outnum[count,2]; outnum[code,4]; outchar[' ,2]}; ENDLOOP; IF (j _ vocabspace MOD cpw)#0 THEN -- pad to word boundary THROUGH [j..cpw) DO symTab[vocabspace] _ null ENDLOOP; outeol[1]}; StatePartition: PROC = { i, j: CARDINAL; i_2; j_sLim-1; DO WHILE statedata[j].ntLink=0 AND i<=j DO j_j-1 ENDLOOP; -- j indexes an ntstate WHILE statedata[i].ntLink#0 AND i=j IF i>=j THEN EXIT ELSE {i_i+1; j_j-1}; -- simulate renumbering ENDLOOP; lastntstate_j}; StateRenumber: PROC = { i, j: CARDINAL; k: INTEGER; swaprec: PGSTypes.StateDataRec; i_2; j_sLim-1; DO WHILE statedata[j].ntLink=0 AND i<=j DO j_j-1 ENDLOOP; -- j indexes an ntstate WHILE statedata[i].ntLink#0 AND i=j IF i>=j THEN EXIT ELSE {renumber[i]_j; renumber[j]_i; i_i+1; j_j-1}; -- if j outword[item.pss]; 1 => outword[item.jf*2048+item.pss]; 2 => outword[(16+item.jf)*2048+item.pss]; ENDCASE}; }.