/***********************************************************************
*
* asmpass0 - Pass 0 for the IBM 7090 assembler.
*
* Changes:
*   12/12/04   DGP   Original.
*   02/02/05   DGP   Correct Macro/IRP expansions.
*   02/03/05   DGP   Added JOBSYM.
*   02/09/05   DGP   Added FAP mode.
*   03/01/05   DGP   Change CALL parm parsing.
*   03/10/05   DGP   Added 7090 macros for 7094 instructions.
*   03/11/05   DGP   Fix null argument in macro expansion.
*                    And chained IF[FT] statements.
*   03/15/05   DGP   Correct macros for 7090 mode and add macro generated
*                    labels.
*   03/17/05   DGP   Fixed CALL error return generation.
*	
***********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "asmdef.h"
#include "asmdmem.h"

extern int pc;			/* the assembler pc */
extern int symbolcount;		/* Number of symbols in symbol table */
extern int absolute;		/* In absolute section */
extern int radix;		/* Number scanner radix */
extern int linenum;		/* Source line number */
extern int exprtype;		/* Expression type */
extern int pgmlength;		/* Length of program */
extern int absmod;		/* In absolute module */
extern int monsym;		/* Include IBSYS Symbols (MONSYM) */
extern int jobsym;		/* Include IBJOB Symbols (JOBSYM) */
extern int termparn;		/* Parenthesis are terminals (NO()) */
extern int genxref;		/* Generate cross reference listing */
extern int addext;		/* Add extern for undef'd symbols (!absolute) */
extern int addrel;		/* ADDREL mode */
extern int qualindex;		/* QUALifier table index */
extern int fapmode;		/* FAP assembly mode */
extern int headcount;		/* Number of entries in headtable */
extern int cpumodel;		/* CPU model */

extern char inbuf[MAXLINE];	/* The input buffer for the scanners */
extern char deckname[MAXSYMLEN+2];/* The assembly deckname */
extern char lbl[MAXLBLLEN+2];	/* The object label */
extern char titlebuf[TTLSIZE+2];/* The assembly TTL buffer */
extern char qualtable[MAXQUALS][MAXSYMLEN+2];/* The QUALifier table */
extern char headtable[MAXHEADS];/* HEAD table */

extern SymNode *symbols[MAXSYMBOLS];/* The Symbol table */
extern char *pscanbuf;		/* Pointer for tokenizers */

static long curpos;		/* Current file position */
static int asmskip;		/* In skip line mode IFF/IFT */
static int gotoskip;		/* In GOTO mode */
static int lblgennum;		/* LBL generated number */
static int macrocount;		/* Number of macros defined */
static int ifcont;		/* IFF/IFT continued */
static int ifrel;		/* IFF/IFT continue relation OR/AND */
static int ifskip;		/* IFF/IFT prior skip result */
static int eofflg = FALSE;	/* EOF on input file */
static int macsloaded;          /* 7094 macros loaded flag */

static char cursym[MAXSYMLEN+2];/* Current label field symbol */
static char gotosym[MAXSYMLEN+2];/* GOTO target symbol */
static char srcbuf[MAXSRCLINE];	/* Source line buffer */
static char etcbuf[MAXSRCLINE];	/* ETC (continuation) buffer */
static char errtmp[256];	/* Error print string */

static MacLines *freemaclines = NULL;/* resusable Macro lines */
static MacDef macdef[MAXMACROS];/* Macro template table */

/*
** 7090 macros for 7094 instructions.
*/

static char *PPC[] =
{
   "(PC    MACRO   O,Y,T ",
   "       PX'O    Y,T ",
   "       P'O'C   Y,T ",
   "       PX'O    Y,T ",
   "       P'O'C   Y,T ",
   "       ENDM "
};

static char *PCA[] =
{
   "PCA    MACRO   Y,T ",
   "       (PC     A,Y,T ",
   "       ENDM "
};

static char *PCD[] =
{
   "PCD    MACRO   Y,T ",
   "       (PC     D,Y,T ",
   "       ENDM "
};

static char *PSC[] =
{
   "(SC    MACRO   O,Y,T ",
   "       SXA     *+1,T ",
   "       AXC     **,T ",
   "       SX'O'   Y,T ",
   "       LXA     *-2,T ",
   "       ENDM "
};

static char *SCA[] =
{
   "SCA    MACRO   Y,T ",
   "       (SC     A,Y,T ",
   "       ENDM "
};

static char *SCD[] =
{
   "SCD    MACRO   Y,T ",
   "       (SC     D,Y,T ",
   "       ENDM "
};

static char *PDAS[] =
{
   "(DAS   MACRO   OP,I,Y,T ",
   "       (IFFF   I,Y    ",
   "       (DFAS   Y,T,OP ",
   "       (IFTF   I,Y,T ",
   "       (XFAS   T,OP ",
   "       (IFTT   I,Y,T ",
   "       (YFAS   OP   ",
   "       IFT     /I/=/*/ ",
   "       (ZFAS   OP,Y,T,  ",
   "       ENDM "
};

static char *DFAD[] =
{
   "DFAD   MACRO*  I,Y,T ",
   "       (DAS    AD,I,Y,T ",
   "       ENDM "
};

static char *DFSB[] =
{
   "DFSB   MACRO*  I,Y,T ",
   "       (DAS    SB,I,Y,T ",
   "       ENDM "
};

static char *DFAM[] =
{
   "DFAM   MACRO*  I,Y,T ",
   "       (DAS    AM,I,Y,T ",
   "       ENDM "
};

static char *DFSM[] =
{
   "DFSM   MACRO*  I,Y,T ",
   "       (DAS    SM,I,Y,T ",
   "       ENDM "
};

static char *PDFAS[] =
{
   "(DFAS  MACRO   Y,T,OP ",
   "       STQ     E.1 ",
   "       F'OP    Y,T ",
   "       STO     E.2 ",
   "       XCA         ",
   "       FAD     E.1 ",
   "       F'OP    Y+1,T ",
   "       FAD     E.2 ",
   "       ENDM "
};

static char *PXFAS[] =
{
   "(XFAS  MACRO   T,OP ",
   "       NOP     ,T         ",
   "       STQ     E.1        ",
   "       F'OP'*  *-2        ",
   "       STO     E.2        ",
   "       TXI     *+1,T,-1   ",
   "       XCA                ",
   "       FAD     E.1        ",
   "       F'OP'*  *-7        ",
   "       FAD     E.2        ",
   "       TXI     *+1,T,1    ",
   "       ENDM "
};

static char *PYFAS[] =
{
   "(YFAS  MACRO   OP,S ",
   "       (SAV4   S       ",
   "       (DFAS   0,4,OP  ",
   "S      AXT     ,4      ",
   "       ENDM "
};

static char *PZFAS[] =
{
   "(ZFAS  MACRO   OP,Y,T,S ",
   "       (FIND   Y,T,S     ",
   "       CLA     E.1       ",
   "       (DFAS   0,4,OP    ",
   "S      AXT     ,4        ",
   "       ENDM "
};

static char *PIFFF[] =
{
   "(IFFF  MACRO   I,Y ",
   "       IFF     /Y/=/**/,AND ",
   "       IFF     /I/=/*/      ",
   "       ENDM "
};

static char *PIFTF[] =
{
   "(IFTF  MACRO   I,Y,T ",
   "       IFF     /T/=//,AND    ",
   "       IFF     /T/=/0/,AND   ",
   "       IFT     /Y/=/**/,AND  ",
   "       IFF     /I/=/*/       ",
   "       ENDM "
};

static char *PIFTT[] =
{
   "(IFTT  MACRO   I,Y,T ",
   "       IFT     /T/=//,OR    ",
   "       IFT     /T/=/0/,AND  ",
   "       IFT     /Y/=/**/,AND ",
   "       IFF     /I/=/*/      ",
   "       ENDM "
};

static char *PSAV4[] =
{
   "(SAV4  MACRO   S ",
   "       AXT     ,0     ",
   "       SXA     S,4    ",
   "       LAC     *-2,4  ",
   "       ENDM "
};

static char *PFIND[] =
{
   "(FIND  MACRO   Y,T,S ",
   "       NOP     Y,T    ",
   "       STO     E.1    ",
   "       CLA*    *-2    ",
   "       STA     *+2    ",
   "       STT     *+1    ",
   "       PXA     ,0     ",
   "       SUB     *-1    ",
   "       SXA     S,4    ",
   "       PAC     0,4    ",
   "       ENDM "
};

static char *PDL[] =
{
   "(DL    MACRO   OP1,OP2,I,Y,T ",
   "       (IFFF   I,Y           ",
   "       (DLST   OP1,OP2,Y,T   ",
   "       (IFTT   I,Y,T         ",
   "       (XLST   OP1,OP2       ",
   "       (IFTF   I,Y,T         ",
   "       (YLST   OP1,OP2,T     ",
   "       IFT     /I/=/*/       ",
   "       (ZLST   OP1,OP2,Y,T,  ",
   "       ENDM "
};

static char *DLD[] =
{
   "DLD    MACRO*  I,Y,T ",
   "       (DL     CLA,LDQ,I,Y,T ",
   "       ENDM "
};

static char *DST[] =
{
   "DST    MACRO*  I,Y,T ",
   "       (DL     STO,STQ,I,Y,T ",
   "       ENDM "
};

static char *PDLST[] =
{
   "(DLST  MACRO   OP1,OP2,Y,T ",
   "       OP1     Y,T         ",
   "       OP2     Y+1,T       ",
   "       ENDM "
};

static char *PXLST[] =
{
   "(XLST  MACRO   OP1,OP2 ",
   "       OP1     **      ",
   "       SXA     *+3,4   ",
   "       LAC     *-2,4   ",
   "       OP2     1,4     ",
   "       AXT     **,4    ",
   "       ENDM "
};

