/***********************************************************************
*
* asmpass2.c - Pass 2 for the IBM 7090 assembler.
*
* Changes:
*   05/21/03   DGP   Original.
*   08/13/03   DGP   Added XREF support.
*   08/20/03   DGP   Changed to call the SLR(1) parser.
*	
***********************************************************************/

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

#include "asmdef.h"
#include "asmbcd.h"

extern int pc;
extern int symbolcount;
extern int genxref;
extern int radix;
extern int xrefgened;
extern int errcount;
extern int linenum;
extern int errnum;
extern int addrexpr;
extern int absolute;
extern int p1errcnt;
extern int pgmlength;
extern char errline[10][120];
extern char inbuf[MAXLINE];
extern SymNode *symbols[MAXSYMBOLS];
extern ErrTable p1error[MAXERRORS];

char ttlbuf[TTLSIZE+2];

static int linecnt = MAXLINE;
static int curp1err = 0;
static int objrecnum = 0;
static int objcnt = 0;
static int pagenum = 0;
static int printed = FALSE;
static char datebuf[48];
static char pcbuf[6];
static char objbuf[16];
static char objrec[82];
static char opbuf[32];
static char cursym[32];
static char lstbuf[MAXLINE];


/***********************************************************************
* printheader - Print header on listing.
***********************************************************************/

static void
printheader (FILE *lstfd)
{
   if (linecnt > LINESPAGE)
   {
      linecnt = 0;
      if (pagenum) fputc ('\f', lstfd);
      fprintf (lstfd, H1FORMAT,
	       VERSION,
	       " ",
	       datebuf,
	       ++pagenum);
      fprintf (lstfd, H2FORMAT, ttlbuf);
   }
}

/***********************************************************************
* printline - Print line on listing.
*
*0        1         2         3         4
*1234567890123456789012345678901234567890
*
* ooooo  SOOOO FF T AAAAA   LLLL  TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
* ooooo  SO DDDDD T AAAAA   LLLL  TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
*
***********************************************************************/

static void
printline (FILE *lstfd)
{
   printheader (lstfd);
   fprintf (lstfd, L1FORMAT, pcbuf, opbuf,
	    linenum, lstbuf);
   linecnt++;
}

static void
printdata (FILE *lstfd, int opc)
{
   printheader (lstfd);
   sprintf (pcbuf, PCFORMAT, opc);
   fprintf (lstfd, L2FORMAT, pcbuf, opbuf);
   linecnt++;
}

/***********************************************************************
* printsymbols - Print the symbol table.
***********************************************************************/

static void
printsymbols (FILE *lstfd)
{
   int i, j;

   linecnt = MAXLINE;
   j = 0;

   for (i = 0; i < symbolcount; i++)
   {
      SymNode *sym;

      printheader (lstfd);

      if (genxref && !linecnt)
      {
	 fprintf (lstfd, " SYMBOL    ADDR    DEF            REFERENCES\n\n");
	 linecnt = 2;
      }

      sym = symbols[i];
      if (sym->symbol[0] != LITERALSYM)
      {
	 char type;

	 if (sym->global) type = 'G';
	 else if (sym->external) type = 'E';
	 else if (sym->relocatable) type = 'R';
	 else type = ' ';

	 fprintf (lstfd, SYMFORMAT,
		  sym->symbol,
		  sym->value,
		  type);
	 j++;
	 if (genxref)
	 {
	    XrefNode *xref = sym->xref_head;

	    j = 0;
	    fprintf (lstfd, " %4d ", symbols[i]->line);
	    while (xref)
	    {
	       if (j >= 9)
	       {
		  fprintf (lstfd, "\n");
		  printheader (lstfd);
	          if (!linecnt)
		  {
		     fprintf (lstfd,
			   " SYMBOL    ADDR    DEF            REFERENCES\n\n");
		     linecnt = 2;
		  }
		  fprintf (lstfd, "                       ");
		  linecnt++;
		  j = 0;
	       }
	       fprintf (lstfd, " %4d ", xref->line);
	       xref = xref->next;
	       j++;
	    }
	    j = 6;
	 }

	 if (j >= 4)
	 {
	    fprintf (lstfd, "\n");
	    linecnt++;
	    j = 0;
	 }
      }
   }
   fprintf (lstfd, "\n");
}

