/***********************************************************************
*
* asmsupt.c - Support routines 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.
*   12/20/04   DGP   Added Qualifiers and condexpr.
*   12/27/04   DGP   Added symlocate.
*   01/04/05   DGP   Added entsymlookup().
*   02/09/05   DGP   Unified error reporting using logerror.
*   03/16/05   DGP   Change operation of symparse.
*	
***********************************************************************/

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

#include "asmdef.h"
#include "asmdmem.h"
#include "errors.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 errnum;		/* Number of pass 2 errors for current line */
extern int exprtype;		/* Expression type */
extern int p1errcnt;		/* Number of pass 0/1 errors */
extern int p1erralloc;		/* Number of pass 0/1 errors allocated */
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 inpass;		/* Which pass are we in */
extern int qualindex;		/* QUALifier table index */
extern int begincount;		/* Number of BEGINs */
extern int litorigin;		/* Literal pool origin */
extern int litpool;		/* Literal pool size */
extern int entsymbolcount;	/* Number of ENTRY symbols */
extern int widemode;		/* Generate wide listing */
extern int rboolexpr;		/* RBOOL expression */
extern int lboolexpr;		/* LBOOL expression */
extern int fapmode;		/* FAP assembly mode */
extern int headcount;		/* Number of entries in headtable */

extern char inbuf[MAXLINE];	/* The input buffer for the scanners */
extern char qualtable[MAXQUALS][MAXSYMLEN+2]; /* The QUALifier table */
extern char errline[10][120];	/* Pass 2 error lines for current statment */
extern char headtable[MAXHEADS];/* HEAD table */

extern SymNode *addextsym;	/* Added symbol for externals */
extern SymNode *symbols[MAXSYMBOLS];/* The Symbol table */
extern SymNode *entsymbols[MAXSYMBOLS];/* The Entry Symbol table */
extern SymNode *freesymbols;	/* Reusable symbols nodes */
extern XrefNode *freexrefs;	/* Reusable xref nodes */
extern ErrTable p1error[MAXERRORS];/* The pass 0/1 error table */

static char errtmp[120];	/* Error print string */

/***********************************************************************
* logerror - Log an error for printing.
***********************************************************************/

void
logerror (char *errmsg)
{
#ifdef DEBUGERROR
   printf ("logerror: linenum = %d, errcount = %d, inpass = %o\n",
	   linenum, errcount, inpass);
   printf ("   p1errcnt = %d, p1erralloc = %d, errnum = %d\n",
	   p1errcnt, p1erralloc, errnum);
   printf ("   errmsg = %s\n", errmsg);
#endif
   if (!chkerror (linenum))
   {
      errcount++;
      if (inpass == 020)
      {
	 strcpy (errline[errnum++], errmsg);
      }
      else
      {
	 if (p1errcnt >= p1erralloc)
	 {
	    p1error[p1errcnt].errortext = (char *)DBG_MEMGET (120);
	    p1erralloc++;
	 }
	 p1error[p1errcnt].errorline = linenum;
	 strcpy (p1error[p1errcnt].errortext, errmsg);
	 p1errcnt++;
      }
   }
}

/***********************************************************************
* Parse_Error - Print parsing error
***********************************************************************/

void
Parse_Error (int cause, int state, int defer)
{
   char errorstring[256];

#ifdef DEBUGPARSEERROR
   printf (
   "Parse_Error: pass = %o, defer = %s, cause = %d, state = %d, linenum = %d\n",
	 inpass, defer ? "TRUE " : "FALSE", cause, state, linenum);
#endif
   if (defer) return;

   strcpy (errorstring, "Unknown error");
   if (cause == PARSE_ERROR)
   {
      switch (state)
      {
      /* Include generated parser errors */
#include "asm7090.err"
      default: ;
      }
   }
   else if (cause == SCAN_ERROR)
   {
      switch (state)
      {
      case INVOCTNUM:
	 strcpy (errorstring, "Invalid octal number");
	 break;
      case INVEXPONENT:
	 strcpy (errorstring, "Exponent out of range");
	 break;
      case INVSYMBOL:
	 strcpy (errorstring, "Invalid symbol");
	 break;
      default: ;
      }
   }
   else if (cause == INTERP_ERROR)
   {
      strcpy (errorstring, "Divide by zero");
   }

   sprintf (errtmp, "%s in expression", errorstring);
   logerror (errtmp);

} /* Parse_Error */

