/* These subroutines manipulate the symbol table.
 *
 * $Log: symtab.c,v $
 * Revision 1.2  1997/06/04 01:21:07  david
 * ANSI-fied the program.
 *
 */

#include <stdio.h>
#include <string.h>
#include "xasm.h"
#include "symbols.h"

static char *RcsId = "$Id: symtab.c,v 1.2 1997/06/04 01:21:07 david Exp $";

#define MaxSymSize 10

static struct symtab *root = NULL; /* Root of Symbol Table */

void xrefins( struct symtab *, char );

/*
   This subroutine attempts to find a symbol in the symbol table and
   return the value, and the 'Multiple Definition' flag. It returns a
   0 (FALSE) if it is not found, and a 1 (TRUE) if it is found
*/
/* xrefflg = Should we reference the Cross Reference Table? */
char symfind( char *symbol, WORD *value, char xrefflg )
{
struct symtab *p;
   
for ( p = root; p != NULL; p = p->next )
   if ( strcmp( p->name, symbol ) == 0 )
      {
      *value = p->value;
      if ( p->line == 0 || p->line > line )
	 fwdref = 1; /* Set forward reference flag */
      if ( xrefflg )
         xrefins( p, ' ' ); /* Symbol referenced, Don't mark 'defined' */
      return( p->muldef ); /* Yep. We found it. Return 'defined' status */
      }

*value = -1;
fwdref = 1; /* Set forward reference flag */
if ( xrefflg )
   symins( symbol, *value, ' ' ); /* Insert symbol & line reference */
return( ' ' ); /* Not defined */
}

/*
   This subroutine inserts the symbol into the correct place in the list.
   If the symbol is already there then it just changes the 'muldef' and
   the 'value' according to the passed variables.
*/
void symins( char *symbol, WORD value, char muldef )
{
struct symtab *p, *q, *r;
int not_found = 1; /* Initialize to "NOT FOUND" */

for ( q = p = root; p != NULL; q = p, p = p->next )
   { /* Is this it or past it? */
   not_found = strcmp( p->name, symbol );
   if ( not_found >= 0 )
      break;
   }
   
if ( not_found ) /* It's not in the list...Insert it */
   { /* Allocate memory and stuff symbol into it */
   if ( (r=(struct symtab *) malloc( sizeof( struct symtab ))) == NULL )
      {
      fprintf( stderr, "symins: *** Out of memory ***\n" );
      exit( 1 );
      }
   /* Initialize values */
   r->name = strdup( symbol ); /* Copy symbol */
   r->value = value;
   r->muldef = muldef;
   r->next = NULL;
   r->xptr = NULL;
   r->line = 0;
   if ( muldef == 'D' )
      xrefins( r, muldef ); /* Mark line symbol defined on */
   /* Now adjust pointers */
   if ( q == NULL || q == p )
      { /* Insert as first one */
      r->next = root;
      root = r;
      }
    else
      if ( p == NULL )
	 {
         q->next = r; /* Insert as last one */
	 }
       else /* Insert inbetween p & q */
          {
          r->next = q->next;
	  q->next = r;
	  }
   }
 else /* It is found...Change the value */
   {
   p->muldef = muldef;
   p->value = value;
   if ( muldef == 'D' )
      xrefins( p, muldef );
   }
}

/* This subroutine displays the contents of the symbol table */
void symdisp(void)
{
struct symtab *p;
char format[15], addr[5];
int count = 0, i;
   
if ( root != NULL )
   {
   printf( "\nSymbol Table:\n\n" );
   sprintf( format, "%%-%ds %%-s  ", MaxSymSize );
   for ( p = root; p != NULL; p = p->next )
      {
      sprintf( addr, "%04x", p->value );
      for ( i = 0; i < 4; i++ )
	  if ( addr[i] >= 'a' && addr[i] < 'z' )
	     addr[i] -= 0x20; /* Make into all CAPS */
      printf( format, p->name, addr );
      if ( (++count & 3) == 0 )
         printf( "\n" );
      }
   printf( "\n" );
   }
}

/* Insert Cross reference lines into the Cross Reference structure */
/* sptr = Pointer to symbol structure */
/* defined = Is symbol defined in this line? */
void xrefins( struct symtab *sptr, char defined )
{
struct xref *ptr, *ptr1 = NULL;
char found = 0;

if ( defined == 'D' )
   sptr->line = line;
 else
   {
   for ( ptr = sptr->xptr; ptr != NULL; ptr1 = ptr, ptr = ptr->next )
      if ( ptr->line == line )
	 {
	 found = 1;
	 break;
	 }
   if ( !found )
      {
      if ( (ptr = (struct xref *) malloc(sizeof(struct xref))) == NULL )
	 {
	 fprintf( stderr, "xrefins: *** Out of Memory. ***\n" );
	 exit( 1 );
	 }
      ptr->next = NULL;
      ptr->line = line;
      if ( ptr1 == NULL )
	 sptr->xptr = ptr;
       else
	 ptr1->next = ptr;
      }
   }
}

void xrefdisp(void)
{
struct symtab *p;
struct xref   *x;
FILE *fd = stdout;
char strval[5];
int i;

fprintf( fd, "Symbol Table and Cross Reference Listing for file %s.\n\n",
   filename );
fprintf( fd, "Symbol     Value Defined Referred from\n" );
fprintf( fd, "---------- ----- ------- -------------\n\n" );

for ( p = root; p!= NULL; p = p->next )
   {
   sprintf( strval, "%04x", p->value );
   for ( i = 0; i < 4; i++ )
      if ( strval[i] >= 'a' && strval[i] <= 'z' )
	 strval[i] -= 0x20;
   fprintf(fd, "%-10s  %s   %5d  ", p->name, strval, p->line); /* MaxSymSize */
   for ( x = p->xptr; x != NULL; x = x->next )
      fprintf( fd, "%5d ", x->line );
   fprintf( fd, "\n" );
   }
}