/***********************************************************************
* punchfinish - Punch a record with sequence numbers.
***********************************************************************/

static void
punchfinish (FILE *outfd)
{
   if (objcnt)
   {
      sprintf (&objrec[SEQUENCENUM], SEQFORMAT, ++objrecnum);
      fputs (objrec, outfd);
      memset (objrec, ' ', sizeof(objrec));
      objcnt = 0;
   }
}

/***********************************************************************
* punchrecord - Punch an object value into record.
***********************************************************************/

static void 
punchrecord (FILE *outfd)
{
   if (objcnt+WORDTAGLEN >= CHARSPERREC)
   {
      punchfinish (outfd);
   }
   strncpy (&objrec[objcnt], objbuf, WORDTAGLEN);
   objbuf[0] = '\0';
   objcnt += WORDTAGLEN;
}

/***********************************************************************
* punchsymbols - Punch EXTRN and ENTRY symbols.
***********************************************************************/

static void
punchsymbols (FILE *outfd)
{
   int i;

   for (i = 0; i < symbolcount; i++)
   {
      if (symbols[i]->external)
      {
	 sprintf (objbuf, EXTRNFORMAT,
	       EXTRN_TAG, symbols[i]->symbol, symbols[i]->value);
         
         punchrecord (outfd);
      }
      else if (symbols[i]->global)
      {
	 sprintf (objbuf, GLOBALFORMAT,
	       GLOBAL_TAG, symbols[i]->symbol, symbols[i]->value);
         punchrecord (outfd);
      }
   }
}

/***********************************************************************
* puncheof - Punch EOF mark.
***********************************************************************/

static void
puncheof (FILE *outfd)
{
   punchfinish (outfd);
}

/***********************************************************************
* processliterals - Process literals.
***********************************************************************/

static void
processliterals (FILE *outfd, FILE *lstfd, int listmode)
{
   char *cp;
   char *token;
   int i, j;
   int literalcount = 0;
   int escapecount = 0;
   int val;
   int tokentype;
   char term;

   for (i = 0; i < symbolcount; i++)
   {
      if (symbols[i]->symbol[0] == LITERALSYM) literalcount++;
   }
   escapecount = literalcount * 2; /* just in case */

   while (literalcount)
   {
      if (--escapecount == 0) break;
      for (i = 0; i < symbolcount; i++)
      {
	 if (symbols[i]->symbol[0] == '=' && symbols[i]->value == pc)
	 {
	    union {
	       uint32 l[2];
	       t_uint64 ll;
	    } d;
	    char sign;

	    sign = '+';
	    cp = &symbols[i]->symbol[1];

	    switch (*cp)
	    {

	    case 'H': /* Hollerith */
	       cp++;
	       opbuf[0] = ' ';
	       for (j = 0; j < 6; j++)
	       {
		  sprintf (&opbuf[j*2+1], CHAR1FORMAT, tobcd[*cp]);
		  objbuf[0] = DATA_TAG;
		  sprintf (&objbuf[j*2+1], CHAR1FORMAT, tobcd[*cp]);
		  if (*cp != '\0') cp++;
	       }
	       strcat (opbuf, "   ");
	       break;

	    case 'O': /* Octal */
	       cp++;
	       d.ll = strtoll (cp, NULL, 8);
	       goto PUTINOBJ;

	    default:  /* Must be Decimal */
	       addrexpr = FALSE;
	       cp = tokscan (cp, &token, &tokentype, &val, &term);
	       sign = '+';
	       if (tokentype == '-' || tokentype == '+')
	       {
		  sign = term;
		  cp = tokscan (cp, &token, &tokentype, &val, &term);
	       }

	       /*
	       ** If decimal number, convert
	       */

	       if (tokentype == DECNUM)
	       {
		  d.ll = strtoll (token, NULL, 10);
	       }

	       /*
	       ** Floating point
	       */

	       else if (tokentype == FLTNUM)
	       {
		  d.ll = strtoll (token, NULL, 8);
	       }
	       addrexpr = TRUE;

PUTINOBJ:
	       if (d.ll < 0)
	       {
	          d.ll = -d.ll;
		  sign = '-';
	       }
	       d.l[MSL] = d.l[MSL] << 2 | d.l[LSL] >> 30;
	       d.l[LSL] &= 07777777777;
	       if (d.l[MSL] & 040)
	       {
		  d.l[MSL] &= 037;
		  sign = '-';
	       }
	       sprintf (opbuf, OP1FORMAT, sign, d.l[MSL], d.l[LSL]);
	       sprintf (objbuf, OCT1FORMAT,
			DATA_TAG,
			sign == '-' ? d.l[MSL] | 040 : d.l[MSL],
			d.l[LSL]);
	    }

	    if (listmode)
	    {
	       sprintf (pcbuf, PCFORMAT, pc);
	       printheader (lstfd);
	       fprintf (lstfd, LITFORMAT,
			pcbuf, opbuf, symbols[i]->symbol);
	       linecnt++;
	    }
	    punchrecord (outfd);

	    pc++;
	    literalcount--;
	    break;
	 }
      }
   }
}