/***********************************************************************
* tokscan - Scan a token.
***********************************************************************/

char *
tokscan (char *buf, char **token, int *tokentype, int *tokenvalue, char *term)
{
   int index;
   toktyp tt;
   tokval val;
   static char t[80];
   static char q[80];
   char c;

#ifdef DEBUGTOK
   printf ("tokscan: Entered: buf = %s", buf);
#endif

   /*
   ** Skip leading blanks
   */

   while (*buf && isspace(*buf))
   {
      /*
      ** We stop scanning on a newline or when we're passed the operands.
      */

      if (*buf == '\n' || (buf - inbuf >= NOOPERAND))
      {
	 t[0] = '\0';
	 *token = t;
	 *term = '\n';
	 *tokentype = EOS;
         return (buf);
      }
      buf++;
   }

   /*
   ** Check for "strange" opcodes, convert to PZE
   */

   if ((buf-inbuf) >= OPCSTART && (buf-inbuf) < VARSTART)
   {
#ifdef DEBUGTOKNULLOP
      printf ("tokscan: buf = %s", buf);
#endif
      if (   !strncmp (buf, "...", 3)
          || !strncmp (buf, "***", 3))
      {
#ifdef DEBUGTOKNULLOP
	 printf ("  null opcode ... found\n");
#endif
	 strcpy (t, "PZE");
	 *tokentype = SYM;
	 *tokenvalue = 0;
	 *token = t;
	 index = 3;
	 *term = *(buf+index);
	 return (buf+index);
      }
   }

#if 0
   /*
   ** If nil operand, return type
   */

   if (!strncmp (buf, "**", 2))
   {
      strcpy (t, "**");
      index = 2;
      if (radix == 8)
	 *tokentype = OCTNUM;
      else
	 *tokentype = SYM;
      *tokenvalue = 0;
      *token = t;
      *term = *(buf+index);
      return (buf+index);
   }
#endif

   /*
   ** Call the scanner to get the token
   */

   index = 0;
#ifdef DEBUGTOK
   printf ("  calling scanner: buf = %s\n", buf);
#endif
   tt = Scanner (buf, &index, &val, t, q, &c, inpass == 020 ? FALSE : TRUE); 
#ifdef DEBUGTOK
   printf ("  token = %s, tokentype = %d, term = %02x, val = %d\n",
	    t, tt, c, val);
   printf (" index = %d, *(buf+index) = %02X\n",  index, *(buf+index));
#endif

   /*
   ** Return proper token and index
   */

   if (tt == DECNUM || tt == OCTNUM)
      c = *(buf+index);
   if (c == ',') index++;
   *token = t;
   *tokentype = tt;
   *tokenvalue = val;
   *term = c;
   return (buf+index);
}

/***********************************************************************
* freexref - Link an xref entry on free chain.
***********************************************************************/

void
freexref (XrefNode *xr)
{
   xr->next = freexrefs;
   freexrefs = xr;
}

/***********************************************************************
* freesym - Link a symbol entry on free chain.
***********************************************************************/

void
freesym (SymNode *sr)
{
   sr->next = freesymbols;
   freesymbols = sr;
}

/***********************************************************************
* symdelete - Delete a symbol from the symbol table.
***********************************************************************/

void
symdelete (SymNode *sym)
{
   int i;

   for (i = 0; i < symbolcount; i++)
   {
      if (symbols[i] == sym)
      {
	 XrefNode *xr, *nxr;

	 xr = symbols[i]->xref_head;
	 while (xr)
	 {
	    nxr = xr->next;
	    freexref (xr);
	    xr = nxr;
	 }
         freesym (symbols[i]);
	 for (; i < symbolcount; i++)
	 {
	    symbols[i] = symbols[i+1];
	 }
	 symbolcount --;
         return;
      }
   }
}

/***********************************************************************
* symlookup - Lookup a symbol in the symbol table.
***********************************************************************/

