-- file: PeepholeZ.mesa, edited by Sweet on November 29, 1979  11:23 PM

DIRECTORY
  Code: FROM "code" USING [dStar],
  CodeDefs: FROM "codedefs" USING [CCIndex, CCNull, CodeCCIndex, JumpCCIndex],
  ComData: FROM "comdata" USING [switches],
  FOpCodes: FROM "fopcodes" USING [
    qADD, qALLOC, qAMUL, qAND, qBCAST, qBCASTL, qBITBLT, qBLT, qBLTC, qBLTCL, 
    qBLTL, qBNDCK, qBRK, qCATCH, qDADD, qDBL, qDCOMP, qDDIV, qDESCB, qDESCBS, 
    qDIV, qDST, qDSUB, qDMOD, qDMUL, qDUP, qDUCOMP, qDUDIV, qDUMOD, qDWDC, 
    qEFC, qEXCH, qFADD, qFCOMP, qFDIV, qFLOAT, qFMUL, qFREE, qFSUB, qGADRB, 
    qINC, qIWDC, qKFCB, qLADRB, qLCO, qLDIV, qLFC, qLG, qLGD, qLI, qLINKB,
    qLL, qLLD, qLLK, qLP, qLST, qLSTF, qME, qMEL, qMRE, qMREL, qMUL, qMXD,
    qMXDL, 
    qMXW, qMXWL, qNEG, qNILCK, qNILCKL, qNOOP, qNOTIFY, qNOTIFYL, qOR, qPL, 
    qPOP, qPORTI, qPORTO, qPS, qPSD, qPSF, qPUSH, qR, qRD, qRDL, qREQUEUE, 
    qREQUEUEL, qRET, qRF, qRFC, qRFL, qRFS, qRFSL, qRIG, qRIGL, qRIL, qRILL, 
    qRL, qRR, qRSTR, qRSTRL, qRXGL, qRXL, qRXLL, qSFC, qSG, qSGD, qSHIFT, qSL, 
    qSLD, qSTARTIO, qSTOP, qSUB, qW, qWD, qWDL, qWF, qWFL, qWFS, qWFSL, qWIGL, 
    qWIL, qWILL, qWL, qWR, qWS, qWSD, qWSF, qWSTR, qWSTRL, qWXGL, qWXL, qWXLL, 
    qXOR],
  Mopcodes: FROM "mopcodes" USING [
    zADD, zADD01, zALLOC, zAND, zBCAST, zBITBLT, zBLT, zBLTC, zBLTCL, zBLTL, 
    zBNDCK, zBRK, zCATCH, zDADD, zDBL, zDCOMP, zDESCB, zDESCBS, zDIV, zDST, 
    zDSUB, zDUP, zDUCOMP, zDWDC, zEFCB, zEXCH, zFREE, zGADRB, zINC, zIWDC, 
    zKFCB, zLADRB, zLDIV, zLFCB, zLGB, zLGDB, zLI0, zLINKB, zLLB, zLLDB, 
    zLLKB, zLP, zLST, zLSTF, zME, zMRE, zMUL, zMXD, zMXW, zNEG, zNILCK, 
    zNILCKL, zNOTIFY, zOR, zPOP, zPORTI, zPORTO, zPUSH, zR0, zRB, zRBL, zRD0, 
    zRDB, zRDBL, zREQUEUE, zRET, zRF, zRFC, zRFL, zRFS, zRFSL, zRIGP, zRIGPL, 
    zRILP, zRILPL, zRR, zRSTR, zRSTRL, zRXGPL, zRXLP, zRXLPL, zSFC, zSGB, 
    zSGDB, zSHIFT, zSLB, zSLDB, zSTARTIO, zSTOP, zSUB, zW0, zWB, zWBL, zWD0, 
    zWDB, zWDBL, zWF, zWFL, zWFS, zWFSL, zWIGPL, zWILP, zWILPL, zWR, zWS0, 
    zWSB, zWSDB, zWSF, zWSTR, zWSTRL, zWXGPL, zWXLP, zWXLPL, zXOR],
  OpCodeParams: FROM "opcodeparams" USING [
    BYTE, DstarLocalProcSlots, ExternalProcBase, ExternalProcSlots, 
    GlobalBase, GlobalLoadSlots, GlobalStoreSlots, LocalBase, LocalLoadSlots, 
    LocalProcBase, LocalProcSlots, LocalPutSlots, LocalStoreSlots, ReadSlots, 
    RILSlots, WriteSlots, zEFCn, zLFCn, zLGn, zLLn, zPLn, zRILn, zRn, zSGn, 
    zSLn, zWn],
  OpTableDefs: FROM "optabledefs" USING [instlength],
  P5: FROM "p5" USING [NumberOfParams, P5Error, C0, C1, C2, LoadConstant],
  PeepholeDefs: FROM "peepholedefs" USING [
    InitParametersC, PackPair, PeepState],
  P5U: FROM "p5u" USING [DeleteCell],
  SDDefs: FROM "sddefs" USING [
    sFADD, sFCOMP, sFDIV, sFLOAT, sFMUL, sFSUB, sLongDiv, sLongMod, sLongMul, 
    sULongDiv, sULongMod],
  Table: FROM "table" USING [Base, Notifier],
  Tree: FROM "tree" USING [treeType];

