-- file PGSTab.mesa -- last modified by Satterthwaite, July 14, 1980 1:18 PM DIRECTORY PGScondefs: FROM "pgscondefs"; PGSTab: PROGRAM IMPORTS PGScondefs EXPORTS PGScondefs = BEGIN OPEN PGScondefs; linewidth, hashval,lastntstate, vocabspace, nlim, tlim: CARDINAL; hashtab: Hashtab; ttab: Ttab; ntab: Ntab; statedata: Statedata; ntdefaults: Ntdefaults; column: Column; renumber: Renumber; vocabindex: Vocabindex; scantab: ARRAY [40B..177B] OF CARDINAL; tabgen: PUBLIC PROC RETURNS [BOOLEAN] = BEGIN success: BOOLEAN ← TRUE; error: PROC [sel: CARDINAL] = BEGIN outeol[1]; outstring[SELECT sel FROM 1 => "FAIL - more than 255 terminal symbols"L, 2 => "FAIL - more than 254 nonterminal symbols"L, 3 => "FAIL - more than 2047 states or productions"L, 4 => "FAIL - more than 15 symbols in a production right part"L, ENDCASE => ""]; outeol[1]; success ← FALSE; END; IF eofile > 255 THEN error[1]; IF totaltokens-eofile+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, SIZE[tabrec]]]; ttab ← LOOPHOLE[makearray[tentries, SIZE[tabrec]]]; statedata ← LOOPHOLE[makearray[slim, SIZE[statedatarec]]]; ntdefaults ← LOOPHOLE[makearray[totaltokens-eofile+2, SIZE[ntdefaultrec]]]; column ← LOOPHOLE[makearray[ntentries+1, SIZE[columnrec]]]; tablesetup[]; closewordstream[]; squashntab[]; outeol[1]; outstring["Parse Table Data"L]; outeol[1]; IF flags[printlalr] THEN {printndef[]; tableoverlays[]}; vocabindex ← LOOPHOLE[makearray[eofile+1, SIZE[CARDINAL]]]; hashval ← 3*eofile/2; hashval ← MIN[251, IF hashval MOD 2 = 0 THEN hashval+1 ELSE hashval]; hashtab ← LOOPHOLE[makearray[hashval+1, SIZE[hashtabrec]]]; hashtabsetup[]; -- output scanner tables openwordstream[scratch:FALSE]; outblock[BASE[hashtab], hashval+1]; outblock[BASE[scantab], 96]; outword[vocabspace]; outword[vocabspace]; outblock[BASE[symtab], (vocabspace+cpw-1)/cpw]; outblock[BASE[vocabindex], eofile+1]; FreeSegment[BASE[hashtab]]; FreeSegment[BASE[vocabindex]]; FreeSegment[BASE[syminfo]]; renumber ← LOOPHOLE[makearray[slim, SIZE[CARDINAL]]]; staterenumber[]; --now output parser tables outarray[1,numprod ,proddataitem]; outarray[1,lastntstate ,nstateitem]; outarray[1,lastntstate ,nlenitem]; outarray[0,nlim-1 ,nsymitem]; outarray[0,nlim-1 ,nactionitem]; outarray[2,totaltokens-eofile+1 ,ntdefaultitem]; outarray[1,slim-1 ,tstateitem]; outarray[1,slim-1 ,tlenitem]; outarray[0,tlim-1 ,tsymitem]; outarray[0,tlim-1 ,tactionitem]; FreeSegment[BASE[prodinfo]]; FreeSegment[BASE[ntab]]; FreeSegment[BASE[ntdefaults]]; FreeSegment[BASE[renumber]]; FreeSegment[BASE[statedata]]; FreeSegment[BASE[ttab]]; RETURN [success]; END; tablesetup: PROC = BEGIN defaultitem, item:itemrec; defaultprod, i, j, k, symbol, ttix, ntix, six, index, ptr: CARDINAL; columnentry: PROC = BEGIN 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 => BEGIN column[index].item ← item; IF lastptr=0 THEN --head of list for column "symbol" BEGIN column[index].link ← ntdefaults[symbol].count; ntdefaults[symbol].count ← index; END ELSE BEGIN column[index].link ← column[lastptr].link; column[lastptr].link ← index; END; index ← index+1; END; ENDLOOP; END; 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[]] --set up entries for state six in ttab and ntab DO 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<=eofile THEN {ttab[ttix] ← [symbol, item]; ttix ← ttix+1} ELSE BEGIN symbol ← symbol-eofile+1; ntab[ntix] ← [symbol, item]; ntix ← ntix+1; columnentry[]; END; 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 BEGIN statedata[six].tlink ← -i; -- point state six at state i ttix ← statedata[six].tindex; -- back up index EXIT; END; 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-eofile+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; END; squashntab: PROC = BEGIN 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 these entries match those of an existing state DO 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 BEGIN statedata[six].ntlink ← -i; -- point state six at state i nlim ← statedata[six].ntindex; -- back up index EXIT; END; ENDLOOP; ENDLOOP; ENDLOOP; END; printndef: PROC = BEGIN i, j:CARDINAL; item:itemrec; outeol[1]; outstring["Nonterminal Default Actions"L]; outeol[1]; linewidth ← 0; j ← 0; FOR i IN [2..totaltokens-eofile+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+eofile-1]]; ENDLOOP; outeol[1]; outstring["Entries removed = "L]; outnum[j,5]; outeol[1]; END; tableoverlays: PROC = BEGIN i:CARDINAL; j, k:INTEGER; outeol[1]; outstring["Table Overlays"L]; outeol[1]; outstring[" row ttab ntab"L]; outeol[1]; FOR i IN [1..slim) DO j ← statedata[i].tlink; k ← statedata[i].ntlink; IF j<0 OR k<0 THEN BEGIN outnum[i,4]; IF j<0 THEN outnum[-j, 5] ELSE outchar[' ,5]; IF k<0 THEN outnum[-k, 5]; outeol[1]; END; ENDLOOP; END; hashtabsetup: PROC = BEGIN i, j, k, h, p, count, freeptr, code:CARDINAL; null:CHARACTER = 0C; outeol[1]; outstring["Scanner hashtable probe counts (terminal symbol, probecount, hashcode)"L]; outeol[1]; vocabspace ← vocabindex[0] ← 0; freeptr ← hashval; linewidth ← 0; FOR i IN [40B..177B] DO scantab[i]←0 ENDLOOP; FOR i IN [1..eofile] -- strip quotes, repack, build vocabindex, scantab and hashtab DO 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] AND symtab[p] ~IN ['A..'Z] THEN BEGIN 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; END ELSE BEGIN FOR j IN [0..k) DO symtab[vocabspace] ← symtab[p+j]; vocabspace ← vocabspace+1; ENDLOOP; vocabindex[i] ← vocabspace; IF i=eofile THEN LOOP; count ← 1; code ← h ← (((symtab[p]-null)*127+(symtab[p+k-1]-null)) MOD hashval) + 1; IF hashtab[h].symptr#0 THEN BEGIN 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; END; 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]; END; ENDLOOP; IF (j ← vocabspace MOD cpw)#0 THEN THROUGH [j..cpw) -- pad to word boundary DO symtab[vocabspace] ← null ENDLOOP; outeol[1]; END; staterenumber: PROC = BEGIN i, j: CARDINAL; k: INTEGER; swaprec: statedatarec; i←2; j←slim-1; DO WHILE statedata[j].ntlink=0 AND i<=j DO j←j-1 ENDLOOP; -- leaves j indexing an ntstate WHILE statedata[i].ntlink#0 AND i<j DO i←i+1 ENDLOOP; -- i indexes a tstate unless i>=j IF i>=j THEN EXIT ELSE BEGIN renumber[i]←j; renumber[j]←i; i←i+1; j←j-1; -- if j<i now, j indexes the renumbered nstate END; ENDLOOP; lastntstate←j; -- renumber the transition entries FOR i IN [0..tlim) DO IF ttab[i].item.tag=0 AND (j←renumber[ttab[i].item.pss])#0 THEN ttab[i].item.pss←j; ENDLOOP; FOR i IN [0..nlim) DO IF ntab[i].item.tag=0 AND (j←renumber[ntab[i].item.pss])#0 THEN ntab[i].item.pss←j; ENDLOOP; FOR i IN [2..totaltokens-eofile+1] DO IF ntdefaults[i].item.tag=0 AND (j←renumber[ntdefaults[i].item.pss])#0 THEN ntdefaults[i].item.pss←j; ENDLOOP; -- remove links and renumber states FOR i IN [1..slim) DO k ← statedata[i].tlink; IF k<0 THEN BEGIN statedata[i].tlink ← statedata[-k].tlink; statedata[i].tindex ← statedata[-k].tindex; END; k ← statedata[i].ntlink; IF k<0 THEN BEGIN statedata[i].ntlink ← statedata[-k].ntlink; statedata[i].ntindex ← statedata[-k].ntindex; END; ENDLOOP; FOR i IN [2..lastntstate] DO IF (j←renumber[i])#0 THEN BEGIN swaprec ← statedata[i]; statedata[i] ← statedata[j]; statedata[j] ← swaprec; END; ENDLOOP; IF flags[printlalr] THEN BEGIN outeol[1]; outstring["Renumbered States"L]; outeol[1]; FOR i IN [2..lastntstate] DO IF renumber[i]#0 THEN BEGIN outnum[i,4]; outstring[" swapped with"L]; outnum[renumber[i],4]; outeol[1]; END; ENDLOOP; END; END; outmodule: PUBLIC PROC [typename, modfname: STRING] = BEGIN i,j,k: CARDINAL; outrange: PROC [id,cover: STRING, ulim: CARDINAL] = BEGIN outchar[' ,2]; outstring[id]; outstring[": TYPE = "L]; outstring[cover]; outstring["[0.."L]; outnum[ulim,3]; outstring["];"L]; outeol[1]; END; outstring["-- file "L]; outstring[modfname]; outeol[1]; outstring["-- created by PGS from "L]; outstring[sourceName]; outstring[", "L]; outtime[]; outeol[2]; outstring[typename]; outstring[": DEFINITIONS = "L]; outeol[1]; outstring[" BEGIN"L]; outeol[2]; outrange["Symbol"L,"",maxcharcode]; outrange["TSymbol"L,"Symbol "L,eofile]; outrange["NTSymbol"L,"Symbol "L,totaltokens-eofile+1]; outeol[1]; outstring["-- token indices for the scanner and parser"L]; outeol[1]; FOR i IN [0..nextalias) DO outchar[' ,2]; k ← aliases[i].alias*tokensize; FOR j IN [k..k+tokensize) WHILE symtab[j]#0C DO outchar[symtab[j],1] ENDLOOP; outstring[": TSymbol ="L]; outnum[aliases[i].terminal,3]; outchar[';,1]; outeol[1]; ENDLOOP; FreeSegment[BASE[symtab]]; FreeSegment[BASE[aliases]]; outeol[1]; outstring[" Default"L]; outstring["Marker: TSymbol ="L]; outstring[" FIRST"L]; outstring["[TSymbol];"L]; outeol[1]; outstring[" End"L]; outstring["Marker: TSymbol ="L]; outstring[" LAST"L]; outstring["[TSymbol];"L]; outeol[2]; outrange["HashIndex"L,"",hashval]; outrange["VIndex"L,"",vocabspace-1]; outstring[" VocabHashEntry: TYPE = MACHINE DEPENDENT RECORD [ symbol: [0..377B], -- symbol index (TSymbol) link: [0..377B]]; -- link to next entry (HashIndex)"L]; outeol[2]; outrange["State"L,"",slim-1]; outrange["NTState"L,"State "L,lastntstate]; outrange["TIndex"L,"",tlim-1]; outrange["NTIndex"L,"",nlim-1]; outrange["Production"L,"",numprod]; outeol[1]; outstring[" Initial"L]; outstring["State: State = "L]; outnum[1,1]; outchar[';,1]; outeol[1]; outstring[" Final"L]; outstring["State: State = "L]; outnum[0,1]; outchar[';,1]; outeol[1]; outstring[" ActionTag: TYPE = MACHINE DEPENDENT RECORD [ reduce: BOOLEAN, -- TRUE iff reduce entry pLength: [0..17B]]; -- number of symbols in production rhs ActionEntry: TYPE = MACHINE DEPENDENT RECORD [ tag: ActionTag, -- [FALSE,0] if a shift entry transition: [0..3777B]]; -- production number / next state ProductionInfo: TYPE = MACHINE DEPENDENT RECORD [ rule: [0..377B], -- reduction rule lhs: Symbol]; -- production lhs symbol (NTSymbol) Table: TYPE = MACHINE DEPENDENT RECORD [ scanTable: RECORD[ hashTab: ARRAY HashIndex OF VocabHashEntry, scanTab: ARRAY CHARACTER [40C..177C] OF TSymbol, vocabBody: RECORD [ -- a string body length, maxlength: CARDINAL, text: PACKED ARRAY VIndex OF CHARACTER], vocabIndex: ARRAY TSymbol OF CARDINAL], parseTable: RECORD[ prodData: ARRAY Production OF ProductionInfo, nStart: ARRAY NTState OF NTIndex, nLength: ARRAY NTState OF CARDINAL, nSymbol: ARRAY NTIndex OF NTSymbol, nAction: ARRAY NTIndex OF ActionEntry, ntDefaults: ARRAY NTSymbol OF ActionEntry, tStart: ARRAY State OF TIndex, tLength: ARRAY State OF CARDINAL, tSymbol: ARRAY TIndex OF TSymbol, tAction: ARRAY TIndex OF ActionEntry]]; Handle: TYPE = POINTER TO Table;"L]; outeol[2]; outstring[" END."L]; outeol[1]; END; proc: TYPE = PROC [index:CARDINAL]; outarray: PROC [llim,ulim: CARDINAL, p: proc] = BEGIN i: CARDINAL; THROUGH [0..llim) DO outword[0] ENDLOOP; FOR i IN [llim..ulim] DO p[i] ENDLOOP; END; proddataitem: proc = {outword[prodinfo[index].rule*256+(prodinfo[index].lhs-eofile+1)]}; nstateitem: proc = {outword[statedata[index].ntindex]}; nlenitem: proc = {outword[statedata[index].ntlink]}; nsymitem: proc = {outword[ntab[index].symbol]}; nactionitem: proc = {repack[ntab[index].item]}; ntdefaultitem: proc = {repack[ntdefaults[index].item]}; tstateitem: proc = {outword[statedata[index].tindex]}; tlenitem: proc = {outword[statedata[index].tlink]}; tsymitem: proc = {outword[ttab[index].symbol]}; tactionitem: proc = {repack[ttab[index].item]}; repack: PROC [item: itemrec] = BEGIN SELECT item.tag FROM 0 => outword[item.pss]; 1 => outword[item.jf*2048+item.pss]; 2 => outword[(16+item.jf)*2048+item.pss]; ENDCASE; END; END.