SymNode *
symlookup (char *sym, char *qual, int add, int xref)
{
   SymNode *ret = NULL;
   int done = FALSE;
   int mid;
   int last = 0;
   int lo;
   int up;
   int r;
   char tblsym[80];
   char lksym[80];

#ifdef DEBUGSYM
   printf ("symlookup: Entered: sym = '%s', qual = '%s'\n", sym, qual);
   printf ("   add = %s, xref = %s\n",
	    add ? "TRUE" : "FALSE",
	    xref ? "TRUE" : "FALSE");
#endif

   /*
   ** Empty symbol table.
   */

   if (symbolcount == 0)
   {
      if (!add) return (NULL);

#ifdef DEBUGSYM
      printf ("   add symbol at top\n");
#endif
      if (freesymbols)
      {
         symbols[0] = freesymbols;
	 freesymbols = symbols[0]->next;
      }
      else if ((symbols[0] = (SymNode *)DBG_MEMGET (sizeof (SymNode))) == NULL)
      {
         fprintf (stderr, "asm7090: Unable to allocate memory\n");
	 exit (ABORT);
      }
      memset (symbols[0], '\0', sizeof (SymNode));
      strcpy (symbols[0]->symbol, sym);
      strcpy (symbols[0]->qualifier, qual);
      symbols[0]->value = pc;
      symbols[0]->line = linenum;
#ifdef DEBUGXREF
      printf ("symlookup: sym = %s defline = %d\n", sym, linenum);
#endif
      if (absolute || absmod)
	 symbols[0]->relocatable = FALSE;
      else
	 symbols[0]->relocatable = TRUE;
      symbolcount++;
      return (symbols[0]);
   }

   /*
   ** Locate using binary search
   */

   lo = 0;
   up = symbolcount;
   last = -1;
   sprintf (lksym, "%s$%s", sym, qual);
   
   while (!done)
   {
      mid = (up - lo) / 2 + lo;
#ifdef DEBUGSYMSEARCH
      printf ("   mid = %d, last = %d\n", mid, last);
#endif
      if (symbolcount == 1)
	 done = TRUE;
      else if (last == mid) break;

      sprintf (tblsym, "%s$%s", symbols[mid]->symbol, symbols[mid]->qualifier);
#ifdef DEBUGSYMSEARCH
      printf ("   tblsym = '%s', lksym = '%s'\n", tblsym, lksym);
#endif
      r = strcmp (tblsym, lksym);

      /*
      ** We have a hit
      */

      if (r == 0)
      {
	 SymNode *symp = symbols[mid];

	 if (add)
	    return (NULL); /* must be a duplicate */

	 /*
	 ** If xref mode, chain a line reference
	 */

	 if (genxref && xref)
	 {
	    XrefNode *new;

	    if (freexrefs)
	    {
	       new = freexrefs;
	       freexrefs = new->next;
	    }
	    else if ((new = (XrefNode *)DBG_MEMGET (sizeof (XrefNode))) == NULL)
	    {
	       fprintf (stderr, "asm7090: Unable to allocate memory\n");
	       exit (ABORT);
	    }
#ifdef DEBUGXREF
	    printf ("symlookup: sym = %s refline = %d\n", sym, linenum);
#endif
	    memset (new, '\0', sizeof(XrefNode));
	    new->next = NULL;
	    new->line = linenum;
	    if (symp->xref_head == NULL)
	    {
	       symp->xref_head = new;
	    }
	    else
	    {
	       (symp->xref_tail)->next = new;
	    }
	    symp->xref_tail = new;
	 }
         return (symbols[mid]);
      }

      /*
      ** Otherwise, get next symbol
      */

      else if (r < 0)
      {
         lo = mid;
      }
      else 
      {
         up = mid;
      }
      last = mid;
   }

   /*
   ** Not found, check to add
   */

   if (add)
   {
      SymNode *new;

#ifdef DEBUGSYM
      printf ("   add new symbol\n");
#endif
      /*
      ** Add to table, allocate storage and initialize symbol
      */

      if (symbolcount+1 > MAXSYMBOLS)
      {
         fprintf (stderr, "asm7090: Symbol table exceeded\n");
	 exit (ABORT);
      }

      if (freesymbols)
      {
         new = freesymbols;
	 freesymbols = new->next;
      }
      else if ((new = (SymNode *)DBG_MEMGET (sizeof (SymNode))) == NULL)
      {
         fprintf (stderr, "asm7090: Unable to allocate memory\n");
	 exit (ABORT);
      }

      memset (new, '\0', sizeof (SymNode));
      strcpy (new->symbol, sym);
      strcpy (new->qualifier, qual);
#ifdef DEBUGXREF
      printf ("symlookup: sym = %s defline = %d\n", sym, linenum);
#endif
      new->value = pc;
      new->line = linenum;
      if (absolute || absmod)
	 new->relocatable = FALSE;
      else
	 new->relocatable = TRUE;

      /*
      ** Insert pointer in sort order.
      */

      for (lo = 0; lo < symbolcount; lo++)
      {
	 sprintf (tblsym, "%s$%s", symbols[lo]->symbol, symbols[lo]->qualifier);

         if (strcmp (tblsym, lksym) > 0)
	 {
	    for (up = symbolcount + 1; up > lo; up--)
	    {
	       symbols[up] = symbols[up-1];
	    }
	    symbols[lo] = new;
	    symbolcount++;
	    return (symbols[lo]);
	 }
      }
      symbols[symbolcount] = new;
      ret = symbols[symbolcount];
      symbolcount++;
   }
   return (ret);
}