/***********************************************************************
* p2aop - Process A type operation code.
***********************************************************************/

static void
p2aop (OpCode *op, int flag, char *bp)
{
   int decr = 0;
   int tag = 0;
   int addr = 0;
   int relocatable;
   int junk;
   char term;

   sprintf (pcbuf, PCFORMAT, pc);
   bp = exprscan (bp, &addr, &term, &relocatable, 1, FALSE, 0);
   if (term == ',')
   {
      bp = exprscan (bp, &tag, &term, &junk, 1, FALSE, 0);
      if (tag < 0 || tag > 7)
      {
	 errcount++;
         sprintf (errline[errnum++], "Invalid tag: %d", tag);
      }
      if (term == ',')
      {
	 bp = exprscan (bp, &decr, &term, &junk, 1, FALSE, 0);
      }
   }

   sprintf (opbuf, OPAFORMAT,
      (op->opvalue & 04000) ? '-' : ' ', (op->opvalue & 03777) >> 9,
      decr & 077777, tag & 07, addr & 077777);
   sprintf (objbuf, OBJAFORMAT,
      relocatable ? RELINST_TAG : ABSINST_TAG,
      op->opvalue >> 9, decr & 077777, tag & 07, addr & 077777);
   pc++;
}

/***********************************************************************
* p2bop - Process B type operation code.
***********************************************************************/

static void
p2bop (OpCode *op, int flag, char *bp)
{
   int tag = 0;
   int addr = 0;
   int relocatable;
   int junk;
   char term;

   sprintf (pcbuf, PCFORMAT, pc);

   bp = exprscan (bp, &addr, &term, &relocatable, 1, FALSE, 0);
   if (term == ',')
   {
      bp = exprscan (bp, &tag, &term, &junk, 1, FALSE, 0);
      if (tag < 0 || tag > 7)
      {
	 errcount++;
         sprintf (errline[errnum++], "Invalid tag: %d", tag);
      }
      if (term == ',')
      {
	 int mod;
	 bp = exprscan (bp, &mod, &term, &junk, 1, FALSE, 0);
	 flag |= mod;
      }
   }

   sprintf (opbuf, OPFORMAT,
      (op->opvalue & 04000) ? '-' : ' ', op->opvalue & 03777,
      flag & 077, tag & 07, addr & 077777);
   sprintf (objbuf, OBJFORMAT,
      relocatable ? RELINST_TAG : ABSINST_TAG,
      op->opvalue, flag & 077, tag & 07, addr & 077777);
   pc++;
}

/***********************************************************************
* p2cop - Process C type operation code.
***********************************************************************/

static void
p2cop (OpCode *op, int flag, char *bp)
{
   int count = 0;
   int tag = 0;
   int addr = 0;
   int relocatable;
   int junk;
   char term;

   sprintf (pcbuf, PCFORMAT, pc);
   bp = exprscan (bp, &addr, &term, &relocatable, 1, FALSE, 0);
   if (term == ',')
   {
      bp = exprscan (bp, &count, &term, &junk, 1, FALSE, 0);
      if (count > 255)
      {
	 errcount++;
         sprintf (errline[errnum++], "Invalid count: %d", count);
      }
   }

   sprintf (opbuf, OPFORMAT,
      (op->opvalue & 04000) ? '-' : ' ',
      op->opvalue & 03777 | ((count & 0300) >> 6),
      count & 077, tag & 07, addr & 077777);
   sprintf (objbuf, OBJFORMAT,
      relocatable ? RELINST_TAG : ABSINST_TAG,
      op->opvalue & 03777 | ((count & 0300) >> 6),
      count & 077, tag & 07, addr & 077777);
   pc++;
}