static char *PYLST[] =
{
   "(YLST  MACRO   OP1,OP2,T ",
   "       OP1     **,T      ",
   "       TXI     *+1,T,-1  ",
   "       OP2*    *-2       ",
   "       TXI     *+1,T,1   ",
   "       ENDM "
};

static char *PZLST[] =
{
   "(ZLST  MACRO   OP1,OP2,Y,T,S ",
   "       (FIND   Y,T,S         ",
   "       IFT     /OP1/=/STO/   ",
   "       CLA     E.1           ",
   "       (DLST   OP1,OP2,0,4   ",
   "S      AXT     **,4          ",
   "       ENDM "
};

static char *DFMP[] =
{
   "DFMP   MACRO*  I,Y,T  ",
   "       (IFFF   I,Y     ",
   "       (DFMP   Y,T     ",
   "       (IFTF   I,Y,T   ",
   "       (XFMP   T       ",
   "       (IFTT   I,Y,T   ",
   "       (YFMP           ",
   "       IFT     /I/=/*/ ",
   "       (ZFMP   Y,T,    ",
   "       ENDM "
};

static char *PDFMP[] =
{
   "(DFMP  MACRO   Y,T ",
   "       STO     E.1   ",
   "       FMP     Y,T   ",
   "       STO     E.2   ",
   "       LDQ     Y,T   ",
   "       FMP     E.1   ",
   "       STQ     E.3   ",
   "       STO     E.4   ",
   "       LDQ     Y+1,T ",
   "       FMP     E.1   ",
   "       FAD     E.2   ",
   "       FAD     E.3   ",
   "       FAD     E.4   ",
   "       ENDM "
};

static char *PXFMP[] =
{
   "(XFMP  MACRO   T ",
   "       NOP     ,T       ",
   "       STO     E.1      ",
   "       FMP*    *-2      ",
   "       STO     E.2      ",
   "       LDQ*    *-4      ",
   "       FMP     E.1      ",
   "       STQ     E.3      ",
   "       STO     E.4      ",
   "       TXI     *+1,T,-1 ",
   "       LDQ*    *-9      ",
   "       TXI     *+1,T,1  ",
   "       FMP     E.1      ",
   "       FAD     E.2      ",
   "       FAD     E.3      ",
   "       FAD     E.4      ",
   "       ENDM "
};

static char *PYFMP[] =
{
   "(YFMP  MACRO   S ",
   "       (SAV4   S    ",
   "       (DFMP   0,4  ",
   "S      AXT     **,4 ",
   "       ENDM "
};

static char *PZFMP[] =
{
   "(ZFMP  MACRO   Y,T,S ",
   "       (FIND   Y,T,S ",
   "       CLA     E.1   ",
   "       (DFMP   0,4   ",
   "S      AXT     ,4    ",
   "       ENDM "
};

static char *PDD[] =
{
   "(DD    MACRO   OP,I,Y,T ",
   "       (IFFF   I,Y      ",
   "       (DFDX   OP,Y,T   ",
   "       (IFTF   I,Y,T    ",
   "       (XFDX   T,OP     ",
   "       (IFTT   I,Y,T    ",
   "       (YFDX   OP       ",
   "       IFT     /I/=/*/  ",
   "       (ZFDX   OP,Y,T,  ",
   "       ENDM "
};

static char *DFDP[] =
{
   "DFDP   MACRO*  I,Y,T ",
   "       (DD     P,I,Y,T ",
   "       ENDM "
};

static char *DFDH[] =
{
   "DFDH   MACRO*  I,Y,T ",
   "       (DD     H,I,Y,T ",
   "       ENDM "
};

static char *PDFDX[] =
{
   "(DFDX  MACRO   OP,Y,T ",
   "       STQ     E.1    ",
   "       FD'OP   Y,T    ",
   "       STO     E.2    ",
   "       STQ     E.3    ",
   "       FMP     Y+1,T  ",
   "       CHS            ",
   "       FAD     E.2    ",
   "       FAD     E.1    ",
   "       FD'OP   Y,T    ",
   "       XCA            ",
   "       FAD     E.3    ",
   "       ENDM "
};

static char *PXFDX[] =
{
   "(XFDX  MACRO   T,OP ",
   "       NOP     ,T       ",
   "       STQ     E.1      ",
   "       FD'OP'* *-2      ",
   "       STO     E.2      ",
   "       STQ     E.3      ",
   "       TXI     *+1,T,-1 ",
   "       FMP*    *-6      ",
   "       CHS              ",
   "       FAD     E.2      ",
   "       FAD     E.1      ",
   "       TXI     *+1,T,1  ",
   "       FD'OP'* *-11     ",
   "       XCA              ",
   "       FAD     E.3      ",
   "       ENDM "
};

static char *PYFDX[] =
{
   "(YFDX  MACRO   OP,S ",
   "       (SAV4   S      ",
   "       (DFDX   OP,0,4 ",
   "S      AXT     ,4     ",
   "       ENDM "
};

static char *PZFDX[] =
{
   "(ZFDX  MACRO   OP,Y,T,S ",
   "       (FIND   Y,T,S  ",
   "       CLA     E.1    ",
   "       (DFDX   OP,0,4 ",
   "S      AXT     **,4   ",
   "       ENDM "
};

static char *FSCA[] =
{
   "FSCA   MACRO   Y,T ",
   "       PXA     Y,T ",
   "       PAC     0,4 ",
   "       SXA     Y,4 ",
   "       ENDM "
};

static char **macros7094[] =
{
   PPC,   PCA,   PCD,   PSC,   SCA,   SCD,   PDAS,  DFAD,  DFSB,  DFAM,
   DFSM,  PDFAS, PXFAS, PYFAS, PZFAS, PIFFF, PIFTF, PIFTT, PSAV4, PFIND,
   PDL,   DLD,   DST,   PDLST, PXLST, PYLST, PZLST, DFMP,  PDFMP, PXFMP,
   PYFMP, PZFMP, PDD,   DFDP,  DFDH,  PDFDX, PXFDX, PYFDX, PZFDX, FSCA,
   NULL
};

/***********************************************************************
* maclookup - Lookup macro in table
***********************************************************************/

static MacDef *
maclookup (char *name)
{
   MacDef *mac = NULL;
   int i;

   for (i = 0; i < macrocount; i++)
   {
      mac = &macdef[i];
      if (!strcmp (mac->macname, name))
      {
	 return (mac);
      }
   }
   return (NULL);
}

/***********************************************************************
* p0mactoken - Process macro tokens
***********************************************************************/

static char *
p0mactokens (char *cp, int field, int index, MacDef *mac)
{
   char *token;
   char *ocp;
   int tokentype;
   int val;
   int j;
   char term;
   char targ[32];
   char largs[MAXSRCLINE];
   char lcltoken[TOKENLEN];

#ifdef DEBUGMACRO
   printf ("p0mactokens: field = %d, index = %d, cp = %s",
	    field, index, cp);
#endif

   /*
   ** Check for NULL operands 
   */

   if (field == 2)
   {
      ocp = cp;
      while (*cp && isspace (*cp))
      {
         cp++;
	 if (cp - ocp > (NOOPERAND))
	    return (cp);
      }
   }

   /*
   ** Substitute #NN for each macro parameter. The number, NN, corresponds to
   ** the paramter number.
   */

   term = '\0';
   largs[0] = '\0';
   do {

      targ[0] = '\0';
      cp = tokscan (cp, &token, &tokentype, &val, &term);
#ifdef DEBUGMACRO
      printf (
	    "   token1 = %s, tokentype = %d, val = %o, term = %c(%x)\n",
	    token, tokentype, val, term, term);
#endif
      /*
      ** If operator in input stream, copy it out
      */

      if (token[0] == '\0')
      {
	 if (tokentype == ASTER)
	    strcpy (targ, "*");
	 else
	    sprintf (targ, "%c", term);
      }

      /*
      ** If subsitution field, marked with apostophe, process.
      */

      else if (term == '\'')
      {
	 strcpy (lcltoken, token);
	 for (j = 0; j < mac->macargcount; j++)
	 {
	    if (!strcmp (token, mac->macargs[j]))
	    {
	       sprintf (lcltoken, "#%02d", j);
	       break;
	    }
	 }
	 strcat (largs, lcltoken);

	 cp++;
	 cp = tokscan (cp, &token, &tokentype, &val, &term);
#ifdef DEBUGMACRO
	 printf (
	    "   token2 = %s, tokentype = %d, val = %o, term = %c(%x)\n",
	    token, tokentype, val, term, term);
#endif
	 if (token[0])
	 {
	    for (j = 0; j < mac->macargcount; j++)
	    {
	       if (!strcmp (token, mac->macargs[j]))
	       {
		  sprintf (targ, "#%02d", j);
		  break;
	       }
	    }
	    if (j == mac->macargcount)
	       strcpy (targ, token);
	 }
	 if (term == '\'')
	    cp++;
         else if (!isspace (term))
	 {
	    strncat (targ, &term, 1);
	    if (!strchr (",+-/*", term)) cp++;
	 }
      }

      /*
      ** If token is a parameter, process
      */

      else
      {
	 for (j = 0; j < mac->macargcount; j++)
	 {
	    if (!strcmp (token, mac->macargs[j]))
	    {
	       sprintf (targ, "#%02d", j);
	       break;
	    }
	 }
	 if (j == mac->macargcount)
	    strcpy (targ, token);
	 if (!isspace(term))
	 {
	    strncat (targ, &term, 1);
	    if (term != ',') cp++;
	 }
      }
      strcat (largs, targ);
   } while (*cp && !isspace(term) && !isspace(*cp));

#ifdef DEBUGMACRO
   printf ("   largs = %s\n", largs);
#endif

   /*
   ** Place processed field into macro template
   */

   switch (field)
   {
   case 0:
      strcat (mac->maclines[index]->label, largs);
      break;
   case 1:
      strcat (mac->maclines[index]->opcode, largs);
      break;
   case 2:
      strcat (mac->maclines[index]->operand, largs);
      break;
   }
   return (cp);
}