/***********************************************************************
* entsymlookup - Lookup an extry symbol in the symbol table.
***********************************************************************/

SymNode *
entsymlookup (char *sym, char *qual, int add, int xref)
{
   SymNode *ret = NULL;
   int done = FALSE;
   int mid;
   int last = 0;
   int lo;
   int up;
   int r;
   char tblsym[80];
   char lksym[80];

#ifdef DEBUGSYM
   printf ("entsymlookup: Entered: sym = '%s', qual = '%s'\n", sym, qual);
   printf ("   add = %s, xref = %s\n",
	    add ? "TRUE" : "FALSE",
	    xref ? "TRUE" : "FALSE");
#endif

   /*
   ** Empty symbol table.
   */

   if (entsymbolcount == 0)
   {
      if (!add) return (NULL);

#ifdef DEBUGSYM
      printf ("add symbol at top\n");
#endif
      if (freesymbols)
      {
         entsymbols[0] = freesymbols;
	 freesymbols = entsymbols[0]->next;
      }
      else if ((entsymbols[0] =
		     (SymNode *)DBG_MEMGET (sizeof (SymNode))) == NULL)
      {
         fprintf (stderr, "asm7090: Unable to allocate memory\n");
	 exit (ABORT);
      }
      memset (entsymbols[0], '\0', sizeof (SymNode));
      strcpy (entsymbols[0]->symbol, sym);
      strcpy (entsymbols[0]->qualifier, qual);
      entsymbols[0]->value = pc;
      entsymbols[0]->line = linenum;
#ifdef DEBUGXREF
      printf ("entsymlookup: sym = %s defline = %d\n", sym, linenum);
#endif
      if (absolute || absmod)
	 entsymbols[0]->relocatable = FALSE;
      else
	 entsymbols[0]->relocatable = TRUE;
      entsymbolcount++;
      return (entsymbols[0]);
   }

   /*
   ** Locate using binary search
   */

   lo = 0;
   up = entsymbolcount;
   last = -1;
   sprintf (lksym, "%s$%s", sym, qual);
   
   while (!done)
   {
      mid = (up - lo) / 2 + lo;
#ifdef DEBUGSYMSEARCH
      printf (" mid = %d, last = %d\n", mid, last);
#endif
      if (entsymbolcount == 1)
	 done = TRUE;
      else if (last == mid) break;

      sprintf (tblsym, "%s$%s",
	       entsymbols[mid]->symbol, entsymbols[mid]->qualifier);
#ifdef DEBUGSYMSEARCH
      printf ("   tblsym = '%s', lksym = '%s'\n", tblsym, lksym);
#endif
      r = strcmp (tblsym, lksym);

      /* 
      ** We have a hit
      */

      if (r == 0)
      {
	 SymNode *symp = entsymbols[mid];

	 if (add)
	    return (NULL); /* must be a duplicate */

	 /*
	 ** If xref mode, chain a line reference
	 */

	 if (genxref && xref)
	 {
	    XrefNode *new;

	    if (freexrefs)
	    {
	       new = freexrefs;
	       freexrefs = new->next;
	    }
	    else if ((new = (XrefNode *)DBG_MEMGET (sizeof (XrefNode))) == NULL)
	    {
	       fprintf (stderr, "asm7090: Unable to allocate memory\n");
	       exit (ABORT);
	    }
#ifdef DEBUGXREF
	    printf ("entsymlookup: sym = %s refline = %d\n", sym, linenum);
#endif
	    memset (new, '\0', sizeof(XrefNode));
	    new->next = NULL;
	    new->line = linenum;
	    if (symp->xref_head == NULL)
	    {
	       symp->xref_head = new;
	    }
	    else
	    {
	       (symp->xref_tail)->next = new;
	    }
	    symp->xref_tail = new;
	 }
         return (entsymbols[mid]);
      }

      /*
      ** Otherwise, get next symbol
      */

      else if (r < 0)
      {
         lo = mid;
      }
      else 
      {
         up = mid;
      }
      last = mid;
   }

   /*
   ** Not found, check to add
   */

   if (add)
   {
      SymNode *new;

#ifdef DEBUGSYM
      printf ("add new symbol\n");
#endif
      /*
      ** Add to table, allocate storage and initialize symbol
      */

      if (entsymbolcount+1 > MAXSYMBOLS)
      {
         fprintf (stderr, "asm7090: Entry symbol table exceeded\n");
	 exit (ABORT);
      }

      if (freesymbols)
      {
         new = freesymbols;
	 freesymbols = new->next;
      }
      else if ((new = (SymNode *)DBG_MEMGET (sizeof (SymNode))) == NULL)
      {
         fprintf (stderr, "asm7090: Unable to allocate memory\n");
	 exit (ABORT);
      }

      memset (new, '\0', sizeof (SymNode));
      strcpy (new->symbol, sym);
      strcpy (new->qualifier, qual);
#ifdef DEBUGXREF
      printf ("entsymlookup: sym = %s defline = %d\n", sym, linenum);
#endif
      new->value = pc;
      new->line = linenum;
      if (absolute || absmod)
	 new->relocatable = FALSE;
      else
	 new->relocatable = TRUE;

      /*
      ** Insert pointer in sort order.
      */

      for (lo = 0; lo < entsymbolcount; lo++)
      {
	 sprintf (tblsym, "%s$%s",
		  entsymbols[lo]->symbol, entsymbols[lo]->qualifier);

         if (strcmp (tblsym, lksym) > 0)
	 {
	    for (up = entsymbolcount + 1; up > lo; up--)
	    {
	       entsymbols[up] = entsymbols[up-1];
	    }
	    entsymbols[lo] = new;
	    entsymbolcount++;
	    return (entsymbols[lo]);
	 }
      }
      entsymbols[entsymbolcount] = new;
      ret = entsymbols[entsymbolcount];
      entsymbolcount++;
   }
   return (ret);
}