/***********************************************************************
* p2dop - Process D type operation code.
***********************************************************************/

static void
p2dop (OpCode *op, int flag, char *bp)
{
   char *token;
   int addr = 0;
   int tokentype;
   char term;

   sprintf (pcbuf, PCFORMAT, pc);
   radix = 8;
   bp = tokscan (bp, &token, &tokentype, &addr, &term);
   radix = 10;
   if (tokentype != OCTNUM)
   {
      errcount++;
      sprintf (errline[errnum++], "Invalid mask: %s", token);
   }
   sprintf (opbuf, OPDFORMAT,
      (op->opvalue & 04000) ? '-' : ' ',
      op->opvalue & 03777,
      flag & 077, addr & 0777777);
   sprintf (objbuf, OBJDFORMAT,
      ABSINST_TAG,
      op->opvalue, flag & 077, addr & 0777777);
   pc++;
}

/***********************************************************************
* p2eop - Process E type operation code. 
***********************************************************************/

static void
p2eop (OpCode *op, int flag, char *bp)
{
   char *token;
   int mod = 0;
   int relocatable;
   char term;
   int tag = 0;

   sprintf (pcbuf, PCFORMAT, pc);
   bp = exprscan (bp, &mod, &term, &relocatable, 1, FALSE, 0);

   sprintf (opbuf, OPFORMAT,
      (op->opvalue & 04000) ? '-' : ' ', op->opvalue & 03777,
      0, tag & 07, op->opmod | mod);
   sprintf (objbuf, OBJFORMAT,
      ABSINST_TAG,
      op->opvalue, 0, tag & 07, op->opmod | mod);
   pc++;
}

/***********************************************************************
* p2pop - Process Pseudo operation code.
***********************************************************************/