/***********************************************************************
* p0macrostring - Process macro templates from a string array
***********************************************************************/

static void
p0macrostring (char **infd)
{
   MacDef *mac;
   char *token;
   char *cp;
   char *bp;
   int macindex;
   int tokentype;
   int val;
   int i;
   int done;
   int genmode;
   int oldtermparn;
   char term;
   char genline[MAXSRCLINE];

   oldtermparn = termparn;
#ifdef DEBUGPARN
   printf ("p0macrostring: termparn = %s\n", termparn ? "TRUE" : "FALSE");
#endif
   termparn = TRUE;

   mac = &macdef[macrocount];
   memset (mac, '\0', sizeof (MacDef));
   macindex = 1;

   strcpy (genline, infd[0]);
   bp = genline;
   pscanbuf = bp;
   cp = cursym;

   while (*bp && !isspace(*bp)) *cp++ = *bp++;
   *cp = '\0';
   strcpy (mac->macname, cursym);

   bp = tokscan (bp, &token, &tokentype, &val, &term);
   if (strcmp (token, "MACRO"))
   {
      termparn = oldtermparn;
      pscanbuf = inbuf;
      return;
   }

   if (term == INDIRECTSYM)
   {
      bp++;
      mac->macindirect = TRUE;
   }

   /*
   ** Scan off the parameters
   */

   i = 0;
   do {
      bp = tokscan (bp, &token, &tokentype, &val, &term);
      strcpy (mac->macargs[i], token);
      i++;
   } while (*bp && !isspace(term));
   mac->macargcount = i;

#ifdef DEBUGMACRO
   printf ("\nMACRO0: name = %s, indirect = %s\n",
      mac->macname, mac->macindirect ? "TRUE" : "FALSE");
   for (i = 0; i < mac->macargcount; i++)
      printf ("   arg%02d = %s\n", i, mac->macargs[i]);
#endif

   /*
   ** Read the source into the template until ENDM.
   */

   done = FALSE;
   i = 0;
   while (!done)
   {
      /*
      ** Write source line to intermediate file with MACDEF mode
      */

      genmode = MACDEF;
      if (infd[macindex])
	 strcpy (genline, infd[macindex++]);

      /*
      ** If END, we're done
      */

      if (!strncmp (&genline[OPCSTART], "ENDM", 4))
	 done = TRUE;

      /*
      ** If not a comment, process template line
      */

      if (!done && genline[0] != COMMENTSYM)
      {

	 /*
	 ** Allocate line template
	 */

	 if (freemaclines)
	 {
	    mac->maclines[i] = freemaclines;
	    freemaclines = mac->maclines[i]->next;
	 }
	 else if ((mac->maclines[i] =
			(MacLines *)DBG_MEMGET (sizeof(MacLines))) == NULL)
	 {
	    fprintf (stderr, "asm7090: Unable to allocate memory\n");
	    exit (ABORT);
	 }
	 memset (mac->maclines[i], '\0', sizeof(MacLines));

	 /*
	 ** If label field process label
	 */

	 cp = genline;
	 if (strncmp (cp, "      ", 6))
	 {
	    while (*cp && isspace (*cp)) cp++;
	    if (isalnum(*cp) || *cp == '.')
	    cp = p0mactokens (cp, 0, i, mac);
#ifdef DEBUGMACRO
	    printf ("   label = %s\n", mac->maclines[i]->label);
#endif
	 }

	 /*
	 ** Process opcode field
	 */

	 cp = p0mactokens (cp, 1, i, mac);
#ifdef DEBUGMACRO
	 printf ("   opcode = %s\n", mac->maclines[i]->opcode);
#endif

	 /*
	 ** Process operand field
	 */

	 cp = p0mactokens (cp, 2, i, mac);
#ifdef DEBUGMACRO
	 printf ("   operand = %s\n", mac->maclines[i]->operand);
#endif
	 i++;
      }
   }
   mac->maclinecount = i;
   macrocount++;

   termparn = oldtermparn;
   pscanbuf = inbuf;
}

/***********************************************************************
* p0macro - Process macro templates
***********************************************************************/

static void
p0macro (char *bp, int flag, FILE *infd, FILE *outfd)
{
   MacDef *mac;
   char *token;
   char *cp;
   int tokentype;
   int val;
   int i;
   int done;
   int genmode;
   int oldtermparn;
   char term;
   char genline[MAXSRCLINE];

   oldtermparn = termparn;
#ifdef DEBUGPARN
   printf ("p0macro: termparn = %s\n", termparn ? "TRUE" : "FALSE");
#endif
   termparn = TRUE;

   mac = &macdef[macrocount];
   memset (mac, '\0', sizeof (MacDef));

   strcpy (mac->macname, cursym);
   if (flag) mac->macindirect = TRUE;

   /*
   ** Scan off the parameters
   */

   i = 0;
   do {
      bp = tokscan (bp, &token, &tokentype, &val, &term);
      strcpy (mac->macargs[i], token);
      i++;
   } while (*bp && !isspace(term));
   mac->macargcount = i;

#ifdef DEBUGMACRO
   printf ("\nMACRO0: name = %s\n", mac->macname);
   for (i = 0; i < mac->macargcount; i++)
      printf ("   arg%02d = %s\n", i, mac->macargs[i]);
#endif

   /*
   ** Read the source into the template until ENDM.
   */

   done = FALSE;
   i = 0;
   while (!done)
   {
      /*
      ** Write source line to intermediate file with MACDEF mode
      */

      genmode = MACDEF;
      if (etcbuf[0])
      {
         strcpy (genline, etcbuf);
	 etcbuf[0] = '\0';
      }
      else
	 fgets (genline, MAXSRCLINE, infd);
      fwrite (&genmode, 1, 4, outfd);
      fputs (genline, outfd);
      linenum++;

      /*
      ** If END, we're done
      */

      if (fapmode)
      {
	 if (!strncmp (&genline[OPCSTART], "END", 3))
	    done = TRUE;
      }
      else
      {
	 if (!strncmp (&genline[OPCSTART], "ENDM", 4))
	    done = TRUE;
      }

      /*
      ** If not a comment, process template line
      */

      if (!done && genline[0] != COMMENTSYM)
      {

	 /*
	 ** Allocate line template
	 */

	 if (freemaclines)
	 {
	    mac->maclines[i] = freemaclines;
	    freemaclines = mac->maclines[i]->next;
	 }
	 else if ((mac->maclines[i] =
			(MacLines *)DBG_MEMGET (sizeof(MacLines))) == NULL)
	 {
	    fprintf (stderr, "asm7090: Unable to allocate memory\n");
	    exit (ABORT);
	 }
	 memset (mac->maclines[i], '\0', sizeof(MacLines));

	 /*
	 ** If label field process label
	 */

	 cp = genline;
	 pscanbuf = cp;
	 if (strncmp (cp, "      ", 6))
	 {
	    while (*cp && isspace (*cp)) cp++;
	    if (isalnum(*cp) || *cp == '.')
	    cp = p0mactokens (cp, 0, i, mac);
#ifdef DEBUGMACRO
	    printf ("   label = %s\n", mac->maclines[i]->label);
#endif
	 }

	 /*
	 ** Process opcode field
	 */

	 cp = p0mactokens (cp, 1, i, mac);
#ifdef DEBUGMACRO
	 printf ("   opcode = %s\n", mac->maclines[i]->opcode);
#endif

	 /*
	 ** Process operand field
	 */

	 cp = p0mactokens (cp, 2, i, mac);
#ifdef DEBUGMACRO
	 printf ("   operand = %s\n", mac->maclines[i]->operand);
#endif
	 i++;
      }
   }
   mac->maclinecount = i;
   macrocount++;

   termparn = oldtermparn;
   pscanbuf = inbuf;
}

/***********************************************************************
* p0pop - Process Pseudo operation codes.
***********************************************************************/

