/***********************************************************************
*
* asmpass1 - Pass 1 for the IBM 7090 assembler.
*
* Changes:
*   05/21/03   DGP   Original.
*   08/20/03   DGP   Changed to call the SLR(1) parser.
*	
***********************************************************************/

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

#include "asmdef.h"

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

extern char ttlbuf[TTLSIZE+2];

static char cursym[32];

/***********************************************************************
* p1allop - Operation processors (all we do here is advance the pc).
***********************************************************************/

static void
p1allop (OpCode *op, char *bp)
{
   pc++;
}

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

static void
p1pop (OpCode *op, char *bp)
{
   SymNode *s;
   char *token;
   int tokentype;
   int relocatable;
   int val;
   char term;

   switch (op->opvalue)
   {

   case BCD_T:
      while (isspace (*bp)) bp++;
      if (isdigit (*bp))
      {
         val = *bp++ - '0';
	 if (val == 1 && *bp == '0')
	 {
	    val = 10;
	    bp++;
	 }
	 pc += val;
      }
      break;

   case BCI_T:
      bp = tokscan (bp, &token, &tokentype, &val, &term);
      pc += val;
      break;

   case BES_T:
      bp = exprscan (bp, &val, &term, &relocatable, 1, FALSE, 0);
      pc += val;
      if (cursym[0])
      {
	 s = symlookup (cursym, FALSE, TRUE);
	 s->value = pc;
	 s->relocatable = relocatable;
      }
      break;

   case BSS_T:
      bp = exprscan (bp, &val, &term, &relocatable, 1, FALSE, 0);
      pc += val;
      break;

   case DEC_T:
   case OCT_T:
      addrexpr = FALSE;
      do {
	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 if (tokentype == '-' || tokentype == '+')
	 {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	 }
	 pc ++;
      } while (term == ',');
      addrexpr = TRUE;
      break;

   case END_T:
      pgmlength = pc;
      break;

   case ENT_T:
      break;

   case EJE_T:
      break;

   case EQU_T:
      bp = exprscan (bp, &val, &term, &relocatable, 1, FALSE, 0);
      if (cursym[0])
      {
	 s = symlookup (cursym, FALSE, TRUE);
	 s->value = val;
	 s->relocatable = relocatable;
      }
      break;

   case EXT_T:
      do {
	 bp = tokscan (bp, &token, &tokentype, &val, &term);
	 if (tokentype != SYM)
	 {
	    errcount++;
	    p1error[p1errcnt].errorline = linenum;
	    p1error[p1errcnt].errortext = (char *)malloc (120);
	    sprintf (p1error[p1errcnt].errortext, "EXTRN requires symbol: %s",
		     token);
	    p1errcnt++;
	    return;
	 }
	 if (strlen(token) > MAXSYMLEN)
	 {
	    errcount++;
	    p1error[p1errcnt].errorline = linenum;
	    p1error[p1errcnt].errortext = (char *)malloc (120);
	    sprintf (p1error[p1errcnt].errortext, "Symbol too long: %s",
		     token);
	    p1errcnt++;
	    return;
	 }
	 if ((s = symlookup (token, FALSE, FALSE)) == NULL)
	 {
	    s = symlookup (token, TRUE, FALSE);
	 }
	 s->value = 0;
	 s->relocatable = TRUE;
	 s->external = TRUE;
      } while (term == ',');
      break;

   case ORG_T:
      radix = 8;
      bp = exprscan (bp, &val, &term, &relocatable, 1, FALSE, 0);
      radix = 10;
      absolute = TRUE;
      pc = val;
      break;

   case REM_T:
      break;

   case SPC_T:
      break;

   case TTL_T:
      if (!ttlbuf[0])
      {
	 char *cp;

	 while (isspace (*bp)) bp++;
	 cp = bp;
	 while (*bp != '\n') bp++;
	 *bp = '\0';
	 strcpy (ttlbuf, cp);
      }
      break;

   default: ;
   }
}

/***********************************************************************
* asmpass1 - Pass 1
***********************************************************************/

int
asmpass1 (FILE *tmpfd)
{
   char *token;
   int status = 0;
   int tokentype;
   int val;
   char term;

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

   /*
   ** Rewind the input.
   */

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

   /*
   ** Process the source.
   */

   pc = 0;
   linenum = 0;
   ttlbuf[0] = '\0';

   while (fgets(inbuf, MAXLINE, tmpfd))
   {
      char *bp;
      char *cp;

#ifdef DEBUG
      printf ("in = %s", inbuf);
#endif
      linenum++;
      bp = inbuf;
      addrexpr = TRUE;

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

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

	 /*
	 ** If label present, add to symbol table.
	 */

         if (isalnum(*bp))
	 {
	    bp = tokscan (bp, &token, &tokentype, &val, &term);
	    strcpy (cursym, token);
	    if (strlen(token) > MAXSYMLEN)
	    {
	       errcount++;
	       p1error[p1errcnt].errorline = linenum;
	       p1error[p1errcnt].errortext = (char *)malloc (120);
	       sprintf (p1error[p1errcnt].errortext, "Symbol too long: %s",
		        token);
	       p1errcnt++;
	       status = -1;
	    }
	    else if ((s = symlookup (token, TRUE, FALSE)) == NULL)
	    {
	       errcount++;
	       p1error[p1errcnt].errorline = linenum;
	       p1error[p1errcnt].errortext = (char *)malloc (120);
	       sprintf (p1error[p1errcnt].errortext, "Duplicate symbol: %s",
		        token);
	       p1errcnt++;
	       status = -1;
	    }
	 }
	 else 
	 {
	    cursym[0] = '\0';
	    while (isspace (*bp)) bp++;
	 }

	 /*
	 ** Scan off opcode.
	 */

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

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

	       case TYPE_P:
	          p1pop (op, bp);
	          break;

	       default:
		  p1allop (op, bp);
	    }
	 }
	 else
	 {
	    /* print errors in pass2 */
	    pc++; 
	    status = -1;
	 }
	 
      }

   }

   return (status);
}