PeepholeZ: PROGRAM
  IMPORTS CPtr: Code, MPtr: ComData, P5U, OpTableDefs, P5, PeepholeDefs
  EXPORTS CodeDefs, PeepholeDefs =
  BEGIN OPEN PeepholeDefs, OpCodeParams, CodeDefs;

  -- imported definitions

  BYTE: TYPE = OpCodeParams.BYTE;
  CodeCCIndex: TYPE = CodeDefs.CodeCCIndex;
  JumpCCIndex: TYPE = CodeDefs.JumpCCIndex;


  cb: Table.Base;		-- code base (local copy)

  PeepholeZNotify: PUBLIC Table.Notifier =
    BEGIN  -- called by allocator whenever table area is repacked
    cb ← base[Tree.treeType];
    RETURN
    END;

  dummy: PRIVATE PROCEDURE =
    BEGIN
    state: PeepState;
    IF FALSE THEN [] ← state;
    END;
  
  UnconvertedInstruction: SIGNAL [opcode: WORD] = CODE;

  PeepZ: PUBLIC PROCEDURE [start: CodeCCIndex] =
    BEGIN -- convert to real instructions (ie from qXXX to zXXX)
    OPEN Mopcodes, FOpCodes;
    next: CodeCCIndex;
    state: PeepState;

    next ← start;
    BEGIN OPEN state;
     UNTIL (c ← next) = CCNull DO
      next ← LOOPHOLE[cb[c].flink];
      WITH cb[LOOPHOLE[c,CCIndex]] SELECT FROM
	code =>
	 IF ~cb[c].realinst THEN
	  BEGIN
	  InitParametersC[@state];
	  SELECT cInst FROM
	    qLG =>
	      BEGIN MoveVar[global, load, single, cP[1]]; P5U.DeleteCell[c] END;
	    qSG =>
	      BEGIN MoveVar[global, store, single, cP[1]]; P5U.DeleteCell[c] END;
	    qLL =>
	      BEGIN MoveVar[local, load, single, cP[1]]; P5U.DeleteCell[c] END;
	    qSL =>
	      BEGIN MoveVar[local, store, single, cP[1]]; P5U.DeleteCell[c] END;
	    qPL =>
	      BEGIN MoveVar[local, put, single, cP[1]]; P5U.DeleteCell[c] END;
	    qLI, qLCO => BEGIN P5.LoadConstant[cP[1]]; P5U.DeleteCell[c] END;
	    qLGD =>
	      BEGIN MoveVar[global, load, double, cP[1]]; P5U.DeleteCell[c] END;
	    qSGD =>
	      BEGIN MoveVar[global, store, double, cP[1]]; P5U.DeleteCell[c] END;
	    qLLD =>
	      BEGIN MoveVar[local, load, double, cP[1]]; P5U.DeleteCell[c] END;
	    qSLD =>
	      BEGIN MoveVar[local, store, double, cP[1]]; P5U.DeleteCell[c] END;
	    qR => BEGIN Move[read, single, cP[1], 0]; P5U.DeleteCell[c] END;
	    qW => BEGIN Move[write, single, cP[1], 0]; P5U.DeleteCell[c] END;
	    qRL => BEGIN Move[readlong, single, cP[1], 0]; P5U.DeleteCell[c] END;
	    qWL => BEGIN Move[writelong, single, cP[1], 0]; P5U.DeleteCell[c] END;
	    qRF => BEGIN Move[read, partial, cP[1], cP[2]]; P5U.DeleteCell[c] END;
	    qWF => BEGIN Move[write, partial, cP[1], cP[2]]; P5U.DeleteCell[c] END;
	    qRFL => BEGIN Move[readlong, partial, cP[1], cP[2]]; P5U.DeleteCell[c] END;
	    qWFL => BEGIN Move[writelong, partial, cP[1], cP[2]]; P5U.DeleteCell[c] END;
	    qRFC => MakeReal[ zRFC, c];
	    qRFS => MakeReal[ zRFS, c];
	    qWFS => MakeReal[ zWFS, c];
	    qRFSL => MakeReal[ zRFSL, c];
	    qWFSL => MakeReal[ zWFSL, c];
	    qRD => BEGIN Move[read, double, cP[1], 0]; P5U.DeleteCell[c] END;
	    qWD => BEGIN Move[write, double, cP[1], 0]; P5U.DeleteCell[c] END;
	    qRSTR => MakeReal[ zRSTR, c];
	    qWSTR => MakeReal[ zWSTR, c];
	    qRXL => MakeLPReal[zRXLP, c];
	    qWXL => MakeLPReal[zWXLP, c];
	    qRIG => MakeGPReal[zRIGP, c];
	    qRIL => IF cP[1] = LocalBase AND cP[2] IN RILSlots
	      THEN BEGIN P5.C0[zRILn+cP[2]]; P5U.DeleteCell[c] END
	      ELSE MakeLPReal[zRILP, c];
	    qWIL => MakeLPReal[zWILP, c];
	    qRDL => BEGIN Move[readlong, double, cP[1], 0]; P5U.DeleteCell[c] END;
	    qWDL => BEGIN Move[writelong, double, cP[1], 0]; P5U.DeleteCell[c] END;
	    qRSTRL => MakeReal[ zRSTRL, c];
	    qWSTRL => MakeReal[ zWSTRL, c];
	    qRXGL => MakeGPReal[zRXGPL, c];
	    qWXGL => MakeGPReal[zWXGPL, c];
	    qRXLL => MakeLPReal[zRXLPL, c];
	    qWXLL => MakeLPReal[zWXLPL, c];
	    qRIGL => MakeGPReal[zRIGPL, c];
	    qWIGL => MakeGPReal[zWIGPL, c];
	    qRILL => MakeLPReal[zRILPL, c];
	    qWILL => MakeLPReal[zWILPL, c];
	    qWS => BEGIN Move[swrite, single, cP[1], 0]; P5U.DeleteCell[c] END;
	    qWSF => BEGIN Move[swrite, partial, cP[1], cP[2]]; P5U.DeleteCell[c] END;
	    qWSD => BEGIN Move[swrite, double, cP[1], 0]; P5U.DeleteCell[c] END;
	    qPS => BEGIN Move[sput, single, cP[1], 0]; P5U.DeleteCell[c] END;
	    qPSF => BEGIN Move[sput, partial, cP[1], cP[2]]; P5U.DeleteCell[c] END;
	    qPSD => BEGIN Move[sput, double, cP[1], 0]; P5U.DeleteCell[c] END;
	    qADD => MakeRealFast[c:c, slow:zADD, fast:zADD01];
	    qSUB => MakeReal[ zSUB, c];
	    qDADD => MakeReal[ zDADD, c];
	    qDSUB => MakeReal[ zDSUB, c];
	    qDCOMP => MakeReal[ zDCOMP, c];
	    qDUCOMP => MakeReal[ zDUCOMP, c];
	    qMUL, qAMUL => MakeReal[ zMUL, c];
	    qDIV => MakeReal[ zDIV, c];
	    qLDIV => MakeReal[ zLDIV, c];
	    qNEG => MakeReal[ zNEG, c];
	    qAND => MakeReal[ zAND, c];
	    qOR => MakeReal[ zOR, c];
	    qXOR => MakeReal[ zXOR, c];
	    qSHIFT => MakeReal[ zSHIFT, c];
	    qPUSH => MakeReal[ zPUSH, c];
	    qPOP => MakeReal[ zPOP, c];
	    qEXCH => MakeReal[ zEXCH, c];
	    qCATCH => MakeReal[ zCATCH, c];
	    qEFC =>
		IF cP[1] IN ExternalProcSlots THEN
		  BEGIN 
		  P5.C0[zEFCn+cP[1]-ExternalProcBase]; 
		  P5U.DeleteCell[c] 
		  END
		ELSE MakeReal[ zEFCB, c];
	    qLLK => MakeReal[ zLLKB, c];
	    qLFC =>
		IF ~CPtr.dStar AND cP[1] IN LocalProcSlots OR
		 CPtr.dStar AND cP[1] IN DstarLocalProcSlots THEN
		  BEGIN
		  P5.C0[zLFCn+cP[1]-LocalProcBase];
		  P5U.DeleteCell[c]
		  END
		ELSE MakeReal[ zLFCB, c];
	    qSFC => MakeReal[ zSFC, c];
	    qRET => MakeReal[ zRET, c];
	    qPORTO => MakeReal[ zPORTO, c];
	    qPORTI => MakeReal[ zPORTI, c];
	    qKFCB => MakeReal[ zKFCB, c];
	    qBLT => MakeReal[ zBLT, c];
	    qBLTL => MakeReal[ zBLTL, c];
	    qBLTC => MakeReal[ zBLTC, c];
	    qBLTCL => MakeReal[ zBLTCL, c];
	    qALLOC => MakeReal[ zALLOC, c];
	    qFREE => MakeReal[ zFREE, c];
	    qSTOP => MakeReal[ zSTOP, c];
	    qBITBLT => MakeReal[ zBITBLT, c];
	    qSTARTIO => MakeReal[ zSTARTIO, c];
	    qDST => MakeReal[ zDST, c];
	    qLST => MakeReal[ zLST, c];
	    qLSTF => MakeReal[ zLSTF, c];
	    qWR => MakeReal[ zWR, c];
	    qRR => MakeReal[ zRR, c];
	    qBRK => MakeReal[ zBRK, c];
	    qLINKB => MakeReal[ zLINKB, c];
	    qLADRB => MakeReal[ zLADRB, c];
	    qGADRB => MakeReal[ zGADRB, c];
	    qINC => MakeReal[ zINC, c];
	    qDUP => MakeReal[ zDUP, c];
	    qDBL => MakeReal[ zDBL, c];
	    qDWDC => MakeReal[ zDWDC, c];
	    qIWDC => MakeReal[ zIWDC, c];
	    qDESCB => MakeReal[ zDESCB, c];
	    qDESCBS => MakeReal[ zDESCBS, c];
            qFADD =>
                BEGIN
                P5.C1[zKFCB, SDDefs.sFADD];
                P5U.DeleteCell[c];
                END;
            qFSUB =>
                BEGIN
                P5.C1[zKFCB, SDDefs.sFSUB];
                P5U.DeleteCell[c];
                END;
            qFMUL =>
                BEGIN
                P5.C1[zKFCB, SDDefs.sFMUL];
                P5U.DeleteCell[c];
                END;
            qFDIV =>
                BEGIN
                P5.C1[zKFCB, SDDefs.sFDIV];
                P5U.DeleteCell[c];
                END;
            qFLOAT =>
                BEGIN
                P5.C1[zKFCB, SDDefs.sFLOAT];
                P5U.DeleteCell[c];
                END;
            qFCOMP =>
                BEGIN
                P5.C1[zKFCB, SDDefs.sFCOMP];
                P5U.DeleteCell[c];
                END;
            qDMUL =>
	      BEGIN
	      P5.C1[zKFCB, SDDefs.sLongMul];
	      P5U.DeleteCell[c];
	      END;
            qDDIV =>
	      BEGIN
	      P5.C1[zKFCB, SDDefs.sLongDiv];
	      P5U.DeleteCell[c];
	      END;
            qDUDIV =>
	      BEGIN
	      P5.C1[zKFCB, SDDefs.sULongDiv];
	      P5U.DeleteCell[c];
	      END;
            qDMOD =>
	      BEGIN
	      P5.C1[zKFCB, SDDefs.sLongMod];
	      P5U.DeleteCell[c];
	      END;
            qDUMOD =>
	      BEGIN
	      P5.C1[zKFCB, SDDefs.sULongMod];
	      P5U.DeleteCell[c];
	      END;
	    qLP => MakeReal[
	      IF (CPtr.dStar OR MPtr.switches['l]) THEN zLP ELSE zLI0, c];
	    qNILCK => MakeReal[ zNILCK, c];
	    qNILCKL => IF (CPtr.dStar OR MPtr.switches['l]) THEN
	        MakeReal[ zNILCKL, c]
	      ELSE
		BEGIN
		P5.C0[zEXCH];
		P5.C0[zNILCK];
		P5.C0[zEXCH];
		P5U.DeleteCell[c];
		END;
	    qBNDCK => MakeReal[ zBNDCK, c];
	    qME, qMEL => MakeReal[ zME, c];
	    qMRE, qMREL => MakeReal[ zMRE, c];
	    qMXW, qMXWL => MakeReal[ zMXW, c];
	    qMXD, qMXDL => MakeReal[ zMXD, c];
	    qNOTIFY, qNOTIFYL => MakeReal[ zNOTIFY, c];
	    qBCAST, qBCASTL => MakeReal[ zBCAST, c];
	    qREQUEUE, qREQUEUEL => MakeReal[ zREQUEUE, c];
	    qNOOP => NULL; -- pass on unconverted to OutBinary
	    ENDCASE =>
	      BEGIN SIGNAL UnconvertedInstruction[cInst]; P5U.DeleteCell[c] END;
	  END;
	ENDCASE; -- of WITH
      ENDLOOP;
    END; -- of OPEN state
    RETURN
    END;

  MakeReal: PROCEDURE [i: BYTE, c: CodeCCIndex] =
    BEGIN
    IF cb[c].realinst OR P5.NumberOfParams[cb[c].inst] # OpTableDefs.instlength[i]-1 THEN P5.P5Error[1025];
    cb[c].inst ← i;
    cb[c].realinst ← TRUE;
    RETURN
    END;

  MakeRealFast: PROCEDURE [slow, fast: BYTE, c: CodeCCIndex] =
    BEGIN
    IF cb[c].realinst OR P5.NumberOfParams[cb[c].inst] # OpTableDefs.instlength[slow]-1 THEN P5.P5Error[1026];
    cb[c].inst ← IF cb[c].minimalStack THEN fast ELSE slow;
    cb[c].realinst ← TRUE;
    RETURN
    END;

  MakeLPReal: PROCEDURE [i: BYTE, c: CodeCCIndex] =
    BEGIN
    IF cb[c].realinst OR P5.NumberOfParams[cb[c].inst] # OpTableDefs.instlength[i]-1+1 THEN P5.P5Error[1027];
    P5.C1[i, PackPair[cb[c].parameters[1]-LocalBase, cb[c].parameters[2]]];
    P5U.DeleteCell[c];
    RETURN
    END;

  MakeGPReal: PROCEDURE [i: BYTE, c: CodeCCIndex] =
    BEGIN
    IF cb[c].realinst OR P5.NumberOfParams[cb[c].inst] # OpTableDefs.instlength[i]-1+1 THEN P5.P5Error[1028];
    P5.C1[i, PackPair[cb[c].parameters[1]-GlobalBase, cb[c].parameters[2]]];
    P5U.DeleteCell[c];
    RETURN
    END;


  cpeep9: PROCEDURE =
    BEGIN -- find 2-instruction sequences
    RETURN
    END;

  cpeep10: PROCEDURE =
    BEGIN -- find bit-testing jumps
    RETURN
    END;

  Mdirection: TYPE = {read, write, swrite, sput, readlong, writelong};
  Mtype: TYPE = {single, double, partial};
  MVdirection: TYPE = {load, store, put};
  MVtype: TYPE = {single, double};
  MVclass: TYPE = {global, local};

  MoveB: ARRAY MVclass OF ARRAY MVtype OF
    PACKED ARRAY MVdirection[load..store] OF BYTE ← [
      [[Mopcodes.zLGB, Mopcodes.zSGB], [Mopcodes.zLGDB, Mopcodes.zSGDB]],
      [[Mopcodes.zLLB, Mopcodes.zSLB], [Mopcodes.zLLDB, Mopcodes.zSLDB]]];

  MoveVar: PROCEDURE [c: MVclass, d: MVdirection, t: MVtype, offset: WORD] =
    BEGIN -- handles LG, SG, LL, SL, LGD, SGD, LLD, SLD, PL class instructions
    OPEN Mopcodes;
    IF t = single THEN
      IF c = local THEN
	SELECT d FROM
	  load => IF offset IN LocalLoadSlots THEN
	    BEGIN P5.C0[zLLn+offset-LocalBase]; RETURN END;
	  store => IF offset IN LocalStoreSlots THEN
	    BEGIN P5.C0[zSLn+offset-LocalBase]; RETURN END;
	  put => IF offset IN LocalPutSlots THEN
	    BEGIN P5.C0[zPLn+offset-LocalBase]; RETURN END;
	  ENDCASE
      ELSE
	SELECT d FROM
	  load => IF offset IN GlobalLoadSlots THEN
	    BEGIN P5.C0[zLGn+offset-GlobalBase]; RETURN END;
	  store => IF offset IN GlobalStoreSlots THEN
	    BEGIN P5.C0[zSGn+offset-GlobalBase]; RETURN END;
	  ENDCASE;
    IF offset ~IN BYTE THEN
      BEGIN
      P5.C1[IF c = global THEN zGADRB ELSE zLADRB, LAST[BYTE]];
      P5.LoadConstant[offset - LAST[BYTE]]; P5.C0[zADD];
      IF t = single THEN IF d = load THEN P5.C0[zR0] ELSE P5.C0[zW0]
      ELSE IF d = load THEN P5.C0[zRD0] ELSE P5.C0[zWD0];
      RETURN
      END;
    P5.C1[MoveB[c][t][d], offset];
    RETURN
    END;


  Move: PROCEDURE [d: Mdirection, t: Mtype, offset, field: WORD] =
    BEGIN -- handles R, W, RF, WF, WS, WSF, PS, PSF class instructions
    OPEN Mopcodes;

    IF d = read AND t = single AND offset IN ReadSlots THEN
      BEGIN P5.C0[zRn+offset]; RETURN END;
    IF d = write AND t = single AND offset IN WriteSlots THEN
      BEGIN P5.C0[zWn+offset]; RETURN END;
    IF offset ~IN BYTE THEN
      BEGIN
      P5.LoadConstant[offset];
      IF d >= readlong THEN
	BEGIN
	P5.LoadConstant[IF LOOPHOLE[offset, INTEGER]>0 THEN 0 ELSE 177777B];
	P5.C0[zDADD]
	END
      ELSE P5.C0[zADD];
      offset ← 0;
      END;
    IF offset = 0 AND d < readlong THEN
      SELECT d FROM
	read => SELECT t FROM
	  single => P5.C0[zR0];
	  double => P5.C0[zRD0];
	  partial => P5.C2[zRF, 0, field];
	  ENDCASE;
	write => SELECT t FROM
	  single => P5.C0[zW0];
	  double => P5.C0[zWD0];
	  partial => P5.C2[zWF, 0, field];
	  ENDCASE;
	swrite, sput => SELECT t FROM
	  single => P5.C0[zWS0];
	  double => P5.C1[zWSDB, 0];
	  partial => P5.C2[zWSF, 0, field];
	  ENDCASE;
	ENDCASE
    ELSE
      SELECT d FROM
	read => SELECT t FROM
	  single => P5.C1[zRB, offset];
	  double => P5.C1[zRDB, offset];
	  partial => P5.C2[zRF, offset, field];
	  ENDCASE;
	write => SELECT t FROM
	  single => P5.C1[zWB, offset];
	  double => P5.C1[zWDB, offset];
	  partial => P5.C2[zWF, offset, field];
	  ENDCASE;
	swrite, sput => SELECT t FROM
	  single => P5.C1[zWSB, offset];
	  double => P5.C1[zWSDB, offset];
	  partial => P5.C2[zWSF, offset, field];
	  ENDCASE;
	readlong => SELECT t FROM
	  single => P5.C1[zRBL, offset];
	  double => P5.C1[zRDBL, offset];
	  partial => P5.C2[zRFL, offset, field];
	  ENDCASE;
	writelong => SELECT t FROM
	  single => P5.C1[zWBL, offset];
	  double => P5.C1[zWDBL, offset];
	  partial => P5.C2[zWFL, offset, field];
	  ENDCASE;
	ENDCASE;
    IF d = sput THEN P5.C0[zPUSH];
    RETURN
    END;



  END...