static int
p0pop (OpCode *op, int flag, char *bp, FILE *infd, FILE *outfd, int inmacro)
{
   SymNode *s;
   OpCode *addop;
   char *token;
   char *cp;
   int tokentype;
   int relocatable;
   int val;
   int i, j;
   int genmode;
   int savenmode;
   char term;
   char genline[MAXSRCLINE];

   savenmode = FALSE;
   switch (op->opvalue)
   {

   case ABS_T:			/* ABSoulute assembly (FAP mode) */
      if (fapmode)
      {
	 addext = FALSE;
         absolute = TRUE;
         absmod = TRUE;
      }
      break;

   case CALL_T:			/* Process CALL */
      {
	 int argcnt = 0;
	 int retcnt = 0;
	 int calline;
	 int oldtermparn;
	 char name[MAXSYMLEN+2];
	 char lclargs[MAXMACARGS][MAXFIELDSIZE];
	 char retargs[MAXMACARGS][MAXFIELDSIZE];

	 oldtermparn = termparn;
#ifdef DEBUGPARN
	 printf ("p0pop: CALL: termparn = %s\n", termparn ? "TRUE" : "FALSE");
#endif
	 termparn = TRUE;
	 calline = linenum;

	 /*
	 ** Get name of called routine
	 */

#ifdef DEBUGCALL
         printf ("p0CALL: line = %s", bp);
#endif

	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 strcpy (name, token);
#ifdef DEBUGCALL
	 printf ("   name = %s\n", token);
#endif

	 /*
	 ** If arguments specified, then scan them off 
	 */

	 if ((fapmode && term == ',') || term == '(')
	 {
	    bp++;
	    cp = bp;
	    while (*bp && *bp != ')' && !isspace (*bp)) bp++;
	    if (!fapmode && *bp != ')')
	    {
	       logerror ("Missing ')' in CALL");
	       termparn = oldtermparn;
	       return(FALSE);
	    }
	    bp++;
	    do {
	       token = cp;
	       while (*cp != ',' && *cp != ')') cp++;
	       term = *cp;
	       *cp++ = '\0';
	       strcpy (lclargs[argcnt], token);
#ifdef DEBUGCALL
	       printf ("   arg[%d] = %s\n", argcnt, token);
#endif
	       argcnt++;
	    } while (term != ')');
	    if (!isspace(*bp)) goto GET_RETURNS;
	 }

	 /*
	 ** Scan off return fields
	 */

	 else if (term == ',')
	 {
      GET_RETURNS:
	    do {
	       if (*bp == '\'') goto GET_ID;
	       bp = tokscan (bp, &token, &tokentype, &val, &term);
	       strcpy (retargs[retcnt], token);
#ifdef DEBUGCALL
	       printf ("   retarg[%d] = %s\n", retcnt, token);
#endif
	       retcnt++;
	    } while (term == ',');
	    if (term == '\'')
	    {
	 GET_ID:
	       bp++;
	       bp = tokscan (bp, &token, &tokentype, &val, &term);
#ifdef DEBUGCALL
	       printf ("   id = %s\n", token);
#endif
	       calline = val;
	    }
	 }

	 /*
	 ** Expand the CALL
	 */

	 genmode = GENINST | CALL;

	 sprintf (genline, "%-6.6s %-7.7s %s,4\n",
		  "", "TSX", name);
	 pc++;
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
	 
	 if (!fapmode)
	 {
	    sprintf (genline, "%-6.6s %-7.7s *+2+%d+%d,,%d\n",
		     "", "TXI", argcnt, retcnt, argcnt);
	    pc++;
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    sprintf (genline, "%-6.6s %-7.7s %d,,..LDIR\n",
		     "", "PZE", calline);
	    pc++;
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	 }

	 for (i = 0; i < argcnt; i++)
	 {
	    sprintf (genline, "%-6.6s %-7.7s %s\n",
		     "", fapmode ? "TSX" : "PZE", lclargs[i]);
	    pc++;
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	 }

	 for (i = retcnt; i > 0; i--)
	 {
	    sprintf (genline, "%-6.6s %-7.7s %s\n",
		     "", "TRA", retargs[i-1]);
	    pc++;
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	 }

	 termparn = oldtermparn;
      }
      break;

   case DUP_T:			/* DUPlicate lines */
      {
         int dupin, dupout;
	 char *duplines[MAXDUPLINES];

	 genmode = DUPINST;

	 /*
	 ** Scan off DUP input line count
	 */

	 bp = exprscan (bp, &dupin, &term, &relocatable, 1, FALSE, 0);
	 if (dupin > MAXDUPLINES)
	 {
	    logerror ("Unsupported opcode addition");
	 }
	 else
	 {
	    /*
	    ** Scan off DUP output line count
	    */

	    bp = exprscan (bp, &dupout, &term, &relocatable, 1, FALSE, 0);

	    /*
	    ** Read the DUP input lines
	    */

	    for (i = 0; i < dupin; i++)
	    {
	       if (etcbuf[0])
	       {
		  strcpy (genline, etcbuf);
		  etcbuf[0] = '\0';
	       }
	       else
		  fgets (genline, MAXSRCLINE, infd);

	       if ((duplines[i] = (char *) DBG_MEMGET (MAXSRCLINE)) == NULL)
	       {
		  fprintf (stderr, "asm7090: Unable to allocate memory\n");
		  exit (ABORT);
	       }
	       strcpy (duplines[i], genline);
	    }

	    /*
	    ** Write out the DUP'd lines
	    */

	    for (i = 0; i < dupout; i++)
	    {
	       for (j = 0; j < dupin; j++)
	       {
		  pc++;
		  fwrite (&genmode, 1, 4, outfd);
		  fputs (duplines[j], outfd);
		  if (strncmp (duplines[j], "      ", 6))
		  {
		     strncpy (duplines[j], "       ", 6);
		  }
		  linenum++;
	       }
	    }
	    for (i = 0; i < dupin; i++)
	       DBG_MEMREL (duplines[i]);
	 }
      }
      break;

   case END_T:			/* END */
      /*
      ** Because of ETC read ahead we reset the input file back one.
      */

      if (!eofflg)
      {
	 if (fseek (infd, curpos, SEEK_SET) < 0)
	    perror ("asm7090: Can't reset input temp file");
      }
      return (TRUE);

   case ENDQ_T:			/* ENDQ */
      if (!fapmode)
      {
	 qualindex --;
	 if (qualindex < 0) qualindex = 0;
      }
      break;

   case EQU_T:			/* EQU */
      bp = exprscan (bp, &val, &term, &relocatable, 1, TRUE, 0);

DO_EQU:
      if (cursym[0])
      {
#ifdef DEBUGEQU
	 printf ("p0pop: EQU: cursym = '%s', val = %05o\n", cursym, val);
#endif
	 if (fapmode)
	 {
	    if (headcount && (strlen(cursym) < MAXSYMLEN))
	    {
	       int i;

	       for (i = 0; i < headcount; i++)
	       {
		  char temp[32];

		  sprintf (temp, "%c", headtable[i]);
#ifdef DEBUGEQU
		  printf ("   cursym = '%s', head = '%s' \n", cursym, temp);
#endif
		  s = symlookup (cursym, temp, TRUE, FALSE);
		  if (s)
		  {
		     s->value = val;
		     s->relocatable = relocatable;
		  }
	       }
	       s = NULL;
	    }
	    else
	    {
#ifdef DEBUGEQU
	       printf ("   cursym = '%s', head = '%s' \n", cursym, "");
#endif
	       s = symlookup (cursym, "", TRUE, FALSE);
	    }
	 }
	 else
	 {
#ifdef DEBUGEQU
	    printf ("   cursym = '%s', qual = '%s' \n",
		    cursym, qualtable[qualindex]);
#endif
	    s = symlookup (cursym, qualtable[qualindex], TRUE, FALSE);
	 }

	 if (s)
	 {
	    s->value = val;
	    s->relocatable = relocatable;
	 }
      }
      break;

   case EVEN_T:			/* EVEN */
      if (absolute & (pc & 00001)) pc++;
      break;

   case GOTO_T:			/* GOTO */

      /*
      ** In this pass, only process if in a macro
      */
      
      if (inmacro)
      {
	 /*
	 ** Scan off target symbol
	 */

	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 if (strlen(token) > MAXSYMLEN) token[MAXSYMLEN] = '\0';
	 strcpy (gotosym, token);
#ifdef DEBUGGOTO
         printf ("asmpass0: GOTO: gotosym = '%s'\n", gotosym);
#endif
	 gotoskip = TRUE;
      }
      break;

   case HEAD_T:			/* HEAD */
      if (fapmode)
      {
	 headcount = 0;
	 do {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	    headtable[headcount++] = token[0];
	    if (headcount >= MAXHEADS)
	    {
	       break;
	    }
	 } while (term == ',');
	 if (headtable[0] == '0') headcount = 0;
      }
      break;

   case IFF_T:			/* IF False */

      /*
      ** In this pass, only process if in a macro
      */
      
      if (inmacro)
      {
	 /*
	 ** Scan the conditional expression and get result
	 */

	 bp = condexpr (bp, &val, &term);
	 if (val >= 0)
	 {
	    int skip;

#ifdef DEBUGIF
	    printf ("p0IFF: val = %d, ifcont = %s\n",
		  val, ifcont ? "TRUE" : "FALSE");
#endif
	    skip = val;
	    asmskip = 0;

	    /*
	    ** If continued, use last result here
	    */

	    if (ifcont)
	    {
#ifdef DEBUGIF
	       printf ("   ifrel = %s, ifskip = %s, skip = %s",
		  ifrel == IFOR ? "OR" : "AND",
		  ifskip ? "TRUE" : "FALSE",
		  skip ? "TRUE" : "FALSE");
#endif
	       if (term == ',')
	       {
		  if (ifrel == IFAND) skip = ifskip || skip;
		  else                skip = ifskip && skip;
		  goto NEXT_IFF_RELATION;
	       }
	       ifcont = FALSE;
	       if (ifrel == IFAND)
	       {
		  if (ifskip || skip)
		     asmskip = 1;
	       }
	       else if (ifrel == IFOR)
	       {
		  if (ifskip && skip)
		     asmskip = 1;
	       }
#ifdef DEBUGIF
	       printf ("   asmskip = %d\n", asmskip);
#endif
	    }

	    /*
	    ** If not continued, check for relation
	    */

	    else if (term == ',')
	    {
	    NEXT_IFF_RELATION:
	       ifcont = TRUE;
	       ifskip = skip;
	       if (!(strcmp (bp, "OR")))
		  ifrel = IFOR;
	       else if (!(strcmp (bp, "AND")))
		  ifrel = IFAND;
#ifdef DEBUGIF
	       printf ("   ifskip = %s\n", ifskip ? "TRUE" : "FALSE");
#endif
	    }

	    /*
	    ** Neither, just do it
	    */

	    else if (skip)
	    {
	       asmskip = 1;
#ifdef DEBUGIF
	       printf ("   asmskip = %d\n", asmskip);
#endif
	    }
	 }
      }
      break;

   case IFT_T:			/* IF True */

      /*
      ** In this pass, only process if in a macro
      */

      if (!fapmode && inmacro)
      {

	 /*
	 ** Scan the conditional expression and get result
	 */

	 bp = condexpr (bp, &val, &term);
	 if (val >= 0)
	 {
	    int skip;

#ifdef DEBUGIF
	    printf ("p0IFT: val = %d, ifcont = %s\n",
		  val, ifcont ? "TRUE" : "FALSE");
#endif
	    skip = !val;
	    asmskip = 0;

	    /*
	    ** If continued, use last result here
	    */

	    if (ifcont)
	    {
#ifdef DEBUGIF
	       printf ("   ifrel = %s, ifskip = %s, skip = %s",
		  ifrel == IFOR ? "OR" : "AND",
		  ifskip ? "TRUE" : "FALSE",
		  skip ? "TRUE" : "FALSE");
#endif
	       if (term == ',')
	       {
		  if (ifrel == IFAND) skip = ifskip || skip;
		  else                skip = ifskip && skip;
		  goto NEXT_IFT_RELATION;
	       }
	       ifcont = FALSE;
	       if (ifrel == IFAND)
	       {
		  if (ifskip || skip)
		     asmskip = 1;
	       }
	       else if (ifrel == IFOR)
	       {
		  if (ifskip && skip)
		     asmskip = 1;
	       }
#ifdef DEBUGIF
	       printf ("   asmskip = %d\n", asmskip);
#endif
	    }

	    /*
	    ** If not continued, check for relation
	    */

	    else if (term == ',')
	    {
	    NEXT_IFT_RELATION:
	       ifcont = TRUE;
	       ifskip = skip;
	       if (!(strcmp (bp, "OR")))
		  ifrel = IFOR;
	       else if (!(strcmp (bp, "AND")))
		  ifrel = IFAND;
#ifdef DEBUGIF
	       printf ("   ifskip = %s\n", ifskip ? "TRUE" : "FALSE");
#endif
	    }

	    /*
	    ** Neither, just do it
	    */

	    else if (skip)
	    {
	       asmskip = 1;
#ifdef DEBUGIF
	       printf ("   asmskip = %d\n", asmskip);
#endif
	    }
	 }
      }
      break;

   case LBL_T:			/* LBL */
      if (fapmode)
      {
	 if (!deckname[0])
	 {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	    if (strlen(token) > MAXLBLLEN) token[MAXLBLLEN] = '\0';
	    strcpy (deckname, token);
	    strcpy (lbl, token);
	 }
      }
      break;

   case LDIR_T:			/* Linkage DIRector */
      if (!fapmode)
      {
	 genmode = GENINST;
	 sprintf (genline, "%-6.6s %-7.7s %s\n", "..LDIR", "PZE", "**");
	 pc++;
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
	 sprintf (genline, "%-6.6s %-7.7s 1,%s\n", "", "BCI", deckname);
	 pc++;
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
      }
      break;

   case MACRO_T:		/* Macro */
      if (inmacro)
	 logerror ("MACRO defintion in MACRO");
      else
	 p0macro (bp, flag, infd, outfd);
      break;

   case NULL_T:			/* NULL */
   	val = pc;
	goto DO_EQU;

   case OPSYN_T:		/* OP SYNonym */
      /*
      ** Scan off opcode
      */

      bp = tokscan (bp, &token, &tokentype, &val, &term);
#ifdef DEBUGOPSYN
      printf (
      "OPSYN0: cursym = %s, token = %s, tokentype = %d, val = %o, term = %c\n",
	      cursym, token, tokentype, val, term);
#endif
      /*
      ** Delete any previous definition and add
      */

      if ((addop = oplookup (token)) != NULL)
      {
	 opdel (cursym);
	 opadd (cursym, addop->opvalue, addop->opmod, addop->optype);
      }

      /*
      ** Synonym opcode not found, error
      */

      else
      {
	 MacDef *oldmac;
	 MacDef *newmac;

	 if ((oldmac = maclookup (token)) != NULL)
	 {
	    newmac = &macdef[macrocount];
	    memcpy (newmac, oldmac, sizeof (MacDef));
	    strcpy (newmac->macname, cursym);
	    macrocount++;
	 }
	 else
	 {
	    sprintf (errtmp, "Invalid opcode for OPSYN: %s", token);
	    logerror (errtmp);
	 }
      }
      break;

   case QUAL_T:			/* QUALified section */
      if (!fapmode)
      {
	 qualindex ++;
	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 if (strlen(token) > MAXSYMLEN) token[MAXSYMLEN] = '\0';
	 strcpy (qualtable[qualindex], token);
      }
      break;

   case RETURN_T:		/* RETURN */
      if (!fapmode)
      {
	 char name[MAXSYMLEN+2];

	 genmode = GENINST | RETURN;
	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 strcpy (name, token);
	 if (term == ',')
	 {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	    sprintf (genline, "%-6.6s %-7.7s %d,4\n", "", "AXT", val);
	    pc++;
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    sprintf (genline, "%-6.6s %-7.7s %s,4\n", "", "SXD", name);
	    pc++;
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	 }
	 sprintf (genline, "%-6.6s %-7.7s %s+1\n", "", "TRA", name);
	 pc++;
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
      }
      break;

   case SAVEN_T:		/* SAVEN cpu context */
      savenmode = TRUE;

   case SAVE_T:			/* SAVE cpu context */
      if (!fapmode)
      {
	 int oldtermparn;
	 int regs[8];
	 int modes[4];
	 char label[MAXSYMLEN+2];
	 char operand[MAXFIELDSIZE];

	 oldtermparn = termparn;
#ifdef DEBUGPARN
	 printf ("p0pop: SAVE: termparn = %s\n", termparn ? "TRUE" : "FALSE");
#endif
	 termparn = TRUE;
	 for (i = 0; i < 8; i++) regs[i] = FALSE;
	 for (i = 0; i < 4; i++) modes[i] = FALSE;

	 /*
	 ** Scan off SAVE args and regs. Order regs.
	 */

	 do
	 {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	    if (term == '(' || term == ')') term = ',';
	    if (tokentype == DECNUM)
	    {
	       if (val < 1 || val > 7)
	       {
		  sprintf (errtmp, "Invalid register for %s: %d",
			   savenmode ? "SAVEN" : "SAVE", val);
		  logerror (errtmp);
		  termparn = oldtermparn;
		  return(FALSE);
	       }
	       regs[val] = TRUE;
	    }
	    else if (tokentype == SYM)
	    {
	       if (!strcmp (token, "I")) modes[0] = TRUE;
	       else if (!strcmp (token, "D")) modes[1] = TRUE;
	       else if (!strcmp (token, "E")) modes[2] = TRUE;
	       else 
	       {
		  sprintf (errtmp, "Invalid mode for %s: %s",
			   savenmode ? "SAVEN" : "SAVE", token);
		  logerror (errtmp);
		  termparn = oldtermparn;
		  return(FALSE);
	       }
	    }
	 } while (term == ',');

	 /*
	 ** Expand the SAVE[N] 
	 */

	 genmode = GENINST | SAVE;

	 /*
	 ** If symbol, generate ENTRY
	 */

	 if (cursym[0])
	 {
	    if (!savenmode && !absmod) /* No ENTRY for SAVEN mode */
	    {
	       sprintf (genline, "%-6.6s %-7.7s %s\n", "", "ENTRY", cursym);
	       fwrite (&genmode, 1, 4, outfd);
	       fputs (genline, outfd);
	       linenum++;
	    }
	    sprintf (operand, "..%04d,,0", lblgennum+3);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", cursym, "TXI", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	 }
	 else 
	 {
	    sprintf (errtmp, "Label required for %s",
		     savenmode ? "SAVEN" : "SAVE");
	    logerror (errtmp);
	    return(FALSE);
	 }

	 /*
	 ** Generate E mode, Error return
	 */

	 if (modes[2])
	 {
	    sprintf (operand, "%s,%d", cursym, 4);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "LDC", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	    sprintf (operand, "%s,%d", "*+5", 4);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "SXD", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	    sprintf (operand, "..%04d,%d", lblgennum+1, 4);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "LAC", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	    sprintf (operand, "%s,%d", "*+1,4", 1);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "TXI", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	    sprintf (operand, "%s,%d", "*+1", 4);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "SXA", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	    sprintf (operand, "%s,%d", "**", 4);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "LXA", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	    sprintf (operand, "%s,%d", "*+1,4", 0);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "TXI", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	    sprintf (operand, "..%04d,%d", lblgennum+2, 4);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "SXA", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	 }

	 /*
	 ** Generate index register loads
	 */

	 for (i = 7; i > 0; i--)
	 {
	       if (i == 4) continue;
	       if (regs[i])
	       {
		  sprintf (operand, "%s,%d", "**", i);
		  sprintf (genline, "%-6.6s %-7.7s %s\n", "", "AXT", operand);
		  fwrite (&genmode, 1, 4, outfd);
		  fputs (genline, outfd);
		  linenum++;
		  pc++;
	       }
	 }
	 
	 sprintf (label, "..%04d", lblgennum+1);
	 sprintf (operand, "%s,%d", "**", 4);
	 sprintf (genline, "%-6.6s %-7.7s %s\n", label, "AXT", operand);
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
	 pc++;
	 
	 /* 
	 ** Generate Indicator load
	 */

	 if (modes[0])
	 {
	    sprintf (operand, "..%04d+1", lblgennum+2);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "LDI", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	 }

	 /*
	 ** Generate Trap enables
	 */

	 if (modes[1])
	 {
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "NZT", ".TRPSW");
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "ENB*", ".TRAPX");
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	 }
	 sprintf (label, "..%04d", lblgennum+2);
	 if (modes[2])
	 {
	    strcpy (operand, "**");
	 }
	 else
	 {
	    strcpy (operand, "1,4");
	 }
	 sprintf (genline, "%-6.6s %-7.7s %s\n", label, "TRA", operand);
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
	 pc++;

	 if (modes[0])
	 {
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "PZE", "**");
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	 }
	 sprintf (label, "..%04d", lblgennum+3);
	 sprintf (genline, "%-6.6s %-7.7s %s\n", label, "EQU", "*");
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
	 pc++;
	 if (modes[1])
	 {
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "XEC", "SYSDSB");
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	 }

	 /*
	 ** Gerate Indicator save
	 */

	 if (modes[0])
	 {
	    sprintf (operand, "..%04d+1", lblgennum+2);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "STI", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	 }

	 /*
	 ** Generate Trap save
	 */

	 if (modes[2])
	 {
	    sprintf (operand, "%s,%d", cursym, 0);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "SXD", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	 }
	 sprintf (operand, "%s,%d", "SYSLOC", 4);
	 sprintf (genline, "%-6.6s %-7.7s %s\n", "", "SXA", operand);
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
	 pc++;

	 /*
	 ** Generate Linkage Director, if not SAVEN
	 */

	 if (!savenmode)
	 {
	    sprintf (operand, "%s,%d", "..LDIR", 4);
	    sprintf (genline, "%-6.6s %-7.7s %s\n", "", "SXA", operand);
	    fwrite (&genmode, 1, 4, outfd);
	    fputs (genline, outfd);
	    linenum++;
	    pc++;
	 }

	 /*
	 ** Generate save registers
	 */

	 sprintf (operand, "..%04d,%d", lblgennum+1, 4);
	 sprintf (genline, "%-6.6s %-7.7s %s\n", "", "SXA", operand);
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
	 pc++;
	 j = 1;
	 for (i = 1; i < 8; i++)
	 {
	    if (i == 4) continue;
	    if (regs[i])
	    {
	       sprintf (operand, "..%04d-%d,%d", lblgennum+1, j, i);
	       sprintf (genline, "%-6.6s %-7.7s %s\n", "", "SXA", operand);
	       fwrite (&genmode, 1, 4, outfd);
	       fputs (genline, outfd);
	       linenum++;
	       pc++;
	       j++;
	    }
	 }
	 lblgennum += 3;
	 termparn = oldtermparn;
      }
      break;

   case SET_T:			/* SET value immediately */
      bp = exprscan (bp, &val, &term, &relocatable, 1, FALSE, 0);
      if (cursym[0])
      {
	 if (!(s = symlookup (cursym, "", FALSE, FALSE)))
	    s = symlookup (cursym, "", TRUE, FALSE);
	 if (s)
	 {
	    s->value = val;
	    s->relocatable = FALSE;
	    s->setvar = TRUE;
	 }
      }
      break;

   case SST_T:
      if (fapmode)
      {
	 monsym = TRUE;
	 bp = tokscan (bp, &token, &tokentype, &val, &term);
#ifdef DEBUGMONSYM
	 printf ("SST %s\n", token);
#endif
	 definemonsyms(0);
	 if (!strcmp (token, "FORTRAN"))
	 {
	    definemonsyms(1);
	 }
      }
      break;

   default: ;
   }

   return (FALSE);
}