/***********************************************************************
* symlocate - Locate first occurance of a symbol in the symbol table.
***********************************************************************/

SymNode *
symlocate (char *sym, int *count)
{
   int mid;
   int lo;
   int up;
   int r;

#ifdef DEBUGSYMLOC
   printf ("symlocate: Entered: sym = '%s'\n", sym);
#endif

   /*
   ** Empty symbol table.
   */

   *count = 0;
   if (symbolcount == 0)
      return (NULL);

   /*
   ** Locate using linear search as binary search will miss without quals.
   */

   lo = 0;
   up = symbolcount;
   
   for (mid = 0; mid < up; mid++)
   {
      r = strcmp (symbols[mid]->symbol, sym);
      if (r == 0)
      {
#ifdef DEBUGSYMLOC
	 printf ("   mid = %d, qual = %s\n", mid, symbols[mid]->qualifier);
#endif
	 /*
	 ** Check if other symbols with different qualifiers above and below.
	 */

	 lo = mid;
	 while (!strcmp (symbols[mid]->symbol, symbols[lo-1]->symbol) &&
	        strcmp (symbols[mid]->qualifier, symbols[lo-1]->qualifier))
	 {
#ifdef DEBUGSYMLOC
	    printf ("   lo = %d, qual = %s\n", lo-1, symbols[lo-1]->qualifier);
#endif
	    lo--;
	 }
	 up = mid;
	 while (!strcmp (symbols[mid]->symbol, symbols[up-1]->symbol) &&
	        strcmp (symbols[mid]->qualifier, symbols[up-1]->qualifier))
	 {
#ifdef DEBUGSYMLOC
	    printf ("   up = %d, qual = %s\n", up-1, symbols[up-1]->qualifier);
#endif
	    up++;
	 }

	 /*
	 ** Number of instances of the same symbols with different quals.
	 */

	 *count = up - lo + 1;
#ifdef DEBUGSYMLOC
	 printf ("   lo = %d, up = %d, count = %d\n", lo, up, *count);
#endif
         return (symbols[mid]);
      }
   }

   /*
   ** Not found
   */

   return (NULL);
}

