/***********************************************************************
*
* asmpass0 - Pass 0 for the IBM 7090 assembler.
*
* Changes:
*   12/12/04   DGP   Original.
*	
***********************************************************************/

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

#include "asmdef.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 errcount;		/* Number of errors in assembly */
extern int exprtype;		/* Expression type */
extern int p1errcnt;		/* Number of pass 0/1 errors */
extern int pgmlength;		/* Length of program */
extern int absmod;		/* In absolute module */
extern int monsym;		/* Include Monitor Symbols (MONSYM) */
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 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 SymNode *symbols[MAXSYMBOLS];/* The Symbol table */
extern ErrTable p1error[MAXERRORS];/* The pass 0/1 error table */

static int asmskip;		/* In skip line mode IFF/IFT */
static int gotoskip;		/* In GOTO mode */
static int lblgennum = 0;	/* LBL generated number */
static int macrocount = 0;	/* 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 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 MacDef macdef[MAXMACROS];/* Macro template table */

/***********************************************************************
* 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];

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

   /*
   ** Check for NULL operands 
   */

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

   /*
   ** Substitute #%02d for each macro parameter. The number corresponds to
   ** the paramter number.
   */

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

      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 == '\'')
      {
	 for (j = 0; j < mac->macargcount; j++)
	 {
	    if (!strcmp (token, mac->macargs[j]))
	    {
	       sprintf (token, "#%02d", j);
	       break;
	    }
	 }
	 strcat (largs, token);

	 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 (term == '\'') cp++;
	 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 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 (!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);
}

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