/***********************************************************************
* p0expand - Expand macros
***********************************************************************/

static void
p0expand (MacDef *mac, int flag, char *bp, FILE *infd, FILE *outfd)
{
   OpCode *op;
   MacDef *lclmac;
   char *token;
   char *cp;
   char *ocp;
   int tokentype;
   int inirp;
   int irpline;
   int irpnum;
   int val;
   int i, j;
   int done;
   int genmode;
   int lclflag;
   int argcnt;
   int oldtermparn;
   char term;
   char genline[MAXSRCLINE];
   char lclargs[MAXMACARGS][MAXFIELDSIZE];
   char irpargs[MAXFIELDSIZE];
   char irparg[MAXFIELDSIZE];


#ifdef DEBUGMACROEXP
   printf ("p0expand: macro = %s, args = %s", mac->macname, bp);
#endif

   oldtermparn = termparn;
#ifdef DEBUGPARN
   printf ("p0expand: termparn = %s\n", termparn ? "TRUE" : "FALSE");
#endif
   termparn = TRUE;

   for (i = 0; i < MAXMACARGS; i++) lclargs[i][0] = '\0';

   /*
   ** If an indirect Macro and flag is set, the first arg is "*".
   */

   argcnt = 0;
   if (mac->macindirect)
   {
      if (flag)
	 strcpy (lclargs[0], "*");
      argcnt++;
   }

   /*
   ** Scan off MACRO arguments
   */

   do {
      ocp = bp;
      bp = tokscan (bp, &token, &tokentype, &val, &term);
#ifdef DEBUGMACROEXP
      printf (
	    "   token = %s, tokentype = %d, val = %o, term = %c(%x)\n",
	    token, tokentype, val, term, term);
#endif
      if (token[0] == '\0' && term == '(')
      {
	 ocp = bp;
	 i = 1;
         while (*bp && i > 0 && !isspace(*bp))
	 {
	    if (*bp == '(')
	    {
	       i++;
	       bp++;
	    }
	    else if (*bp == ')')
	    {
	       if (i)
	       {
		  i--;
		  if (i) bp++;
	       }
	    }
	    else bp++;
	 }
#ifdef DEBUGMACROEXP
         printf ("   *bp = %c(%x) %s, pocp = %s\n", *bp, *bp, bp, ocp);
#endif
	 if (*bp == ')')
	 {
	    *bp++ = '\0';
	    strcat (lclargs[argcnt], ocp);
	 }
	 else
	 {
	    logerror ("Missing ')' in macro");
	 }
	 term = *bp;
	 if (term == ',') bp++;
	 else if (isalnum(term) || term == '.')
	    term = ',';
      }
      else if (token[0] == '\0' && tokentype == NULSYM)
      {
	 strcat (lclargs[argcnt], "**");
      }
      else if (token[0] == '\0' && tokentype == ASTER)
      {
	 strcat (lclargs[argcnt], "*");
      }
      else if (token[0] == '\0' && tokentype == EOS)
      {
      }
      else if (token[0] == '\0')
      {
         strncat (lclargs[argcnt], &term, 1);
      }
      else
      {
	 strcat (lclargs[argcnt], token);
      }
      if (isspace (term) || term == ',') argcnt++;
   } while (!isspace(term));

   termparn = oldtermparn;

#ifdef DEBUGMACROEXP
   for (i = 0; i < argcnt; i++)
      printf ("   arg%02d = %s\n", i, lclargs[i]);
#endif

   inirp = FALSE;

   /*
   ** Go through MACRO and fill in missing labels with generated labels.
   */

   for (i = 0; i < mac->maclinecount; i++)
   {
      char genindex[3];

      cp = mac->maclines[i]->label;
      if ((ocp = strchr(cp, '#')) != NULL)
      {
	 ocp++;
	 strncpy (genindex, ocp, 2);
	 genindex[2] = '\0';
	 j = atoi (genindex);
	 if (!lclargs[j][0])
	 {
	    sprintf (lclargs[j], "..%04d", lblgennum);
	    lblgennum++;
	 }
      }
   }

   /*
   ** Go through MACRO template and replace parameters with the
   ** user arguments.
   */

   for (i = 0; i < mac->maclinecount; i++)
   {
      char genlabel[MAXFIELDSIZE];
      char genopcode[MAXFIELDSIZE];
      char genoperand[MAXFIELDSIZE];
      char genindex[3];

      /*
      ** Process label field
      */

      done = FALSE;
      genmode = 0;
      genlabel[0] = '\0';
      token = genlabel;
      cp = mac->maclines[i]->label;

      while (*cp && !done)
      {
	 if ((ocp = strchr(cp, '#')) != NULL)
	 {
	    if (ocp > cp)
	       strncat (token, cp, ocp-cp);
	    ocp++;
	    strncpy (genindex, ocp, 2);
	    ocp += 2;
	    cp = ocp;
	    genindex[2] = '\0';
	    j = atoi (genindex);
	    if (inirp && j == irpnum)
	    {
	       strcat(token, irparg);
	    }
	    else
	    {
	       strcat (token, lclargs[j]);
	    }
	 }
	 else
	 {
	    strcat (token, cp);
	    done = TRUE;
	 }
      }
      if (strlen(genlabel) > MAXSYMLEN) genlabel[MAXSYMLEN] = '\0';
      strcpy (cursym, genlabel);
#ifdef DEBUGMACROEXP
      printf ("   genlabel = %s\n", genlabel);
#endif

      /*
      ** Process opcode field
      */

      done = FALSE;
      genopcode[0] = '\0';
      token = genopcode;
      cp = mac->maclines[i]->opcode;

      while (*cp && !done)
      {
	 if ((ocp = strchr(cp, '#')) != NULL)
	 {
	    if (ocp > cp)
	       strncat (token, cp, ocp-cp);
	    ocp++;
	    strncpy (genindex, ocp, 2);
	    ocp += 2;
	    cp = ocp;
	    genindex[2] = '\0';
	    j = atoi (genindex);
	    if (inirp && j == irpnum)
	    {
	       strcat(token, irparg);
	    }
	    else
	    {
	       strcat (token, lclargs[j]);
	    }
	 }
	 else
	 {
	    strcat (token, cp);
	    done = TRUE;
	 }
      }
#ifdef DEBUGMACROEXP
      printf ("   genopcode = %s\n", genopcode);
#endif

      /*
      ** Process operand field
      */

      done = FALSE;
      genoperand[0] = '\0';
      token = genoperand;
      cp = mac->maclines[i]->operand;

      while (*cp && !done)
      {
	 if ((ocp = strchr(cp, '#')) != NULL)
	 {
	    if (ocp > cp)
	       strncat (token, cp, ocp-cp);
	    ocp++;
	    strncpy (genindex, ocp, 2);
	    ocp += 2;
	    cp = ocp;
	    genindex[2] = '\0';
	    j = atoi (genindex);
	    if (inirp && j == irpnum)
	    {
	       strcat(token, irparg);
	    }
	    else
	    {
	       strcat (token, lclargs[j]);
	    }
	 }
	 else
	 {
	    strcat (token, cp);
	    done = TRUE;
	 }
      }
      strcat (genoperand, "\n");
#ifdef DEBUGMACROEXP
      printf ("   genoperand = %s", genoperand);
#endif
      sprintf (genline, "%-6.6s %-7.7s %s", genlabel, genopcode, genoperand);
#ifdef DEBUGMACROEXP
      printf ("%s", genline);
#endif
      
      /*
      ** Lookup opcode for macro expansion control
      */

      lclflag = 0;
      termparn = FALSE;
      tokscan (genopcode, &token, &tokentype, &val, &term);
      termparn = oldtermparn;
      op = oplookup (token);
      if (term == INDIRECTSYM) lclflag = 060;

      /*
      ** If not skipping, IF[F/T], process
      */

      if (!asmskip)
      {
	 /*
	 ** Process GOTO in macro
	 */

	 if (gotoskip)
	 {
	    if (cursym[0] && !strcmp(cursym, gotosym))
	    {
#ifdef DEBUGGOTO
	       printf ("   cursym = '%s', gotosym = '%s'\n", cursym, gotosym);
#endif
	       gotoskip = FALSE;
	       goto GOTO_ENDS;
	    }
	    else
	    {
#ifdef DEBUGGOTO
	       printf ("   genopcode = '%s'\n", genopcode);
#endif
	       if (op && op->optype == TYPE_P && op->opvalue == IRP_T)
	       {
	          gotoskip = FALSE;
		  genmode = MACEXP | MACCALL;
	       }
	       else
	       {
		  genmode = MACEXP | SKPINST;
	       }
	       fwrite (&genmode, 1, 4, outfd);
	       fputs (genline, outfd);
	       linenum++;
	    }
	 }

	 /*
	 ** Not in GOTO, check for other controls
	 */

	 else
	 {
	 GOTO_ENDS:
	    /*
	    ** Check Pseudo ops that control macro
	    */

	    if (op && op->optype == TYPE_P)
	    {
	       char psopline[MAXSRCLINE];

	       switch (op->opvalue)
	       {
	       case IFF_T:
	       case IFT_T:
	       case GOTO_T:
		  genmode = MACCALL;
	       case SET_T:
		  genmode |= MACEXP;
		  fwrite (&genmode, 1, 4, outfd);
		  fputs (genline, outfd);
		  linenum++;
		  strcpy (psopline, genoperand);
		  cp = psopline;
		  p0pop (op, lclflag, cp, infd, outfd, TRUE);
		  break;

	       case IRP_T:

		  /*
		  ** Process IRP here
		  */

		  genmode = (MACEXP | MACCALL);
		  fwrite (&genmode, 1, 4, outfd);
		  fputs (genline, outfd);
		  linenum++;

		  /*
		  ** If in IRP block, get next IRP arg
		  */

		  if (inirp)
		  {
		     irparg[0] = '\0';
		     strcpy (genoperand, irpargs);
		     cp = genoperand;

		     /*
		     ** If another IRP args, scan it off and loop
		     */

		     if (*cp)
		     {
			if (*cp == '(')
			{
			   int ii;

			   cp++;
			   ocp = cp;
			   ii = 1;
			   while (*cp && ii > 0 && !isspace(*cp))
			   {
			      if (*cp == '(')
			      {
				 ii++;
				 cp++;
			      }
			      else if (*cp == ')')
			      {
				 if (ii)
				 {
				    ii--;
				 }
			      }
			      else cp++;
			   }
#ifdef DEBUGMACROEXP
			printf ("   *cp = %c(%x), pocp = %s\n", *cp, *cp, ocp);
#endif
			   if (*cp == ')')
			   {
			      *cp++ = '\0';
			      if (*cp == ',') cp++;
			   }
			   strcpy (irparg, ocp);
			}
			else do {
			   cp = tokscan (cp, &token, &tokentype, &val, &term);
			   strcat (irparg, token);
			   if (term == ',') break;
			} while (*cp);
			strcpy (irpargs, cp);
#ifdef DEBUGMACROEXP
			printf ("   irpargs1 = %s\n", irpargs);
			printf ("   irparg1  = %s\n", irparg);
#endif
			i = irpline;
		     }
		     /*
		     ** No more args, exit loop
		     */
		     else
		     {
			inirp = FALSE;
		     }
		  }

		  /*
		  ** New IRP, get first arg and start loop
		  */

		  else
		  {
		     inirp = TRUE;
		     irpline = i;
		     irpnum = j;
		     irparg[0] = '\0';
		     cp = strchr (genoperand, '\n');
		     *cp = '\0';
		     cp = genoperand;
		     if (*cp == '(')
		     {
			int ii;

		        cp++;
			ocp = cp;
			ii = 1;
			while (*cp && ii > 0 && !isspace(*cp))
			{
			   if (*cp == '(')
			   {
			      ii++;
			      cp++;
			   }
			   else if (*cp == ')')
			   {
			      if (ii)
			      {
				 ii--;
			      }
			   }
			   else cp++;
			}
#ifdef DEBUGMACROEXP
		     printf ("   *cp = %c(%x), pocp = %s\n", *cp, *cp, ocp);
#endif
			if (*cp == ')')
			{
			   *cp++ = '\0';
			   if (*cp == ',') cp++;
			}
			strcpy (irparg, ocp);
		     }
		     else do {
			cp = tokscan (cp, &token, &tokentype, &val, &term);
			strcat (irparg, token);
		     } while (*cp && term != ',');
		     strcpy (irpargs, cp);
#ifdef DEBUGMACROEXP
		     printf ("   irpargs0 = %s\n", irpargs);
		     printf ("   irparg0  = %s\n", irparg);
#endif
		  }
		  break;

	       default:
		  genmode = MACEXP;
		  fwrite (&genmode, 1, 4, outfd);
		  fputs (genline, outfd);
		  linenum++;
	       }
	    }

	    /*
	    ** Check if macro is called in macro
	    */

	    else if ((lclmac = maclookup (genopcode)) != NULL)
	    {
	       genmode = (MACEXP | MACCALL);
	       fwrite (&genmode, 1, 4, outfd);
	       fputs (genline, outfd);
	       linenum++;
	       p0expand (lclmac, lclflag, genoperand, infd, outfd);
	    }

	    /*
	    ** None of the above, send it on to next pass
	    */

	    else
	    {
	       genmode = MACEXP;
	       fwrite (&genmode, 1, 4, outfd);
	       fputs (genline, outfd);
	       linenum++;
	    }
	 }
      }

      /*
      ** In skip, decrement skip count
      */

      else
      {
	 genmode = MACEXP | SKPINST;
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
#ifdef DEBUGIF
         printf ("SKIP: %s", genline);
#endif
	 linenum++;
	 asmskip--;
      }
   }

}