/***********************************************************************
* symparse - Process symbol references from parser.
***********************************************************************/

tokval 
symparse (char *sym, char *qual, int *relo, int defer, int pcinc)
{
   SymNode *s;
   tokval value;
   int relocatable;
   int qndx;
   int xref;
   int count;
   char temp2[MAXSYMLEN+2];

   s = NULL;
   addextsym = NULL;
   relocatable = *relo;

   xref = (((inpass & 070) == 010) && defer == FALSE) ? FALSE : TRUE;

#ifdef DEBUGSYMPARSE
   printf ("symparse: Entered: sym = '%s', qual = '%s'\n", sym, qual);
   printf ("   defer = %s, xref = %s\n",
	    defer ? "TRUE" : "FALSE",
	    xref ? "TRUE" : "FALSE");
#endif

   /*
   ** With FAP check symbol with head.
   */

   if (fapmode)
   {
      if (qual[0])
      {
	 if (qual[0] == '0')
	    s = symlookup (sym, "", FALSE, xref);
	 else
	    s = symlookup (sym, qual, FALSE, xref);
      }
      else if (strlen(sym) == MAXSYMLEN)
      {
	 temp2[0] = sym[0];
	 temp2[1] = '\0';
	 s = symlookup (&sym[1], temp2, FALSE, xref);
      }
      else if (headcount)
      {
	 sprintf (temp2, "%c", headtable[0]);
	 s = symlookup (sym, temp2, FALSE, xref);
      }
      if (!s)
	 s = symlookup (sym, "", FALSE, xref);
   }

   /*
   ** With MAP check symbol with qualifers
   */

   else
   {
      s = symlookup (sym, qual, FALSE, xref);
      if (!s) 
      {

	 /*
	 ** Not found, check if in QUAL scope
	 */

	 if (qualindex)
	 {
	    for (qndx = qualindex; qndx >= 0; qndx--)
	    {
	       strcpy (temp2, qualtable[qndx]);
	       s = symlookup (sym, temp2, FALSE, xref);
	       if (s) break;
	    }
	 }

	 /*
	 ** If not found, check if Monitor Symbol
	 */

	 if (!s)
	 {
	    if (monsym || jobsym)
	    {
	       s = symlookup (sym, "S.S", FALSE, xref);
	    }

	 }

	 /*
	 ** If not found, check if symbol exists without a qual
	 */

	 if (!s)
	 {
	    if (inpass > 010 && (s = symlocate (sym, &count)))
	    {
	       /* 
	       ** If only one occurance, we found it
	       */
	       if (count != 1) s = NULL;
	    }
	 }
      }
   }


   /*
   ** Not found
   */

   if (!s)
   {
      if (!defer)
      {
	 /*
	 ** If in add external mode (relocatable) add as an external
	 */

	 if (addext)
	 {
	    if (fapmode)
	    {
	       if (qual[0] == '0') qual[0] = '\0';
	    }
	    s = symlookup (sym, qual, TRUE, xref);

	    if (s)
	    {
	       s->value = 0;
	       if (absmod || absolute)
		  s->relocatable = FALSE;
	       else
		  s->relocatable = TRUE;
	       s->external = TRUE;
	       addextsym = s;
	       goto SYM_FOUND;
	    }
	 }
	 
	 /*
	 ** Otherwise, it is an error
	 */

	 sprintf (errtmp, "Undefined symbol: %s", sym);
	 logerror (errtmp);
      }
      value = 0;
   }

   /*
   ** We found it.
   */

   else
   {

   SYM_FOUND:
      /*
      ** If in Boolean expression handle appropriately
      */

      if ((exprtype & EXPRTYPEMASK) == BOOLEXPR)
      {
#if 0
	 /*
	 ** Only BOOL data allowed in a boolean expression
	 */

	 if (!s->bool)
	 {
	    sprintf (errtmp, "Invalid symbol for BOOL expression: %s", sym);
	    logerror (errtmp);
	    value = 0;
	 }

	 /*
	 ** Bool value, return value and characteristics
	 */

	 else
	 {
#endif
#ifdef DEBUGBOOLSYM
            printf (
	       "symparse: BOOL sym = %s, val = %o, lrbool = %s, rbool = %s\n",
		  sym, s->value,
		  s->lrbool ? "TRUE" : "FALSE",
		  s->rbool ? "TRUE" : "FALSE");
#endif
	    value = s->value;
	    if (s->lrbool)
	    {
	       if (s->rbool) rboolexpr = TRUE;
	       else          lboolexpr = TRUE;
	    }
#if 0
	 }
#endif
      }

      /*
      ** Address expression
      */

      else
      {
	 /* Mark REF as being used */
	 if (s->external && s->value == 0)
	    s->relocatable = !absolute;
	 if (s->relocatable) relocatable++;
	 value = s->value;
	 if (s->external)
	 {
	    /* Don't relocate since it's extern tail */
	    if (value == 0) relocatable = 100;
	    /* back link reference chain */
	    s->value = pc + pcinc; 
	 }
      }
   }

   *relo = relocatable;
   return (value);
}