static int
p2pop (OpCode *op, char *bp, FILE *lstfd, FILE *outfd)
{
   char *cp;
   char *token;
   int i, j;
   int spc;
   int val;
   int relocatable;
   int tmpnum0;
   int tmpnum1;
   int tokentype;
   union {
      uint32 l[2];
      t_uint64 ll;
   } d;
   char sign;
   char term;

   sprintf (pcbuf, PCFORMAT, pc);
   strcpy (opbuf, OPBLANKS);

   switch (op->opvalue)
   {

   case BCD_T:
      cp = bp;
      while (isspace (*bp)) bp++;
      if (isdigit (*bp))
      {
         tmpnum0 = *bp++ - '0';
	 if (tmpnum0 == 1 && *bp == '0')
	 {
	    tmpnum0 = 10;
	    bp++;
	 }
	 cp = bp;
         goto PACKCHARS;
      }
      errcount++;
      sprintf (errline[errnum++], "Invalid BCD size: %s", cp);
      break;

   case BCI_T:
      bp = exprscan (bp, &val, &term, &relocatable, 1, FALSE, 0);
      tmpnum0 = val;
      if (tmpnum0 < 0 || tmpnum0 > 10)
      {
	 errcount++;
         sprintf (errline[errnum++], "Invalid BCI size: %d", val);
	 break;
      }
PACKCHARS:
      if (tmpnum0 == 1)
      {
         int j;
	 opbuf[0] = ' ';
	 for (j = 0; j < 6; j++)
	 {
	    sprintf (&opbuf[j*2+1], CHAR1FORMAT, tobcd[*bp]);
	    objbuf[0] = DATA_TAG;
	    sprintf (&objbuf[j*2+1], CHAR1FORMAT, tobcd[*bp]);
	    if (*bp != '\n') bp++;
	 }
	 strcat (opbuf, "   ");
      }
      else
      {
	 printed = TRUE;
	 for (i = 0; i < tmpnum0; i++)
	 {
	    int j;
	    opbuf[0] = ' ';
	    for (j = 0; j < 6; j++)
	    {
	       sprintf (&opbuf[j*2+1], CHAR1FORMAT, tobcd[*bp]);
	       objbuf[0] = DATA_TAG;
	       sprintf (&objbuf[j*2+1], CHAR1FORMAT, tobcd[*bp]);
	       if (*bp != '\n') bp++;
	    }
	    strcat (opbuf, "   ");
	    if (i == 0)
	    {
	       printline (lstfd);
	    }
	    else
	    {
	       printdata (lstfd, pc+i);
	    }
	    punchrecord (outfd);
	 }
      }
      pc += tmpnum0;
      break;

   case BES_T:
   case BSS_T:
      bp = exprscan (bp, &val, &term, &relocatable, 1, FALSE, 0);
      if (val < 0 || val > 32767)
      {
	 errcount++;
         sprintf (errline[errnum++], "Invalid BSS size: %d", val);
	 break;
      }
      pc += val;
      sprintf (objbuf, WORDFORMAT, BSS_TAG, val);
      break;

   case DEC_T:
      j = 0;
      spc = 0;
      addrexpr = FALSE;
      do {
	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 spc++;
	 sign = '+';
	 if (tokentype == '-' || tokentype == '+')
	 {
	    sign = term;
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	 }

	 /*
	 ** If decimal number, convert
	 */

	 if (tokentype == DECNUM)
	 {
	    d.ll = strtoll (token, NULL, 10);
	    d.l[MSL] = d.l[MSL] << 2 | d.l[LSL] >> 30;
	    d.l[LSL] &= 07777777777;
	 }

	 /*
	 ** Floating point
	 */

	 else if (tokentype == FLTNUM)
	 {
	    d.ll = strtoll (token, NULL, 8);
	    d.l[MSL] = d.l[MSL] << 2 | d.l[LSL] >> 30;
	    d.l[LSL] &= 07777777777;
	 }

	 /*
	 ** Binary point
	 */

	 else
	 {
	    /*
	    ** Check if Binary point
	    */

	    if (strchr (token, 'B'))
	    {
#ifdef BINARYPOINT /* Not totally working, yet */
	       cp = token;
	       d.ll = 0;
	       while (isdigit(*cp))
	       {
		  d.ll = (d.ll * 10) + (*cp - '0');
		  cp ++;
	       }
	       if (*cp == 'B')
	       {
		  int shift;
		  cp++;
		  shift = atoi (cp);
		  d.ll <<= 36 - shift;
		  d.l[MSL] = d.l[MSL] << 2 | d.l[LSL] >> 30;
		  d.l[LSL] &= 07777777777;
		  if (d.l[MSL] & 037777777740)
		  {
		     errcount++;
		     sprintf (errline[errnum++], "Binary point overflow: %s", token);
		     break;
		  }
	       }
	       else
	       {
		  errcount++;
		  sprintf (errline[errnum++], "Invalid Binary point DEC: %s", token);
		  break;
	       }
#else
	       errcount++;
	       sprintf (errline[errnum++], "Binary point not supported: %s", token);
	       break;
#endif
	    }
         }

	 sprintf (opbuf, OP1FORMAT, sign, d.l[MSL], d.l[LSL]);
	 sprintf (objbuf, OCT1FORMAT,
		  DATA_TAG,
		  sign == '-' ? d.l[MSL] | 040 : d.l[MSL],
		  d.l[LSL]);
	 printed = TRUE;
	 if (j == 0)
	 {
	    printline (lstfd);
	 }
	 else
	 {
	    printdata (lstfd, pc+j);
	 }
	 punchrecord (outfd);
	 j++;
      } while (term == ',');
      addrexpr = TRUE;
      pc += spc;
      break;

   case END_T:
      strcpy (pcbuf, PCBLANKS);
      bp = tokscan (bp, &token, &tokentype, &val, &term);
      if (tokentype == SYM)
      {
         SymNode *s;

	 if (strlen (token) > MAXSYMLEN)
	 {
	    errcount++;
	    sprintf (errline[errnum++], "Symbol too long: %s", token);
	 }
	 else if ((s = symlookup (token, FALSE, FALSE)) == NULL)
	 {
	    errcount++;
	    sprintf (errline[errnum++], "Undefined symbol: %s", token);
	 }
	 else
	 {
	    sprintf (opbuf, ADDRFORMAT, s->value);
	    sprintf (objbuf, WORDFORMAT,
		  (!absolute && s->relocatable) ? RELENTRY_TAG : ABSENTRY_TAG,
		  s->value);
	 }
      }
      return (1);
      break;

   case ENT_T:
      strcpy (pcbuf, PCBLANKS);
      do {
	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 if (tokentype != SYM)
	 {
	    errcount++;
	    sprintf (errline[errnum++], "ENTRY requires symbol: %s", token);
	 }
	 else if (strlen (token) > MAXSYMLEN)
	 {
	    errcount++;
	    sprintf (errline[errnum++], "Symbol too long: %s", token);
	 }
	 else
	 {
	    SymNode *s;

	    if ((s = symlookup (token, FALSE, FALSE)) == NULL)
	    {
	       errcount++;
	       sprintf (errline[errnum++], "ENTRY undefined: %s", token);
	    }
	    else
	    {
	       s->global = TRUE;
	    }
	 }
      } while (term == ',');
      break;

   case EJE_T:
      strcpy (pcbuf, PCBLANKS);
      linecnt = MAXLINE;
      break;

   case EQU_T:
      strcpy (pcbuf, PCBLANKS);
      if (cursym[0] == '\0')
      {
         errcount++;
	 strcpy (errline[errnum++], "EQU requires a label");
      }
      else
      {
	 SymNode *s;

	 s = symlookup (cursym, FALSE, TRUE);
	 sprintf (opbuf, ADDRFORMAT, s->value);
      }
      break;

   case EXT_T:
      strcpy (pcbuf, PCBLANKS);
      break;

   case OCT_T:
      j = 0;
      spc = 0;
      radix = 8;
      addrexpr = FALSE;
      do {
	 cp = bp;
	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 spc++;
	 sign = '+';
	 if (tokentype == '-' || tokentype == '+')
	 {
	    sign = term;
	    cp = bp;
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	 }
	 if (strlen(token) > 12)
	 {
	    errcount++;
	    sprintf (errline[errnum++], "Invalid octal number: %s", bp);
	    break;
	 }
	 if ((i = strlen (token)) > 6)
	 {
	    sscanf (&token[i-6], "%lo", &tmpnum1);
	    token[i-6] = '\0';
	    sscanf (token, "%lo", &tmpnum0);
	 }
	 else 
	 {
	    tmpnum0 = 0;
	    sscanf (token, "%lo", &tmpnum1);
	 }
	 if (sign == '-') tmpnum0 |= 0400000;
	 sprintf (opbuf, OP2FORMAT,
		  tmpnum0 & 0400000 ? '-' : '+',
		  tmpnum0 & 0377777, tmpnum1);
	 sprintf (objbuf, OCT2FORMAT, DATA_TAG, tmpnum0, tmpnum1);
	 printed = TRUE;
	 if (j == 0)
	 {
	    printline (lstfd);
	 }
	 else
	 {
	    printdata (lstfd, pc+j);
	 }
	 punchrecord (outfd);
	 j++;
      } while (term == ',');
      pc += spc;
      addrexpr = TRUE;
      radix = 10;
      break;

   case ORG_T:
      radix = 8;
      bp = exprscan (bp, &val, &term, &relocatable, 1, FALSE, 0);
      radix = 10;
      if (val < 0 || val > 32767)
      {
	 errcount++;
         sprintf (errline[errnum++], "Invalid ORG value: %d", val);
	 break;
      }
      pc = val;
      sprintf (pcbuf, PCFORMAT, pc);
      sprintf (objbuf, WORDFORMAT, ORG_TAG, pc);
      break;

   case REM_T:
      strcpy (pcbuf, PCBLANKS);
      break;

   case SPC_T:
      strcpy (pcbuf, PCBLANKS);
      bp = exprscan (bp, &val, &term, &relocatable, 1, FALSE, 0);
      if (val < 0 || val > LINESPAGE)
      {
	 errcount++;
         sprintf (errline[errnum++], "Invalid SPACE count: %d", val);
	 break;
      }
      printline (lstfd);
      printed = TRUE;
      for (i = val; i > 0; i--)
      {
	 printheader (lstfd);
	 fputs ("\n", lstfd);
	 linecnt++;
      }
      break;

   case TTL_T:
      strcpy (pcbuf, PCBLANKS);
      while (isspace (*bp)) bp++;
      cp = bp;
      while (*bp != '\n') bp++;
      *bp = '\0';
      strcpy (ttlbuf, cp);
      break;

   default: ;
   }
   return (0);
}

