-- file DIParser.Mesa -- last modified by -- Sandman, January 16, 1979 3:58 PM -- Barbara, May 15, 1978 11:13 AM -- Bruce, July 23, 1980 5:50 PM DIRECTORY CompilerUtil USING [parse, LockTableSegment, UnlockTableSegment], DebugOps USING [], Inline USING [COPY, LowHalf], P1 USING [AssignDescriptors, Atom, lastntstate, ProcessQueue, ScanInit, ScanReset, Token], ParseTable USING [ActionEntry, ActionTag, DefaultMarker, FinalState, Handle, InitialState, NTIndex, NTSymbol, ProductionInfo, State, TIndex, TSymbol], Storage USING [FreePages, Pages, PagesForWords]; Parser: PROGRAM IMPORTS CompilerUtil, P1, Inline, Storage EXPORTS DebugOps, P1 = BEGIN -- Debugger Interpreter parser with no error recovery OPEN P1, ParseTable; ParseError: PUBLIC SIGNAL [errorLoc: CARDINAL] = CODE; SyntaxError: PUBLIC SIGNAL [errorLoc: CARDINAL] = CODE; currentState: State; inputSymbol, lhs: TSymbol; input: PROCEDURE RETURNS [symbol: Token]; inputLoc: CARDINAL; inputValue: UNSPECIFIED; qI, top: CARDINAL; stackSize: CARDINAL; queueSize: CARDINAL; q: DESCRIPTOR FOR ARRAY OF ActionEntry; --reduction rules v: DESCRIPTOR FOR ARRAY OF UNSPECIFIED; --parse stack l: DESCRIPTOR FOR ARRAY OF CARDINAL; --sourceline index s: DESCRIPTOR FOR ARRAY OF State; -- transition tables for terminal input symbols tStart: DESCRIPTOR FOR ARRAY OF TIndex; tLength: DESCRIPTOR FOR ARRAY OF CARDINAL; tSymbol: DESCRIPTOR FOR ARRAY OF TSymbol; tAction: DESCRIPTOR FOR ARRAY OF ActionEntry; -- transition tables for nonterminal input symbols nStart: DESCRIPTOR FOR ARRAY OF NTIndex; nLength: DESCRIPTOR FOR ARRAY OF CARDINAL; nSymbol: DESCRIPTOR FOR ARRAY OF NTSymbol; nAction: DESCRIPTOR FOR ARRAY OF ActionEntry; ntDefaults: DESCRIPTOR FOR ARRAY OF ActionEntry; proddata: DESCRIPTOR FOR ARRAY OF ProductionInfo; -- initialization/termination refCount: CARDINAL ← 0; table: ParseTable.Handle; Initialize: PROCEDURE [s: STRING] = BEGIN OPEN CompilerUtil; refCount ← refCount + 1; IF refCount > 1 THEN ParseInit[s, NIL] ELSE {table ← Inline.LowHalf[LockTableSegment[parse]]; ParseInit[s, table]}; END; Finalize: PROCEDURE = BEGIN EraseQueue[]; EraseStack[]; refCount ← refCount - 1; IF refCount = 0 THEN CompilerUtil.UnlockTableSegment[CompilerUtil.parse]; END; ParseInit: PROCEDURE [string: STRING, table: ParseTable.Handle] = BEGIN OPEN table; ScanInit[string, table]; stackSize ← queueSize ← 0; ExpandStack[64]; ExpandQueue[256]; IF table # NIL THEN BEGIN tStart ← DESCRIPTOR[parseTable.tStart]; tLength ← DESCRIPTOR[parseTable.tLength]; tSymbol ← DESCRIPTOR[parseTable.tSymbol]; tAction ← DESCRIPTOR[parseTable.tAction]; nStart ← DESCRIPTOR[parseTable.nStart]; nLength ← DESCRIPTOR[parseTable.nLength]; nSymbol ← DESCRIPTOR[parseTable.nSymbol]; nAction ← DESCRIPTOR[parseTable.nAction]; ntDefaults ← DESCRIPTOR[parseTable.ntDefaults]; proddata ← DESCRIPTOR[parseTable.prodData]; END; RETURN END; InputLoc: PUBLIC PROCEDURE RETURNS [CARDINAL] = BEGIN RETURN [inputLoc] END; -- the main parsing procedures DParse: PUBLIC PROCEDURE [string: STRING] RETURNS [complete: BOOLEAN] = BEGIN i, valid, k, m: CARDINAL; -- stack pointers j, j0: CARDINAL; tj: ActionEntry; input ← Atom; Initialize[string]; i ← top ← valid ← 0; qI ← 0; s[0] ← currentState ← InitialState; [inputSymbol, inputValue, inputLoc] ← input[].symbol; WHILE currentState # FinalState DO BEGIN j0 ← tStart[currentState]; FOR j IN [j0 .. j0 + tLength[currentState]) DO SELECT tSymbol[j] FROM inputSymbol, DefaultMarker => EXIT; ENDCASE; REPEAT FINISHED => GO TO SyntaxError; ENDLOOP; tj ← tAction[j]; IF ~tj.tag.reduce -- scan or scan reduce entry THEN BEGIN IF qI > 0 THEN BEGIN FOR k IN (valid..i] DO s[k] ← s[top+(k-valid)] ENDLOOP; AssignDescriptors[q,v,l,proddata]; ProcessQueue[qI, top ! ParseError => GO TO SyntaxError; UNWIND => Finalize[]]; qI ← 0; EXITS SyntaxError => BEGIN Finalize[]; SIGNAL SyntaxError[inputLoc]; END; END; top ← valid ← i ← i+1; v[i] ← inputValue; l[i] ← inputLoc; [inputSymbol,inputValue,inputLoc] ← input[].symbol; END; WHILE tj.tag # ActionTag[FALSE, 0] DO IF qI >= queueSize THEN ExpandQueue[256]; q[qI] ← tj; qI ← qI + 1; i ← i-tj.tag.pLength; -- pop 1 state per rhs symbol currentState ← s[IF i > valid THEN top+(i-valid) ELSE (valid ← i)]; lhs ← proddata[tj.transition].lhs; BEGIN IF currentState <= lastntstate THEN BEGIN j ← nStart[currentState]; FOR j IN [j..j+nLength[currentState]) DO IF lhs = nSymbol[j] THEN BEGIN tj ← nAction[j]; GO TO nfound END; ENDLOOP; END; tj ← ntDefaults[lhs]; EXITS nfound => NULL; END; i ← i+1; ENDLOOP; IF (m ← top+(i-valid)) >= stackSize THEN ExpandStack[64]; s[m] ← currentState ← tj.transition; EXITS SyntaxError => BEGIN Finalize[]; SIGNAL SyntaxError[inputLoc]; END; END; ENDLOOP; BEGIN AssignDescriptors[q,v,l,proddata]; ProcessQueue[qI, top ! ParseError => GOTO SyntaxError; UNWIND => Finalize[]]; EXITS SyntaxError => BEGIN Finalize[]; SIGNAL SyntaxError[inputLoc]; END; END; Finalize[]; RETURN [ScanReset[]] END; ExpandStack: PROCEDURE [delta: CARDINAL] = BEGIN sS, sL, sV: CARDINAL; p: POINTER; newS: DESCRIPTOR FOR ARRAY OF State; newL: DESCRIPTOR FOR ARRAY OF CARDINAL; newV: DESCRIPTOR FOR ARRAY OF UNSPECIFIED; newSize: CARDINAL = stackSize + delta; sS ← newSize*SIZE[State]; sL ← newSize*SIZE[CARDINAL]; sV ← newSize*SIZE[UNSPECIFIED]; p ← Storage.Pages[Storage.PagesForWords[sS+sL+sV]]; newS ← DESCRIPTOR[p, newSize]; newL ← DESCRIPTOR[p+sS, newSize]; newV ← DESCRIPTOR[p+sS+sL, newSize]; IF stackSize # 0 THEN BEGIN Inline.COPY[from: BASE[s], nwords: stackSize, to: BASE[newS]]; Inline.COPY[from: BASE[l], nwords: stackSize, to: BASE[newL]]; Inline.COPY[from: BASE[v], nwords: stackSize, to: BASE[newV]]; EraseStack[]; END; s ← newS; l ← newL; v ← newV; stackSize ← newSize; RETURN END; EraseStack: PROCEDURE = BEGIN IF stackSize = 0 THEN RETURN; stackSize ← 0; Storage.FreePages[BASE[s]]; RETURN END; ExpandQueue: PROCEDURE [delta: CARDINAL] = BEGIN newQ: DESCRIPTOR FOR ARRAY OF ActionEntry; newSize: CARDINAL = queueSize + delta; newQ ← DESCRIPTOR[Storage.Pages[Storage.PagesForWords[ newSize*SIZE[ActionEntry]]], newSize]; IF queueSize # 0 THEN BEGIN Inline.COPY[from: BASE[q], nwords: newSize, to: BASE[newQ]]; EraseQueue[]; END; q ← newQ; queueSize ← newSize; RETURN END; EraseQueue: PROCEDURE = BEGIN IF queueSize = 0 THEN RETURN; queueSize ← 0; Storage.FreePages[BASE[q]]; RETURN END; END.