/***********************************************************************
* exprscan - Scan an expression and return its value.
***********************************************************************/

char *
exprscan (char *bp, int *val, char *tterm, int *relo, int entsize, int defer,
	  int pcinc)
{
   char *cp;
   int spaces = FALSE;
   int index = 0;
   int lrelo = FALSE;
   tokval lval = 0;

#ifdef DEBUGEXPR
   printf ("exprscan: entered: bp = %s\n", bp);
#endif
   cp = bp;

   /*
   ** Skip leading blanks
   */

   while (*bp && isspace(*bp))
   {
      spaces = TRUE;
      bp++;
   }

   /*
   ** If no operands, return EOL
   */

   if (spaces && (bp - inbuf >= NOOPERAND))
   {
      bp = cp;
      *tterm = '\n';
      *val = lval;
      *relo = lrelo;
      return (bp);
   }

#ifdef DEBUGEXPR
   printf ("   bp = %s\n", bp);
#endif

#if 0
   /*
   ** If nil operand, return type
   */

   if (!strncmp (bp, "**", 2))
   {
      index = 2;
      *tterm = *(bp+index);
      *val = lval;
      *relo = lrelo;
#ifdef DEBUGEXPR
      printf ("   null op: term = %c\n", *tterm);
#endif
      if (*tterm == ',') index++;
      return (bp+index);
   }
#endif

   /*
   ** Else, if literal then scan it off and put in symbol table
   */

   else if (*bp == LITERALSYM)
   {
      SymNode *s;
      char *cp;

      cp = bp;
      while (*cp && !isspace(*cp)) cp++;
      *cp = '\0';

#ifdef DEBUGLIT
      printf ("exprscan: pc = %o, litpool = %d, litorigin = %o, inpass = %o\n",
	       pc, litpool, litorigin, inpass);
#endif
      if (!(s = symlookup (bp, qualtable[qualindex], FALSE, TRUE)))
      {
	 if (!(s = symlookup (bp, qualtable[qualindex], TRUE, TRUE)))
	 {
	    sprintf (errtmp, "Unable to add Literal: %s", bp);
	    logerror (errtmp);
	    lval = 0;
	 }
	 if ((inpass & 070) == 010)
	 {
	    s->value = pc;
	    litpool++;
	 }
	 else
	 {
	    if (litorigin)
	       s->value = litorigin++;
	    else
	       s->value = pgmlength++;
	 }
      }
      lval = s->value;
      if (s->relocatable) lrelo = TRUE;
   }

   /*
   ** Call the parser to scan the expression
   */

   else if (strlen(bp) && *bp != ',')
   {
      if (*bp == '-')
      {
         if (*(bp+1) == ',' || isspace(*(bp+1)))
	 {
	    index = 1;
	    *tterm = *(bp+index);
	    *val = lval;
	    *relo = lrelo;
	    if (*tterm == ',') index++;
	    return (bp+index);
	 }
	 if (*(bp+1) == '1' && (*(bp+2) == ',' || isspace(*(bp+2))))
	 {
	    lval = (exprtype & BOOLVALUE) ? 0777777 : 077777 ;
	    index = 2;
	    *tterm = *(bp+index);
	    *val = lval;
	    *relo = lrelo;
	    if (*tterm == ',') index++;
	    return (bp+index);
	 }
      }
      else if (*bp == '/' && (*(bp+1) == ',' || isspace (*(bp+1))))
      {
	 lval = (exprtype & BOOLVALUE) ? 0777777 : 077777 ;
	 index = 1;
	 *tterm = *(bp+index);
	 *val = lval;
	 *relo = lrelo;
	 if (*tterm == ',') index++;
	 return (bp+index);
      }
      lval = Parser (bp, &lrelo, &index, entsize, defer, pcinc);
   }
#ifdef DEBUGEXPR
   printf (" index = %d, *(bp+index) = %02X\n",
	 index, *(bp+index));
   printf (" lrelo = %d, lval = %d\n", lrelo, lval);
#endif
   
   /*
   ** Return proper value and index
   */

   *tterm = *(bp+index);
   if (*tterm == ',') index++;
   *val = lval;
   *relo = lrelo;
   return (bp+index);
}