/***********************************************************************
* p0ibsys - process IBSYS cards.
***********************************************************************/

static void
p0ibsys (char *bp, FILE *outfd)
{
   char *token;
   int genmode;
   int tokentype;
   int val;
   int oldtermparn;
   char term;

#ifdef DEBUGCTLCARD
   printf ("p0ibsys: %s", bp);
#endif

   /*
   ** Send control card to next pass
   */

   genmode = CTLCARD;
   fwrite (&genmode, 1, 4, outfd);
   fputs (bp, outfd);

   oldtermparn = termparn;
#ifdef DEBUGPARN
   printf ("p0ibsys: termparn = %s\n", termparn ? "TRUE" : "FALSE");
#endif
   termparn = FALSE;

   bp++;
   /*
   ** If not a comment, process
   */

   if (*bp != COMMENTSYM)
   {
      /*
      ** Scan off command
      */

      bp = tokscan (bp, &token, &tokentype, &val, &term);
#ifdef DEBUGCTLCARD
      printf (
	    "   token1 = %s, tokentype = %d, val = %o, term = %c(%x)\n",
	    token, tokentype, val, term, term);
#endif
      /*
      ** If $TITLE then scan off the title
      */

      if (!strcmp (token, "TITLE"))
      {
	 char *cp;

	 bp = &inbuf[VARSTART];
	 while (*bp && isspace (*bp)) bp++;
	 cp = bp;
	 while (*bp != '\n')
	 {
	    if (bp - inbuf > RIGHTMARGIN) break;
	    if (bp - cp == TTLSIZE) break;
	    bp++;
	 }
	 *bp = '\0';
	 strcpy (titlebuf, cp);
      }

      /*
      ** If $EXECUTE then scan and check if IBSFAP.
      */

      else if (!strcmp (token, "EXECUTE"))
      {
	 bp = &inbuf[VARSTART];
	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 if (!strcmp (token, "IBSFAP"))
	 {
	    fapmode = TRUE;
	    oldtermparn = FALSE;
	 }
      }

      /*
      ** If $IBMAP then scan and process the options.
      */

      else if (!strcmp (token, "IBMAP"))
      {
         bp = &inbuf[OPCSTART];

	 /*
	 ** Get the deckname
	 */

	 if (!isspace(*bp))
	 {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
#ifdef DEBUGCTLCARD
	    printf (
	    "   token2 = %s, tokentype = %d, val = %o, term = %c(%x)\n",
	    token, tokentype, val, term, term);
#endif
	    if (strlen (token) > MAXSYMLEN) token[MAXSYMLEN] = '\0';
	    strcpy (deckname, token);
	    if (strlen (token) > 4) token[4] = '\0';
	    strcpy (lbl, token);
	    
	 }

	 /*
	 ** Parse the options
	 */

	 bp = &inbuf[VARSTART];
	 do {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	    if (term == '(')
	    {
	       strcpy (token, "(");
	       strncat (token, bp, 3);
	       bp += 3;
	       term = *bp;
	       if (*bp == ',') bp++;
	    }
#ifdef DEBUGCTLCARD
	    printf (
	    "   token3 = %s, tokentype = %d, val = %o, term = %c(%x)\n",
	    token, tokentype, val, term, term);
#endif
	    if (!strcmp (token, "ABSMOD"))
	    {
	       addext = FALSE;
	       absmod = TRUE;
	    }
	    else if (!strcmp (token, "ADDREL"))
	    {
	       addrel = TRUE;
	       addext = TRUE;
	       absmod = FALSE;
	    }
	    else if (!strcmp (token, "RELMOD"))
	    {
	       addext = TRUE;
	       absmod = FALSE;
	    }
	    else if (!strcmp (token, "JOBSYM"))
	    {
	       jobsym = TRUE;
	       definejobsyms();
	    }
	    else if (!strcmp (token, "M90"))
	    {
	       cpumodel = 7090;
	    }
	    else if (!strcmp (token, "M94"))
	    {
	       cpumodel = 7094;
	    }
	    else if (!strcmp (token, "MONSYM"))
	    {
	       monsym = TRUE;
	       definemonsyms(0);
	    }
	    else if (!strcmp (token, "NO()"))
	    {
	       oldtermparn = TRUE;
	    }
	    else if (!strcmp (token, "()OK"))
	    {
	       oldtermparn = FALSE;
	    }
	    else if (!strcmp (token, "REF"))
	    {
	       genxref = TRUE;
	    }
	 } while (term == ',');
      }
   }

   termparn = oldtermparn;
#ifdef DEBUGPARN
   printf ("p0ibsys: exit: termparn = %s\n", termparn ? "TRUE" : "FALSE");
#endif
}

