-- file PGSScan.Mesa rewritten by PGS, 29-Aug-80 9:27 -- file PGSScan.Mesa -- syntax last modified by Satterthwaite, 7-Jan-80 11:31 -- code last modified by Satterthwaite, July 14, 1980 2:53 PM DIRECTORY PGS1: TYPE USING [ErrorContext, InputLoc, locateindex, Token], ParseTable: FROM "PGSParseTable" USING [ ActionEntry, EndMarker, Handle, HashIndex, Production, ProductionInfo, tokenID, tokenNUM, tokenTAB3, tokenTAB4, TSymbol, VocabHashEntry], PGScondefs: TYPE; Scanner: PROGRAM IMPORTS PGS1, PGScondefs EXPORTS PGS1, PGScondefs = BEGIN OPEN PGS1, ParseTable, PGScondefs; hashTab: POINTER TO ARRAY HashIndex OF VocabHashEntry; scanTab: POINTER TO ARRAY CHARACTER [40C..177C] OF TSymbol; vocab: STRING; vocabIndex: POINTER TO ARRAY TSymbol OF CARDINAL; check: CARDINAL = 3; warning: CARDINAL = 0; specErrorCases: CARDINAL = 5; token, numRhsChars: CARDINAL; lineWidth: INTEGER; insertFlag: CARDINAL; hashChain: DESCRIPTOR FOR ARRAY [1..symtabsize/4] OF CARDINAL; ProductionArray: TYPE = ARRAY Production OF ProductionInfo; -- local data base (supplied by parser) v: DESCRIPTOR FOR ARRAY OF UNSPECIFIED; l: DESCRIPTOR FOR ARRAY OF CARDINAL; q: DESCRIPTOR FOR ARRAY OF ActionEntry; prodData: POINTER TO ProductionArray; -- initialization/termination AssignDescriptors: PUBLIC PROC [ qd: DESCRIPTOR FOR ARRAY OF ActionEntry, vd: DESCRIPTOR FOR ARRAY OF UNSPECIFIED, ld: DESCRIPTOR FOR ARRAY OF CARDINAL, pp: POINTER TO ProductionArray] = {q ← qd; v ← vd; l ← ld; prodData ← pp}; outtoken: PUBLIC PROC [symbol:CARDINAL] RETURNS [CARDINAL] = BEGIN IF symbol=0 THEN {outstring["* * *"]; RETURN[5]}; FOR i:CARDINAL IN [0..syminfo[symbol].length) DO outchar[symtab[symbol*tokensize+i],1] ENDLOOP; RETURN [syminfo[symbol].length] END; -- the interpretation rules prix, chix: CARDINAL; --indexes into prodinfo and rhschar rhsFlag: BOOLEAN; lastSymbol, lhsDef: CARDINAL; ProcessQueue: PUBLIC PROC [qI, top: CARDINAL] = BEGIN qj,i,j,k: CARDINAL; opt: Options; -- local procedures PrintTableHead: PROC [c: CHARACTER]= BEGIN IF flags[echo] THEN {outeol[2];outstring["||TABLE"]; outchar[c,1]; outeol[1]} END; SetRuleChain: PROC [rule: CARDINAL, chain: BOOLEAN] = BEGIN FixLastProd[]; IF prix=LENGTH[prodinfo] THEN --production table overflow prodinfo ← LOOPHOLE[expand[prodinfo,SIZE[prodrecord],LENGTH[prodinfo]/8]]; prodinfo[prix].chain ← chain; IF rule>maxrule THEN Error[check+10,-5,InputLoc[]] ELSE prodinfo[prix].rule ← rule END; FixLastProd: PROC = BEGIN prodinfo[prix-1].lhs ← lhsDef; IF prodinfo[prix-1].count=0 THEN tokeninfo[lhsDef-eofile].empty ← TRUE; IF rhsFlag THEN -- too many rhschars {rhsFlag ← FALSE; Error[check+5, (prix-1+specErrorCases), InputLoc[]]}; END; ProdHeader: PROC [new:BOOLEAN] = BEGIN prodinfo[prix].index ← chix; IF lhsDef>eofile THEN BEGIN IF tokeninfo[lhsDef-eofile].count=alternatelim THEN BEGIN Error[check+1, lhsDef,InputLoc[]]; --too many alternatives tokeninfo[lhsDef-eofile].count ←1 END; tokeninfo[lhsDef-eofile].count ← tokeninfo[lhsDef-eofile].count + 1; END; IF flags[echo] THEN BEGIN lineWidth ← outbuflim-tokensize-14; outeol[IF new THEN 2 ELSE 1];outnum[prix,3]; outstring[IF prodinfo[prix].chain THEN " C " ELSE " "]; outnum[prodinfo[prix].rule,3]; outchar[' ,2]; outchar[' ,tokensize-(IF new THEN outtoken[lhsDef] ELSE 0)]; outstring[IF new THEN " ::= " ELSE " | "]; END; prix ← prix+1 END; LhsSymbol: PROC [symbol:CARDINAL] = BEGIN lhsDef ← symbol; IF lhsDef<=eofile THEN Error[check+4,lhsDef,InputLoc[]] -- undefined or terminal symbol before ::= ELSE IF tokeninfo[lhsDef-eofile].index = 0 THEN tokeninfo[lhsDef-eofile].index ← prix ELSE Error[check+2,lhsDef,InputLoc[]]; --multiple definitions ProdHeader[TRUE]; END; -- end of local procedures FOR qj IN [0..qI) DO top ← top-q[qj].tag.pLength+1; SELECT prodData[q[qj].transition].rule FROM 0 => -- TYPE: ParseTable MODULE: PGSParseTable.mesa -- BINARY: PGSParseData.bcd INTERFACE: SELF -- GOAL: grammar -- TERMINALS: -- symbol num '? '| "::=" 'C "||TABLE1" "||TABLE2" "||TABLE3" -- "||TABLE4" "||INPUT" "||CHAIN" "||LISTS" "||PRINTLR" -- "||PRINTLALR" "||FIRST" "||IDS" "GOAL" -- ALIASES: symbol tokenID num tokenNUM '? tokenQUERY -- "||TABLE3" tokenTAB3 "||TABLE4" tokenTAB4 '? InitialSymbol -- PRODUCTIONS: -- grammar ::= '? head ruleset BEGIN FixLastProd[]; numprod ← prix-1; numRhsChars ← chix-1; i ← 1; IF flags[echo] THEN outeol[1]; IF numprod > psslim OR totaltokens > psslim THEN Error[check+6,0,InputLoc[]]; FreeSegment[BASE[hashChain]]; WHILE syminfo[i].used AND i<=totaltokens DO IF i>eofile AND tokeninfo[i-eofile].index = 0 THEN EXIT; i ← i+1; ENDLOOP; IF i <= totaltokens THEN BEGIN defflag:BOOLEAN ← FALSE; lineWidth ← 0; Error[warning+3,0,InputLoc[]]; seterrstream[]; FOR i IN [i..totaltokens] DO j ← 0; IF ~syminfo[i].used THEN j ← j+1; IF i > eofile AND tokeninfo[i-eofile].index = 0 THEN j ← j+2; IF j # 0 THEN BEGIN IF (lineWidth ← lineWidth+(k←(11+j)/2)) > outbuflim THEN {outeol[1]; lineWidth ← k}; outnum[i,5]; IF j#2 THEN outchar['U,1] ELSE defflag ← TRUE; IF j>1 THEN outchar['D,1] END; ENDLOOP; outeol[1]; resetoutstream[]; IF defflag THEN Error[check+3,-2,InputLoc[]]; -- nonterminal used but not defined END; FOR i IN [1..numprod] DO IF prodinfo[i].chain THEN IF prodinfo[i].count # 1 OR rhschar[prodinfo[i].index] <= eofile THEN BEGIN Error[warning+2, -(i+specErrorCases), InputLoc[]]; prodinfo[i].chain ← FALSE; END; ENDLOOP; END; 1 => -- head ::= directives terminals nonterminals "||TABLE4" -- head ::= directives terminals nonterminals aliases "||TABLE4" BEGIN totaltokens ← lastSymbol; PrintTableHead['4]; tokeninfo ← LOOPHOLE[makearray[totaltokens-eofile+1,SIZE[tokenrecord]]]; prodinfo ← LOOPHOLE[makearray[maxprod+1,SIZE[prodrecord]]]; rhschar ← LOOPHOLE[makearray[maxrhssymbols+1,SIZE[CARDINAL]]]; FOR i IN [0..totaltokens-eofile] DO tokeninfo[i] ← [count:0, empty:FALSE, index:0] ENDLOOP; prodinfo[0] ← [count:2, rule:0, chain:FALSE, lhs:0, index:0]; FOR i IN [1..maxprod] DO prodinfo[i] ← [count:0, rule:0, chain:FALSE, lhs:0, index:0]; ENDLOOP; IF flags[echo] THEN BEGIN outeol[1]; outchar[' ,20]; outstring["GOAL ::= "]; [] ← outtoken[eofile+1]; outchar[' ,1]; [] ← outtoken[eofile] END; rhschar[0] ← eofile+1; rhschar[1] ← eofile; syminfo[eofile+1].used ← syminfo[eofile].used ← TRUE; prix ← 1; chix ← 2; lhsDef ← 0; rhsFlag ← FALSE; END; 2 => -- directives ::= BEGIN FOR opt IN [FIRST[Options]..LAST[Options]] DO flags[opt] ← FALSE ENDLOOP; l[top] ← InputLoc[]; END; 3 => -- directive ::= "||INPUT" {flags[echo] ← TRUE; setoutstream[".echo"]}; 4 => -- directive ::= "||CHAIN" flags[chain] ← TRUE; 5 => -- directive ::= "||LISTS" flags[lists] ← TRUE; 6 => -- directive ::= "||PRINTLR" flags[printlr] ← TRUE; 7 => -- directive ::= "||PRINTLALR" flags[printlalr] ← TRUE; 8 => -- directive ::= "||FIRST" flags[first] ← TRUE; 9 => -- directive ::= "||IDS" flags[ids] ← TRUE; 10 => -- terminals ::= "||TABLE1" BEGIN IF flags[echo] THEN BEGIN outeol[1]; FOR opt IN [FIRST[Options]..LAST[Options]] DO IF flags[opt] THEN outstring[ SELECT opt FROM echo => "||INPUT "L, chain => "||CHAIN "L, lists => "||LISTS "L, printlr => "||PRINTLR "L, printlalr => "||PRINTLALR "L, first => "||FIRST "L, ENDCASE => "||IDS "L]; ENDLOOP; END; PrintTableHead['1]; END; 11 => -- terminals ::= terminals discard symbol -- nonterminals ::= nonterminals discard symbol BEGIN lastSymbol ← v[top+2]; IF flags[echo] THEN BEGIN outnum[lastSymbol, 3]; outchar[' , 2]; [] ← outtoken[lastSymbol]; outeol[1] END; END; 12 => -- nonterminals ::= "||TABLE2" BEGIN PrintTableHead['2]; eofile ← lastSymbol; nextalias ← 0; -- assert TABLE3 empty in case it is omitted END; 13 => -- aliases ::= "||TABLE3" BEGIN PrintTableHead['3]; aliases ← LOOPHOLE[makearray[64,SIZE[aliasrecord]]]; END; 14 => -- aliases ::= aliases symbol symbol BEGIN IF v[top+1]>eofile THEN Error[check+7,v[top+1],InputLoc[]]; IF v[top+2]<=eofile THEN Error[check+8,v[top+2],InputLoc[]]; IF nextalias=LENGTH[aliases] THEN aliases ← LOOPHOLE[expand[aliases,SIZE[aliasrecord],LENGTH[aliases]/8]]; aliases[nextalias] ← [v[top+1],v[top+2]]; nextalias ← nextalias+1; IF flags[echo] THEN BEGIN outchar[' ,tokensize+1-outtoken[v[top+1]]]; outchar[' ,1]; j ← v[top+2]*tokensize; FOR i IN [j..j+tokensize) WHILE symtab[i]#0C DO outchar[symtab[i],1] ENDLOOP; outeol[1]; END; END; 15 => -- discard ::= l[top] ← InputLoc[]; -- keep the parser error recovery happy 16 => -- rulegroup ::= symbol "::=" {SetRuleChain[prix, FALSE]; LhsSymbol[v[top]]}; 17 => -- rulegroup ::= prefix symbol "::=" LhsSymbol[v[top+1]]; 18 => -- rulegroup ::= rulegroup symbol "::=" {SetRuleChain[prix, FALSE]; LhsSymbol[v[top+1]]}; 19 => -- rulegroup ::= rulegroup prefix symbol "::=" LhsSymbol[v[top+2]]; 20 => -- rulegroup ::= rulegroup '| {SetRuleChain[prix, FALSE]; ProdHeader[FALSE]}; 21 => -- rulegroup ::= rulegroup prefix '| ProdHeader[FALSE]; 22 => -- rulegroup ::= rulegroup symbol BEGIN i ← v[top+1]; syminfo[i].used ← TRUE; IF i=eofile OR i=eofile+1 THEN Error[check+9,0,InputLoc[]]; --goal symbols IF flags[echo] THEN BEGIN IF lineWidth<syminfo[i].length THEN BEGIN outeol[1]; outchar[' ,tokensize+18]; lineWidth ← outbuflim - tokensize-18; END; IF (lineWidth ← (lineWidth-outtoken[i]-1)) > 0 THEN outchar[' , 1]; END; IF chix=LENGTH[rhschar] THEN rhschar ← LOOPHOLE[expand[rhschar,SIZE[CARDINAL],LENGTH[rhschar]/8]]; rhschar[chix]←i; chix ← chix +1; IF prodinfo[prix-1].count = rhslim THEN {prodinfo[prix-1].count ← 1; rhsFlag ← TRUE}; prodinfo[prix-1].count ← prodinfo[prix-1].count+1; END; 23 => -- prefix ::= num SetRuleChain[v[top], FALSE]; 24 => -- prefix ::= num num -- prefix ::= '? num SetRuleChain[v[top+1], FALSE]; 25 => -- prefix ::= discard 'C SetRuleChain[prix, TRUE]; 26 => -- prefix ::= discard 'C num SetRuleChain[v[top+2], TRUE]; 27 => -- prefix ::= '? SetRuleChain[prix, FALSE]; 28 => -- directives ::= directives directive -- discard ::= num -- discard ::= '? -- ruleset ::=C rulegroup -- ruleset ::= goalrule rulegroup -- goalrule ::= "GOAL" "::=" symbol symbol NULL; ENDCASE => ERROR; ENDLOOP; END; -- the following procedure is called from the ScanReset if no errors FinishInput: PROCEDURE = BEGIN emptyflag: BOOLEAN ← TRUE; i,j,k,prix,chix: CARDINAL; -- compute nonterminals deriving empty WHILE emptyflag DO emptyflag ← FALSE; FOR i IN [1..totaltokens-eofile] -- each nonterminal DO IF tokeninfo[i].empty THEN LOOP; --which does not derive empty j ← tokeninfo[i].index; FOR prix IN [j..j+tokeninfo[i].count) -- each production of the nonterminal DO k ← prodinfo[prix].index; FOR chix IN [k..k+prodinfo[prix].count) -- each rhs character DO IF rhschar[chix]<=eofile OR ~tokeninfo[rhschar[chix]-eofile].empty THEN EXIT; REPEAT FINISHED => {tokeninfo[i].empty ← emptyflag ← TRUE; EXIT}; ENDLOOP ENDLOOP ENDLOOP ENDLOOP; checkout[]; END; -- the following procedure outputs the data structure contents in the tables: -- PRODUCTIONINFO TOKENINFO SYMINFO -- num count rule chain lhs index count empty index link used length symbol -- 4 1 3 5 1 4 5 2 3 1 5 2 4 1 3 1 ... checkout: PUBLIC PROC = BEGIN i: CARDINAL; IF flags[ids] THEN BEGIN seterrstream[]; outeol[1]; outstring[" PRODUCTIONINFO TOKENINFO SYMINFO"]; FOR i IN [0..MAX[numprod,totaltokens]] DO outeol[1]; outnum[i,4]; outchar[' ,1]; IF i>numprod THEN outchar[' ,20] ELSE BEGIN outnum[prodinfo[i].count,3]; outnum[prodinfo[i].rule,5]; outchar[IF prodinfo[i].chain THEN 'C ELSE ' , 1]; outnum[prodinfo[i].lhs,4]; outnum[prodinfo[i].index,5]; outchar[' ,2]; END; IF i<=totaltokens AND i>0 THEN BEGIN IF i<=eofile THEN outchar[' ,11] ELSE BEGIN outnum[tokeninfo[i-eofile].count,3]; outchar[IF tokeninfo[i-eofile].empty THEN 'E ELSE ' ,1]; outnum[tokeninfo[i-eofile].index,5]; outchar[' ,2] END; outnum[syminfo[i].link,4]; outchar[IF syminfo[i].used THEN 'U ELSE ' ,1]; outnum[syminfo[i].length,3]; outchar[' ,1]; [] ← outtoken[i]; END ENDLOOP; outeol[1]; outstring["RHSCHAR"]; lineWidth ← outbuflim; FOR i IN [0..numRhsChars] DO lineWidth ← lineWidth+tokensize+1; IF lineWidth > outbuflim THEN {outeol[1]; outnum[i,4]; lineWidth ← 4}; outchar[' ,1]; [] ← outtoken[rhschar[i]]; ENDLOOP; outeol[1]; resetoutstream[]; END; END; -- error recovery TokenValue: PUBLIC PROC [s: TSymbol] RETURNS [UNSPECIFIED] = {RETURN [0]}; -- text input and error routines NUL: CHARACTER = 0C; tB: POINTER TO PACKED ARRAY OF CHARACTER; tI, tMax: [0..TextChars]; tOrigin, tLimit: CARDINAL; tEnded: BOOLEAN; FillTextBuffer: PROC = BEGIN tOrigin ← tLimit; IF tEnded THEN tMax ← 0 ELSE {[tB, tMax, tEnded] ← nextbuffer[]; tLimit ← tOrigin + tMax}; IF tMax = 0 THEN {tB[0] ← NUL; tMax ← 1}; tI ← 0; END; buffer: STRING = [tokensize]; -- token assembly area nTokens: CARDINAL; -- token count nErrors: CARDINAL; -- lexical errors char: CHARACTER; -- current (most recently scanned) character NextChar: PROC = -- also expanded inline within Atom BEGIN IF (tI←tI+1) = tMax THEN FillTextBuffer[]; char ← tB[tI]; END; Atom: PUBLIC PROC RETURNS [t: Token] = BEGIN OPEN t; LocateToken: PROC [string: STRING] RETURNS [CARDINAL] = BEGIN -- returns token corresponding to string i,j,k: CARDINAL; j ← hashChain[(string.length*256+LOOPHOLE[string[0],CARDINAL]) MOD (symtabsize/4) + 1]; WHILE j # 0 DO IF syminfo[j].length = string.length THEN BEGIN i ← j*tokensize; FOR k IN [0..string.length) DO IF symtab[i+k]#string[k] THEN EXIT REPEAT FINISHED => RETURN[j] ENDLOOP; END; j ← syminfo[j].link; ENDLOOP; RETURN [0] END; TokenToSymTab: PROC [string: STRING, token: CARDINAL] = BEGIN i,j: CARDINAL; i ← token*tokensize; FOR j IN [0..string.length) DO symtab[i+j] ← string[j] ENDLOOP; syminfo[token].length ← string.length; syminfo[token].used ← FALSE; j ← (string.length*256+LOOPHOLE[string[0],CARDINAL]) MOD (symtabsize/4) + 1; syminfo[token].link ← hashChain[j]; hashChain[j] ← token; END; TokenOrId: PROC [sub:CARDINAL]= BEGIN j, s1, s2: CARDINAL; h: HashIndex; WHILE char ~IN [NUL..' ] DO IF sub<tokensize THEN buffer[sub] ← char; sub ← sub + 1; NextChar[]; ENDLOOP; IF sub>tokensize THEN {buffer.length←sub←tokensize; Error[1,-1,index]}; --overlength IF sub = 1 THEN BEGIN class ← scanTab[buffer[0]]; IF class # 0 THEN RETURN END; j ← buffer[0] - 0C; h ← ((j*128-j) + CARDINAL[buffer[sub-1]-0C]) MOD LAST[HashIndex] + 1; WHILE (j ← hashTab[h].symbol) # 0 DO IF vocabIndex[j]-(s2←vocabIndex[j-1]) = sub THEN FOR s1 IN [0 .. sub) DO IF buffer[s1] # vocab[s2] THEN EXIT; s2 ← s2+1; REPEAT FINISHED => BEGIN IF j = tokenTAB3 THEN insertFlag ← 2 ELSE IF j = tokenTAB4 THEN insertFlag ← 3; IF j<=tokenNUM THEN EXIT; class ← j; RETURN END; ENDLOOP; IF (h ← hashTab[h].link) = 0 THEN EXIT; ENDLOOP; buffer.length←sub; class←tokenID; value←LocateToken[buffer]; SELECT insertFlag FROM 1 => -- reading terminals and nonterminals IF value # 0 THEN Error[check+2,value,index] -- multiply defined symbol ELSE BEGIN IF token=LENGTH[symtab] THEN BEGIN symtab ← LOOPHOLE[ expand[LOOPHOLE[symtab],wordsfortoken,LENGTH[symtab]/16]]; syminfo ← LOOPHOLE[expand[syminfo,SIZE[symtabrecord],LENGTH[syminfo]/16]]; END; TokenToSymTab[buffer, token]; value ← token; token ← token+1; END; 2 => -- processing aliases IF value=0 THEN BEGIN s1 ← token*tokensize; IF token=LENGTH[symtab] THEN symtab ← LOOPHOLE[ expand[LOOPHOLE[symtab],wordsfortoken,LENGTH[symtab]/16]]; FOR j IN [0..buffer.length) DO symtab[s1+j] ← buffer[j] ENDLOOP; value ← token; token ← token+1; END; 3 => -- processing productions IF value = 0 THEN Error[check+3,-3,index]; --symbol not defined ENDCASE; END; DO WHILE char IN [NUL..' ] DO SELECT char FROM ControlZ => UNTIL char = CR DO IF (tI←tI+1) = tMax THEN {IF tEnded THEN GO TO EndFile; FillTextBuffer[]}; char ← tB[tI]; ENDLOOP; ENDCASE; IF (tI←tI+1) = tMax THEN {IF tEnded THEN GO TO EndFile; FillTextBuffer[]}; char ← tB[tI]; ENDLOOP; index ← tOrigin + tI; value ← 0; SELECT char FROM IN ['0..'9] => BEGIN val:CARDINAL; valid:BOOLEAN; maxval:CARDINAL=6553; maxd:CARDINAL = 5; valid ← TRUE; val ← 0; WHILE char IN ['0..'9] DO IF valid THEN BEGIN d:[0..9]; d ← char-'0; val ← 10*val +d; valid ← val<maxval OR (val=maxval AND d<=maxd); END; NextChar[]; ENDLOOP; IF ~valid THEN val ←maxval*10+maxd; class ← tokenNUM; value ← val; GO TO GotNext; END; '- => BEGIN pChar: CHARACTER; NextChar[]; IF char # '- THEN {buffer[0] ← '-; TokenOrId[1]; GO TO GotNext}; char ← NUL; DO pChar ← char; IF (tI←tI+1) = tMax THEN {IF tEnded THEN GO TO EndFile; FillTextBuffer[]}; char ← tB[tI]; SELECT char FROM '- => IF pChar = '- THEN EXIT; CR => EXIT; ENDCASE; ENDLOOP; NextChar[]; END; ENDCASE => {TokenOrId[0]; GO TO GotNext}; REPEAT GotNext => NULL; EndFile => BEGIN FillTextBuffer[]; char ← tB[tI]; class ← EndMarker; index ← tOrigin; value ← 0; END; ENDLOOP; nTokens ← nTokens + 1; RETURN END; -- initialization/finalization ScanInit: PUBLIC PROC [tablePtr: ParseTable.Handle] = BEGIN i: CARDINAL; hashTab ← @tablePtr.scanTable.hashTab; scanTab ← @tablePtr.scanTable.scanTab; vocab ← LOOPHOLE[@tablePtr.scanTable.vocabBody, STRING]; vocabIndex ← @tablePtr.scanTable.vocabIndex; tLimit ← 0; tMax ← 0; tEnded ← FALSE; FillTextBuffer[]; char ← tB[tI]; nTokens ← nErrors ← 0; buffer.length ← tokensize; -- initialise symbol table token ← 1; insertFlag ← 1; symtab ← LOOPHOLE[makearray[symtabsize+1,wordsfortoken]]; syminfo ← LOOPHOLE[makearray[symtabsize+1,SIZE[symtabrecord]]]; FOR i IN [1..symtabsize] DO syminfo[i] ← [link:0, length:0, used:FALSE] ENDLOOP; hashChain ← DESCRIPTOR[AllocateSegment[symtabsize/4],symtabsize/4]; FOR i IN [1..symtabsize/4] DO hashChain[i] ← 0 ENDLOOP; END; ScanReset: PUBLIC PROC [pErrors: CARDINAL] RETURNS [CARDINAL, CARDINAL] = BEGIN IF (pErrors+nErrors)=0 THEN FinishInput[]; RETURN [nTokens, nErrors] END; -- error handling ResetScanIndex: PUBLIC PROC [index: CARDINAL] = BEGIN IF index = tLimit THEN {FillTextBuffer[]; char ← tB[tI]; RETURN}; IF index < tOrigin THEN BEGIN tLimit ← locateindex[index]; tMax ← 0; tEnded ← FALSE; FillTextBuffer[]; END; tI ← index - tOrigin; char ← tB[tI]; END; Error: PROC [code: CARDINAL, control: INTEGER, index: CARDINAL]= BEGIN ErrorContext[ SELECT code FROM 1 => "WARNING - Overlength symbol (increase TOKENSIZE?) truncated to - "L, 2 => "WARNING - Not a chain production - "L, 3 => "WARNING - Unused(U) or undefined(D)symbols (refer to TABLE1 and 2)"L, 4 => "ERROR - Nonterminal with too many rules (increase ALTERNATELIM?) - "L, 5 => "ERROR - Multiple definitions of symbol - "L, 6 => "ERROR - Symbol not defined - "L, 7 => "ERROR - Terminal precedes ::= - "L, 8 => "ERROR - Too many rhs symbols in production (increase RHSLIM?) - "L, 9 => "ERROR - Internal field will overflow - increase PSSLIM"L, 10 => "ERROR - Aliased symbol not a terminal symbol - "L, 11 => "ERROR - Aliases must not be terminal symbols - "L, 12 => "ERROR - Goal symbols used in rhs"L, 13 => "ERROR - Number greater than "L, ENDCASE => NIL, index]; IF code>check THEN nErrors ← nErrors+1; SELECT -control FROM <0 => [] ← outtoken[control]; 0 => NULL; 1 => outstring[buffer]; 2 => outstring["see previous message"L]; 3 => {outstring[buffer]; outstring[" not in TABLE1 or 2"L]}; 4 => NULL; -- not used 5 => outstring["MAXRULE"L]; ENDCASE => outnum[-control-specErrorCases, 5]; outeol[2]; IF code<=check THEN warningslogged ← TRUE; resetoutstream[]; END; END.