/***********************************************************************
* condexpr - Scan a conditional assembly expression and return its value.
***********************************************************************/

char *
condexpr (char *bp, int *val, char *term)
{
   char *lbp;
   char *rbp;
   int r;
   int rel;
   int ret;

#ifdef DEBUGCONDEXPR
   printf ("condexpr: linenum = %d: bp = %s", linenum, bp);
#endif

   /*
   ** Skip leading blanks 
   */

   while (*bp && isspace(*bp)) bp++;
   lbp = bp;

   /*
   ** Locate terminal space 
   */

   while (*bp && !isspace(*bp)) bp++;
   *term = *bp;
   *bp = '\0';

   /*
   ** Locate added condition, if any
   */

   if ((rbp = strchr (lbp, ',')) != NULL)
   {
      *term = *rbp;
      *rbp++ = '\0';
      bp = rbp;
   }

   /*
   ** If there is an equal sign, we have an expression. evaluate
   */

   if ((rbp = strchr (lbp, '=')) != NULL)
   {
      *rbp++ = '\0';

      /*
      ** check if GT operation
      */

      if (*rbp == '+')
      {
         rel = GT;
	 rbp++;
      }

      /*
      ** check if LT operation
      */

      else if (*rbp == '-')
      {
         rel = LT;
	 rbp++;
      }

      /* 
      ** Must be strict equality
      */

      else
      {
         rel = EQ;
      }
#ifdef DEBUGCONDEXPR
      printf ("   lbp = %s, rel = %d, rbp = %s\n", lbp, rel, rbp);
#endif

      /* 
      ** Check if string compare
      */

      if (*lbp == '/')
      {
	 char *cp;
	 char lch[MAXSYMLEN+2];
	 char rch[MAXSYMLEN+2];

	 /*
	 ** Yes, isolate compare tokens
	 */

         if (*rbp != '/')
	 {
	    *term = *rbp;
	    *val = -1;
	    return (bp);
	 }
	 lbp++, rbp++;
	 cp = lch;
	 *cp = '\0';

	 while (*lbp && *lbp != '/')
	 {
	    *cp++ = *lbp++;
	    *cp = '\0';
	 }
	 cp = rch;
	 *cp = '\0';

	 while (*rbp && *rbp != '/')
	 {
	    *cp++ = *rbp++;
	    *cp = '\0';
	 }
#ifdef DEBUGCONDEXPR
	 printf ("   lch = '%s', rch = '%s'\n", lch, rch);
#endif
	 /*
	 ** Compare string tokens
	 */

	 r = strcmp (lch, rch);
      }

      /*
      ** Not a string, do arithmetic compare
      */

      else
      {
	 int index = 0;
	 int lrelo = 0;
	 tokval lval;
	 tokval rval;

	 /*
	 ** Use the parser to return expression values
	 */

	 if (*lbp)
	    lval = Parser (lbp, &lrelo, &index, 1, FALSE, 0);
	 else
	    lval = 0;
	 if (*rbp)
	    rval = Parser (rbp, &lrelo, &index, 1, FALSE, 0);
	 else
	    rval = 0;
#ifdef DEBUGCONDEXPR
	 printf ("   lval = %d, rval = %d\n", lval, rval);
#endif

	 /*
	 ** Set compare values
	 */

	 if (lval > rval) r = 1;
	 else if (lval < rval) r = -1;
	 else r = 0;
      }

      /*
      ** Set return relation based on requesed compare
      */

      if (rel == EQ && r == 0) ret = TRUE;
      else if (rel == GT && r > 0) ret = TRUE;
      else if (rel == LT && r < 0) ret = TRUE;
      else ret = FALSE;
#ifdef DEBUGCONDEXPR
      printf ("   val = %d, ret = %s\n", r, ret ? "TRUE" : "FALSE");
      printf ("   term = %c(%x), bp = %s\n", *term, *term, bp);
#endif
      *val = ret;
   }
   return (bp);
}