/***********************************************************************
* asmpass0 - Pass 0
***********************************************************************/

int
asmpass0 (FILE *tmpfd0, FILE *tmpfd1)
{
   MacDef *mac;
   char *token;
   int i;
   int done;
   int flag;
   int genmode;
   int status = 0;
   int tokentype;
   int val;
   char term;
   char opcode[MAXSYMLEN+2];

#ifdef DEBUGP0RDR
   printf ("asmpass0: Entered\n");
#endif

   /*
   ** Clear out macro table.
   */

   for (i = 0; i < MAXMACROS; i++)
   {
      memset ((char *)&macdef[i], '\0', sizeof(MacDef));
   }

   lblgennum = 1;
   macrocount = 0;
   macsloaded = FALSE;

   /*
   ** Rewind the output.
   */

   if (fseek (tmpfd1, 0, SEEK_SET) < 0)
   {
      perror ("asm7090: Can't rewind temp file");
      return (-1);
   }

   /*
   ** Process the source.
   */

   pc = 0;
   linenum = 0;

   etcbuf[0] = '\0';
   qualindex = 0;
   linenum = 0;
   headcount = 0;
   done = FALSE;

   while (!done)
   {
      char *bp;

      srcbuf[0] = '\0';
      curpos = ftell (tmpfd0);
      if (etcbuf[0])
      {
         strcpy (srcbuf, etcbuf);
	 if (!eofflg && !fgets(etcbuf, MAXSRCLINE, tmpfd0))
	 {
	    etcbuf[0] = '\0';
	    eofflg = TRUE;
	 }
      }
      else
      {
	 if (!eofflg && !fgets(srcbuf, MAXSRCLINE, tmpfd0))
	 {
	    srcbuf[0] = '\0';
	    eofflg = TRUE;
	 }
	 else if (!eofflg && !fgets(etcbuf, MAXSRCLINE, tmpfd0))
	 {
	    etcbuf[0] = '\0';
	    eofflg = TRUE;
	 }
      }

      if (eofflg && !srcbuf[0])
      {
         done = TRUE;
	 status = 1;
	 break;
      }

      linenum++;
      genmode = 0;
      gotoskip = FALSE;
      exprtype = ADDREXPR;
      radix = 10;

      strcpy (inbuf, srcbuf);
#ifdef DEBUGP0RDR
      printf ("P0in = %s", inbuf);
#endif
      bp = inbuf;

      /*
      ** Check if IBSYS control card.
      */

      if (*bp == IBSYSSYM)
      {
         p0ibsys (bp, tmpfd1);
	 linenum--;
      }

      /*
      ** If not a comment, then process.
      */

      else if (*bp != COMMENTSYM)
      {
	 OpCode *op;

	 /*
	 ** If not 7094 mode assmebly, define macros for 7094 instructions.
	 */

	 if (!macsloaded && cpumodel > 704 && cpumodel < 7094)
	 {
	    macsloaded = TRUE;

	    for (i = 0; macros7094[i]; i++)
	    {
	       p0macrostring (macros7094[i]);
	    }

	 }
	 
	 /*
	 ** If label present, add to symbol table.
	 ** On MAP/FAP the symbol can start in any column up to 6.
	 ** And FAP can have embedded blanks, eg. "( 3.4)"
	 */

	 if (strncmp (bp, "      ", 6))
	 {
	    char *cp;
	    char *dp;
	    char temp[8];

	    strncpy (temp, bp, 6);
	    cp = temp+6;
	    *cp-- = '\0';
	    while (*cp == ' ') *cp-- = '\0';
	    cp = dp = temp;
	    while (*cp)
	    {
	       if (*cp == ' ') cp++;
	       else *dp++ = *cp++;
	    }
	    *dp = '\0';

	    strcpy (cursym, temp);
#ifdef DEBUGCURSYM
	    printf ("asmpass0: cursym = %s\n", cursym);
#endif
	    bp += 6;
	    while (*bp && isspace (*bp)) bp++;
	 }
	 else 
	 {
	    cursym[0] = '\0';
	    while (*bp && isspace (*bp)) bp++;
	 }

	 /*
	 ** Scan off opcode.
	 */

	 if (!strncmp (&inbuf[OPCSTART], "   ", 3))
	 {
	    strcpy (opcode, "PZE"); /* Make a blank opcode a PZE */
	    bp = &inbuf[10];
	 }
	 else
	 {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	    strcpy (opcode, token);
	 }

	 /*
	 ** Check etcbuf for ETC
	 */

	 if (etcbuf[0])
	 {
	    if ((strlen(etcbuf) > OPCSTART+4) &&
	        !strncmp (&etcbuf[OPCSTART], "ETC", 3))
	    {
	       genmode |= CONTINU;
	    }
	 }

	 /*
	 ** Check for indirect addressing.
	 ** Maybe either "TRA*  SYM" or "TRA  *SYM".
	 */

	 flag = 0;
	 if (term == INDIRECTSYM)
	 {
	    flag = 060;
	    bp++;
	 }
	 else
	 {
	    int nooperands;

	    while (*bp && isspace(*bp))
	    {
	       if (*bp == '\n' || (bp - inbuf >= NOOPERAND))
	       {
		  nooperands = TRUE;
		  break;
	       }
	       bp++;
	    }
	    if (!nooperands && *bp == INDIRECTSYM &&
	       ((isalnum(*(bp+1)) || (*(bp+1) == '.'))))
	    {
	       flag = 060;
	       bp++;
	    }
	    else
	       flag = 0;
	 }

	 /*
	 ** Check opcodes
	 */

	 op = oplookup (opcode);

	 /*
	 ** If pseudo op, process
	 */

	 if (op && op->optype == TYPE_P)
	 {
	    /*
	    ** Set MACCALL for CALL, SAVE[N] and RETURN.
	    */

	    switch (op->opvalue)
	    {
	    case CALL_T:
	    case SAVE_T:
	    case SAVEN_T:
	    case RETURN_T:
	       genmode |= MACCALL;
	       break;
	    default: ;
	    }

	    fwrite (&genmode, 1, 4, tmpfd1);
	    fputs (srcbuf, tmpfd1);
	    done = p0pop (op, flag, bp, tmpfd0, tmpfd1, FALSE);
	    if (done) status = 0;
	 }

	 /*
	 ** Else, Check macro table
	 */

	 else if ((mac = maclookup (opcode)) != NULL)
	 {
	    genmode |= MACCALL;
	    fwrite (&genmode, 1, 4, tmpfd1);
	    fputs (srcbuf, tmpfd1);
	    p0expand (mac, flag, bp, tmpfd0, tmpfd1);
	    asmskip = 0;
	    gotoskip = FALSE;
	 }

	 /*
	 ** None of the above, send on
	 */

	 else
	 {
	    pc++;
	    fwrite (&genmode, 1, 4, tmpfd1);
	    fputs (srcbuf, tmpfd1);
	 }
      }

      /*
      ** A comment, in FAP there is some meaning.
      */

      else
      {
	 fwrite (&genmode, 1, 4, tmpfd1);
	 fputs (srcbuf, tmpfd1);
	 if (fapmode && !titlebuf[0])
	 {
	    char *cp;

	    bp++;
	    while (*bp && isspace(*bp)) bp++;
	    cp = bp;
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	    if (!strcmp (token, "FAP")) ;
	    else if (!strcmp (token, "ID")) ;
	    else
	    {
	       while (*bp != '\n')
	       {
		  if (bp - inbuf > RIGHTMARGIN) break;
		  if (bp - cp == TTLSIZE) break;
		  bp++;
	       }
	       *bp = '\0';
	       strcpy (titlebuf, cp);
	    }
	 }
      }

   }

   /*
   ** Clean up
   */

   for (i = 0; i < macrocount; i++)
   {
      int j;
      for (j = 0; j < macdef[i].maclinecount; j++)
      {
         macdef[i].maclines[j]->next = freemaclines;
	 freemaclines = macdef[i].maclines[j];
      }
   }

#ifdef DEBUGMULTIFILE
   printf ("asmpass0: %d lines in file\n", linenum);
#endif

   return (status);
}