static void
p0macro (char *bp, 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;
   termparn = TRUE;

   mac = &macdef[macrocount];

   strcpy (mac->macname, cursym);

   /*
   ** Scan off the parameters
   */

   i = 0;
   do {
      bp = tokscan (bp, &token, &tokentype, &val, &term);
      strcpy (mac->macargs[i], token);
      i++;
   } while (!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 ENDM, we're done
      */

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

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

      else if (genline[0] != COMMENTSYM)
      {

	 /*
	 ** Allocate line template
	 */

	 if ((mac->maclines[i] = (MacLines *)malloc(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 (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;
}

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

static void
p0pop (OpCode *op, 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 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;
	 termparn = TRUE;
	 calline = linenum;

	 /*
	 ** Get name of called routine
	 */

	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 strcpy (name, token);

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

	 if (term == '(')
	 {
	    bp++;
	    cp = bp;
	    while (*bp != ')' && !isspace (*bp)) bp++;
	    if (*bp != ')')
	    {
	       errcount++;
	       p1error[p1errcnt].errorline = linenum;
	       p1error[p1errcnt].errortext = (char *)malloc (120);
	       sprintf (p1error[p1errcnt].errortext,
			"Missing ')' in CALL");
	       p1errcnt++;
	       return;
	    }
	    bp++;
	    do {
	       cp = tokscan (cp, &token, &tokentype, &val, &term);
	       strcpy (lclargs[argcnt],token);
	       argcnt++;
	    } while (term != ')');
	    if (!isspace(*bp)) goto GET_RETURNS;
	 }

	 /*
	 ** Scan off return fields
	 */

	 else if (term == ',')
	 {
      GET_RETURNS:
	    do {
	       bp = tokscan (bp, &token, &tokentype, &val, &term);
	       strcpy (retargs[argcnt], token);
	       retcnt++;
	    } while (term == ',');
	    if (term == '\'')
	    {
	       bp++;
	       bp = tokscan (bp, &token, &tokentype, &val, &term);
	       calline = val;
	    }
	 }
	 
	 /*
	 ** Expand the CALL
	 */

	 genmode = GENINST;
	 sprintf (genline, "%-6.6s %-7.7s %s,4\n",
		  "", "TSX", name);
	 pc++;
	 fwrite (&genmode, 1, 4, outfd);
	 fputs (genline, outfd);
	 linenum++;
	 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",
		     "", "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]);
	    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)
	 {
	    errcount++;
	    p1error[p1errcnt].errorline = linenum;
	    p1error[p1errcnt].errortext = (char *)malloc (120);
	    sprintf (p1error[p1errcnt].errortext,
		     "Unsupported opcode addition");
	    p1errcnt++;
	 }
	 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 *) malloc (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);
		  linenum++;
	       }
	    }
	    for (i = 0; i < dupin; i++)
	       free (duplines[i]);
	 }
      }
      break;

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

   case EQU_T:			/* EQU */
      bp = exprscan (bp, &val, &term, &relocatable, 1, TRUE, 0);
      if (cursym[0])
      {
	 if (!(s = symlookup (cursym, qualtable[qualindex], FALSE, FALSE)))
	    s = symlookup (cursym, qualtable[qualindex], TRUE, FALSE);
	 if (s)
	 {
	    s->value = val;
	    s->relocatable = relocatable;
	 }
      }
#ifdef DEBUGEQU
      printf ("p0pop: EQU: cursym = '%s', val = %d\n", cursym, val);
#endif
      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 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;

	    skip = val;
	    asmskip = 0;

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

	    if (ifcont)
	    {
#ifdef DEBUGIF
	       printf ("p0IFF: ifrel = %s, ifskip = %s, skip = %s",
		  ifrel == IFOR ? "OR" : "AND",
		  ifskip ? "TRUE" : "FALSE",
		  skip ? "TRUE" : "FALSE");
#endif
	       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 == ',')
	    {
	       ifcont = TRUE;
	       ifskip = skip;
	       if (!(strcmp (bp, "OR")))
		  ifrel = IFOR;
	       else if (!(strcmp (bp, "AND")))
		  ifrel = IFAND;
	    }

	    /*
	    ** Neither, just do it
	    */

	    else if (val)
	    {
	       asmskip = 1;
	    }
	 }
      }
      break;

   case IFT_T:			/* IF True */

      /*
      ** 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;

	    skip = val;
	    asmskip = 0;

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

	    if (ifcont)
	    {
#ifdef DEBUGIF
	       printf ("p0IFT: ifrel = %s, ifskip = %s, skip = %s",
		  ifrel == IFOR ? "OR" : "AND",
		  ifskip ? "TRUE" : "FALSE",
		  skip ? "TRUE" : "FALSE");
#endif
	       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 == ',')
	    {
	       ifcont = TRUE;
	       ifskip = skip;
	       if (!(strcmp (bp, "OR")))
		  ifrel = IFOR;
	       else if (!(strcmp (bp, "AND")))
		  ifrel = IFAND;
	    }

	    /*
	    ** Neither, just do it
	    */

	    else if (!val)
	    {
	       asmskip = 1;
	    }
	 }
      }
      break;

   case LDIR_T:			/* Linkage DIRector */
      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)
      {
	 errcount++;
	 p1error[p1errcnt].errorline = linenum;
	 p1error[p1errcnt].errortext = (char *)malloc (120);
	 sprintf (p1error[p1errcnt].errortext,
		  "MACRO defintion in MACRO");
	 p1errcnt++;
      }
      else
	 p0macro (bp, infd, outfd);
      break;

   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
	 {
	    errcount++;
	    p1error[p1errcnt].errorline = linenum;
	    p1error[p1errcnt].errortext = (char *)malloc (120);
	    sprintf (p1error[p1errcnt].errortext,
		     "Invalid opcode for OPSYN: %s",
		     token);
	    p1errcnt++;
	 }
      }
      break;

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

   case RETURN_T:		/* RETURN */
      {
	 char name[MAXSYMLEN+2];

	 genmode = GENINST;
	 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 */
      {
	 int oldtermparn;
	 int regs[8];
	 int modes[4];
	 char label[MAXSYMLEN+2];
	 char operand[MAXFIELDSIZE];

	 oldtermparn = termparn;
	 termparn = TRUE;
	 genmode = GENINST;
	 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)
	       {
		  errcount++;
		  p1error[p1errcnt].errorline = linenum;
		  p1error[p1errcnt].errortext = (char *)malloc (120);
		  sprintf (p1error[p1errcnt].errortext,
			      "Invalid register for %s: %d",
			      savenmode ? "SAVEN" : "SAVE", val);
		  p1errcnt++;
		  return;
	       }
	       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 
	       {
		  errcount++;
		  p1error[p1errcnt].errorline = linenum;
		  p1error[p1errcnt].errortext = (char *)malloc (120);
		  sprintf (p1error[p1errcnt].errortext,
			      "Invalid mode for %s: %s",
			      savenmode ? "SAVEN" : "SAVE", token);
		  p1errcnt++;
		  return;
	       }
	    }
	 } while (term == ',');

	 /*
	 ** Expand the SAVE[N} 
	 */

	 /*
	 ** If symbol, generate ENTRY
	 */

	 if (cursym[0])
	 {
	    if (!savenmode) /* 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 
	 {
	    errcount++;
	    p1error[p1errcnt].errorline = linenum;
	    p1error[p1errcnt].errortext = (char *)malloc (120);
	    sprintf (p1error[p1errcnt].errortext, "Label required for %s",
			      savenmode ? "SAVEN" : "SAVE");
	    p1errcnt++;
	    return;
	 }

	 /*
	 ** 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;

   default: ;
   }
}

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

static void
p0expand (MacDef *mac, 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 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;
   termparn = TRUE;

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

   /*
   ** Scan off MACRO arguments
   */

   argcnt = 0;
   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 (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), pocp = %s\n", *bp, *bp, ocp);
#endif
	 if (*bp == ')')
	 {
	    *bp++ = '\0';
	    strcat (lclargs[argcnt], ocp);
	 }
	 else
	 {
	    errcount++;
	    p1error[p1errcnt].errorline = linenum;
	    p1error[p1errcnt].errortext = (char *)malloc (120);
	    sprintf (p1error[p1errcnt].errortext,
		     "Missing ')' in macro");
	    p1errcnt++;
	 }
	 term = *bp;
	 if (term == ',') bp++;
      }
      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 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
      */

      op = oplookup (genopcode);

      /*
      ** 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);
		  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, 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)
		     {
			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;
		     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, 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
      {
	 asmskip--;
      }
   }

   asmskip = 0;
   gotoskip = FALSE;
}

/***********************************************************************
* 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;
   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 (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 $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, "MONSYM"))
	    {
	       monsym = TRUE;
	       definemonsyms();
	    }
	    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;
}

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

int
asmpass0 (FILE *tmpfd0, FILE *tmpfd1)
{
   MacDef *mac;
   char *token;
   int i;
   int eofflg;
   int done;
   int genmode;
   int status = 0;
   int tokentype;
   int val;
   char term;

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

   /*
   ** Clear out macro table.
   */

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

   /*
   ** Rewind the input.
   */

   if (fseek (tmpfd0, 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;
   done = FALSE;
   eofflg = FALSE;

   while (!done)
   {
      char *bp;

      srcbuf[0] = '\0';
      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;
	 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 label present, add to symbol table.
	 ** On MAP/FAP the symbol can start in any column up to 6.
	 */

	 if (strncmp (bp, "      ", 6))
	 {
	    while (isspace (*bp)) bp++;
	    if (isalnum(*bp) || *bp == '.' || *bp == '(')
	    {
	       bp = tokscan (bp, &token, &tokentype, &val, &term);
	       if (strlen(token) > MAXSYMLEN)
		  token[MAXSYMLEN] = '\0';
	       strcpy (cursym, token);
	    }
	 }
	 else 
	 {
	    cursym[0] = '\0';
	    while (isspace (*bp)) bp++;
	 }

	 /*
	 ** Scan off opcode.
	 */

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

	 /*
	 ** Check etcbuf for ETC
	 */

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

	 /*
	 ** Check opcodes
	 */

	 op = oplookup (token);

	 /*
	 ** If pseudo op, process
	 */

	 if (op && op->optype == TYPE_P)
	 {
	    fwrite (&genmode, 1, 4, tmpfd1);
	    fputs (srcbuf, tmpfd1);
	    p0pop (op, bp, tmpfd0, tmpfd1, FALSE);
	 }

	 /*
	 ** Else, Check macro table
	 */

	 else if ((mac = maclookup (token)) != NULL)
	 {
	    genmode |= MACCALL;
	    fwrite (&genmode, 1, 4, tmpfd1);
	    fputs (srcbuf, tmpfd1);
	    p0expand (mac, bp, tmpfd0, tmpfd1);
	 }

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

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

   }

   return (status);
}
