-- Modified version of the Tool Driver's TDParser

DIRECTORY
  Format USING [Decimal],
  MStream USING [Handle],
  ParseInterface USING [
    ActionEntry, ActionTag, DefaultMarker, FinalState, InitialState, 
    NTIndex, NTState, NTSymbol, ProductionInfo, State,
    TableRef, TIndex, TSymbol, EndMarker, tSEMICOLON],
  Runtime USING [GetTableBase, GlobalFrame],
  Storage USING [FreePages, Pages, PagesForWords],
  ParseTables USING [],
  ParseDefs USING [AssignDescriptors, Atom, ProcessQueue, ScanInit,
  	ScanFinal, Value, Value2, ErrorContext], 
  PrintingDefs USING [outProc, OutCode]; 
    
Parser: PROGRAM
    IMPORTS Format, Runtime, Storage, ParseTables, ParseDefs, PrintingDefs EXPORTS ParseDefs = {
  OPEN ParseInterface;

  errorLimit: CARDINAL = 10;  
  currentState: State;
  inputSymbol, lhs: TSymbol;
  lastntstate: ParseInterface.State = LAST[ParseInterface.NTState];
  
  inputValue: ParseDefs.Value;
  inputLoc: CARDINAL;
  stackSize: CARDINAL;
  queueSize: CARDINAL;
  
  q: LONG DESCRIPTOR FOR ARRAY OF ActionEntry;  --reduction rules
  qI: CARDINAL;
  
  v: LONG DESCRIPTOR FOR ARRAY OF ParseDefs.Value; --parse stack
  v2: LONG DESCRIPTOR FOR ARRAY OF ParseDefs.Value2; --parse stack
  l: LONG DESCRIPTOR FOR ARRAY OF CARDINAL; -- source position
  s: LONG DESCRIPTOR FOR ARRAY OF State;
  top: CARDINAL;
  
  -- transition tables for terminal input symbols
  
  tStart: LONG DESCRIPTOR FOR ARRAY OF TIndex;
  tLength: LONG DESCRIPTOR FOR ARRAY OF CARDINAL;
  tSymbol: LONG DESCRIPTOR FOR ARRAY OF TSymbol;
  tAction: LONG DESCRIPTOR FOR ARRAY OF ActionEntry;
  
  -- transition tables for nonterminal input symbols
  
  nStart: LONG DESCRIPTOR FOR ARRAY OF NTIndex;
  nLength: LONG DESCRIPTOR FOR ARRAY OF CARDINAL;
  nSymbol: LONG DESCRIPTOR FOR ARRAY OF NTSymbol;
  nAction: LONG DESCRIPTOR FOR ARRAY OF ActionEntry;
  ntDefaults: LONG DESCRIPTOR FOR ARRAY OF ActionEntry;
  
  -- production information
  
  proddata: LONG DESCRIPTOR FOR ARRAY OF ParseInterface.ProductionInfo;
  
-- initialization/termination

  table: ParseInterface.TableRef;
  
  ParseInit: PROCEDURE [stream: MStream.Handle] =
    BEGIN
    table ← Runtime.GetTableBase[Runtime.GlobalFrame[ParseTables]];
    ParseDefs.ScanInit[stream, table];
    stackSize ← queueSize ← 0;
    s ← NIL;  q ← NIL;
    tStart ← DESCRIPTOR[table.parseTable.tStart];
    tLength ← DESCRIPTOR[table.parseTable.tLength];
    tSymbol ← DESCRIPTOR[table.parseTable.tSymbol];
    tAction ← DESCRIPTOR[table.parseTable.tAction];
    nStart ← DESCRIPTOR[table.parseTable.nStart];
    nLength ← DESCRIPTOR[table.parseTable.nLength];
    nSymbol ← DESCRIPTOR[table.parseTable.nSymbol];
    nAction ← DESCRIPTOR[table.parseTable.nAction];
    ntDefaults ← DESCRIPTOR[table.parseTable.ntDefaults];
    proddata ← DESCRIPTOR[table.parseTable.prodData];
    ExpandQueue[256];
    ExpandStack[128];  
    END;
    
--  the main parsing procedures

  Parse: PUBLIC PROCEDURE [stream: MStream.Handle] =
    BEGIN
    i, valid, k, m: CARDINAL;		-- stack pointers
    j, j0: CARDINAL;
    nErrors: CARDINAL;
    tj: ActionEntry;
    
    ParseInit[stream];
    i ← top ← valid ← 0;  qI ← 0;  nErrors ← 0;
    s[0] ← currentState ← InitialState;
    [inputSymbol, inputValue, inputLoc] ← ParseDefs.Atom[].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 => GOTO 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;
	      ParseDefs.ProcessQueue[qI, top];
	      qI ← 0;
	      END;
	  top ← valid ← i ← i+1;
	  v[i] ← inputValue;
	  [inputSymbol, inputValue, inputLoc]  ← ParseDefs.Atom[].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 =>
	{
		PrintingDefs.OutCode["Syntax Error at "L, 0];
		Format.Decimal[PrintingDefs.outProc↑, inputLoc];
		PrintingDefs.OutCode[", error context '"L, 0];
		ParseDefs.ErrorContext[];
		PrintingDefs.OutCode["'\n"L, 0];
		IF top > 0 THEN
			i ← valid ← top ← top-1;
		qI ← 0;
		currentState ← s[i];
		nErrors ← nErrors + 1;
		IF nErrors > errorLimit THEN {
		    PrintingDefs.OutCode["Abandoning parse.\n"L, 0];
		    EXIT; };
		-- on error scan to next '; or
		-- to the end of file
		DO
			IF inputSymbol = tSEMICOLON OR
			   inputSymbol = ParseInterface.EndMarker
		        THEN EXIT;
			[inputSymbol, inputValue, inputLoc]
					← ParseDefs.Atom[].symbol;
		ENDLOOP;
	};
      END;
      ENDLOOP;
      
    ParseDefs.ProcessQueue[qI, top];

    EraseQueue[];
    EraseStack[];
    ParseDefs.ScanFinal[];
    END;
    
  ExpandStack: PROCEDURE [delta: CARDINAL] =
    BEGIN
    sS, sL, sV, sV2: CARDINAL;
    p: LONG POINTER;
    newS: LONG DESCRIPTOR FOR ARRAY OF State;
    newL: LONG DESCRIPTOR FOR ARRAY OF CARDINAL;
    newV: LONG DESCRIPTOR FOR ARRAY OF ParseDefs.Value;
    newV2: LONG DESCRIPTOR FOR ARRAY OF ParseDefs.Value2;
    newSize: CARDINAL = stackSize + delta;
    sS ← newSize*SIZE[State];
    sL ← newSize*SIZE[CARDINAL];
    sV ← newSize*SIZE[ParseDefs.Value];
    sV2 ← newSize*SIZE[ParseDefs.Value2];
    p ← Storage.Pages[Storage.PagesForWords[sS+sL+sV+sV2]];
    newS ← DESCRIPTOR[p, newSize];
    newL ← DESCRIPTOR[p+sS, newSize];
    newV ← DESCRIPTOR[p+sS+sL, newSize];
    newV2 ← DESCRIPTOR[p+sS+sL+sV, newSize];
    FOR i: CARDINAL IN [0..stackSize) DO
    	newS[i] ← s[i];
	newL[i] ← l[i];
	newV[i] ← v[i];
	newV2[i] ← v2[i];
    ENDLOOP;
    EraseStack[];
    s ← newS;
    l ← newL;
    v ← newV;
    v2 ← newV2;
    stackSize ← newSize;
    ParseDefs.AssignDescriptors[q,v,v2,l,proddata];
    END;
    
  EraseStack: PROCEDURE =
    {IF stackSize # 0 THEN {stackSize ← 0; Storage.FreePages[BASE[s]]}};
    
  ExpandQueue: PROCEDURE [delta: CARDINAL] =
    BEGIN
    newQ: LONG DESCRIPTOR FOR ARRAY OF ActionEntry;
    newSize: CARDINAL = queueSize + delta;
    newQ ← DESCRIPTOR[Storage.Pages[Storage.PagesForWords[
      newSize*SIZE[ActionEntry]]], newSize];
    IF queueSize # 0 THEN
      BEGIN
      FOR i: CARDINAL IN [0..queueSize) DO
	    newQ[i] ← q[i];
      ENDLOOP;
      EraseQueue[];
      END;
    q ← newQ;
    queueSize ← newSize;
    END;
    
  EraseQueue: PROCEDURE =
    {IF queueSize # 0 THEN {queueSize ← 0; Storage.FreePages[BASE[q]]}};
    
}.