/***********************************************************************
* asmpass2 - Pass 2 
***********************************************************************/

int
asmpass2 (FILE *tmpfd, FILE *outfd, int listmode, FILE *lstfd)
{
   char *bp, *cp;
   char *token;
   int status = 0;
   int done = 0;
   int flag;
   int val;
   int tokentype;
   time_t curtime;
   char term;

#ifdef DEBUG
   printf ("asmpass2: Entered\n");
#endif

   /*
   ** Get current date/time.
   */

   if (listmode)
   {
      curtime = time(NULL);
      strcpy (datebuf, ctime(&curtime));
      *strchr (datebuf, '\n') = '\0';
   }

   /*
   ** Rewind input file.
   */

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

   /*
   ** Process the source.
   */

   memset (objrec, ' ', sizeof(objrec));

   pc = 0;
   linenum = 0;
   while (!done && fgets (inbuf, MAXLINE, tmpfd))
   {
#ifdef DEBUG
      printf ("in = %s", inbuf);
#endif
      linenum++;
      addrexpr = TRUE;
      printed = FALSE;
      errnum = 0;
      errline[0][0] = '\0';
      objbuf[0] = '\0';
      strcpy (lstbuf, inbuf);
      bp = inbuf;

      if (*bp == COMMENTSYM)
      {
	 strcpy (pcbuf, PCBLANKS);
         strcpy (opbuf, OPBLANKS);
      }
      else
      {
	 OpCode *op;

	 /*
	 ** If label present, scan it off.
	 */

         if (isalnum(*bp))
	 {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	    strcpy (cursym, token);
	 }
	 else 
	 {
	    cursym[0] = '\0';
	    while (isspace (*bp)) bp++;
	 }

	 /*
	 ** Scan off opcode.
	 */

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

	 /*
	 ** Check for indirect addressing.
	 */

	 if (term == '*') flag = 060;
	 else flag = 0;

	 /*
	 ** Process according to type.
	 */

	 if ((op = oplookup (token)) != NULL)
	 {
	    switch (op->optype)
	    {

	       case TYPE_A:
		  p2aop (op, flag, bp);
	          break;

	       case TYPE_B:
		  p2bop (op, flag, bp);
	          break;

	       case TYPE_C:
		  p2cop (op, flag, bp);
	          break;

	       case TYPE_D:
		  p2dop (op, flag, bp);
	          break;

	       case TYPE_E:
		  p2eop (op, flag, bp);
	          break;

	       case TYPE_P:
	          done = p2pop (op, bp, lstfd, outfd);
	    }
	 }
	 else
	 {
	    pc++;
	    errcount++;
	    sprintf (errline[errnum++], "Invalid opcode: %s", token);
	 }
	 
      }

      /*
      ** Write out a print line.
      */

      if (listmode && !printed)
      {
         printline (lstfd);
	 printed = FALSE;
      }

      /*
      ** Write an object buffer.
      */

      if (objbuf[0])
      {
         punchrecord (outfd);
      }

      /*
      ** Process errors
      */

      if (errnum)
      {
	 int i;

	 for (i = 0; i < errnum; i++)
	 {
	    if (listmode)
	    {
	       fprintf (lstfd, "ERROR: %s\n", errline[i]);
	       linecnt++;
	    }
	    else
	    {
	       fprintf (stderr, "asm7090: %d: %s\n", linenum, errline[i]);
	    }
	    errline[i][0] = '\0';
	 }
	 status = -1;
      }
      if (p1errcnt && p1error[curp1err].errorline == linenum)
      {
	 if (listmode)
	 {
	    fprintf (lstfd, "ERROR: %s\n", p1error[curp1err].errortext);
	    linecnt++;
	 }
	 else
	 {
	    fprintf (stderr, "asm7090: %d: %s\n",
		     linenum, p1error[curp1err].errortext);
	 }
	 p1errcnt--;
	 curp1err++;
	 status = -1;
      }
   }

   if (!done)
   {
      errcount++;
      if (listmode)
      {
         fprintf (lstfd, "ERROR: No END record\n");
      }
      else
      {
	 fprintf (stderr, "asm7090: %d: No END record\n", linenum);
      }
      status = -1;
   }
   else
   {

      /*
      ** Process literals
      */

      processliterals (outfd, lstfd, listmode);

      /*
      ** Punch EXTRN and GLOAL entries
      */

      punchsymbols (outfd);
      puncheof (outfd);

      /*
      ** Print symbol table
      */

      if (listmode)
      {
         printsymbols (lstfd);
      }
   }

   return (status);
}
