
/* Symbol table manipulation routines */

#include <stdio.h>
#include "cc65.h"

#ifndef M6502
extern int debug;
extern int maxloc;
extern int tmpx, tmpy;
#endif

struct hashent * findsym();

/*
  addsfld( psym, tarray, offset )
  Add a struct field definition to symbol table.
*/
addsfld(psym, tarray, offset)
struct hashent * psym;
char * tarray;
int offset;
{
char * tptr;

  if (psym->h_glb != 0)
    {
      MultDef("component");
    }
  tptr = Gmalloc(strlen(tarray) + 1);
  strcpy(tptr, tarray);

  psym->h_glb = SC_SFLD;
  psym->h_gtptr = tptr;
  psym->h_gdata = offset;
}

/*
  addstag( psym, sz )
  Define a struct/union tag to the symbol table.  Returns index into
  structs array.
*/
int addstag(psym, sz)
struct hashent * psym;
int sz;
{
  if (psym->h_glb != NULL)
    {
      /*
        tag already declared; check for multiple declare
      */
#ifdef M6502
/*
   Sigh.  should be able to declare that thing unsigned byte,
   and do it this way, but cc65 generates the wrong code, and
   sign extends anyhow.  mask it by hand.
      if ((psym->h_glb != SC_STAG) ||
*/
      if (((psym->h_glb & 0xFF) != SC_STAG) ||
#else
      if (((psym->h_glb & 0xFF) != SC_STAG) ||
#endif
	  ((sz != 0) && (psym->h_gdata != 0)))
	{
	  MultDef("tag");
	}
      /*
        define struct size if sz != 0
      */
      if (sz != 0)
	{
	  psym->h_gdata = sz;
	}
      return;
    }

  psym->h_glb = SC_STAG;
  psym->h_gdata = sz;
  return;
}

/*
  addsym( sym )
  Add a symbol to the symbol table.
*/
struct hashent * addsym(sym)
char * sym;
{
  struct hashent ** hptr;
  struct hashent * psym;

  if (psym = findsym(sym))
    {
      return (psym);
    }

  /*
    Allocate storage for hash table entry
  */
  psym = (struct hashent *) Gmalloc(sizeof(struct hashent) + strlen(sym));
  bzero(psym, sizeof(struct hashent));
  strcpy(psym->h_name, sym);

  /*
    Add a symbol entry to the hash table.  hashval set by findsym above.
  */
  hptr = &htab[hashval];
  psym->h_ptr = *hptr;
  return (*hptr = psym);
}

/*
  findsym( sym )
  Look up sym in hash table and return ptr to entry.
*/
struct hashent * findsym(sym)
char * sym;
{
struct hashent * p;

#ifdef M6502
/* this seems to be about as good a place as any to put the
   stack overflow checker */
  chkstk();
#endif

  hashval = hash(sym);
  for (p = htab[hashval]; p != NULL; p = p->h_ptr)
    {
      if (!strcmp(p->h_name, sym))
	{
	  return (p);
	}
    }
  return (NULL);
}

/*
  addglb( psym, tarray, sc )
  Add a global symbol to the symbol table
*/
addglb(psym, tarray, sc)
struct hashent * psym;
char * tarray;
int sc;
{
char * tptr;
int sz1;

  if (psym->h_glb != 0)
    {
      /*
       * symbol entered previously.
       */
      if (psym->h_glb & SC_STRUCT)
	{
	  MultDef("global symbol");
	  return;
	}

      if ((tarray[0] == T_ARRAY) &&
	  (((sz1 = decode(psym->h_gtptr + 1)) == 0) ||
	   (decode(tarray + 1) == 0)))
	{
	  if (strcmp(psym->h_gtptr + 4, tarray + 4) != 0)
	    {
	      MultDef("global symbol");
	      return;
	    }
	  if (sz1 == 0)
	    {
	      encode(psym->h_gtptr + 1, decode(tarray + 1));
	    }
	}
      else if (strcmp(psym->h_gtptr, tarray) != 0)
	{
	  MultDef("global symbol");
	  return;
	}
      /*
      if (((tarray != NULL) && (strcmp(psym->h_gtptr, tarray) != 0)) ||
          (psym->h_glb & SC_STRUCT)) {
          Error("multiply defined global symbol");
          return;
          }
      */
      psym->h_glb |= sc;
      return;
    }

  tptr = Gmalloc(strlen(tarray) + 1);
  strcpy(tptr, tarray);

  psym->h_glb = sc;
  psym->h_gtptr = tptr;
/*    psym->h_gdata = 10000 + glblbl++;	-- jrd */
/* we always want symbol name, not internal cruft, so we just shove ptr
   to start of name string in here instead of internal ident */
#ifdef M6502
  psym->h_gdata = (int) psym->h_name;
#else
  psym->h_gdata = (int) &psym->h_name;
#endif

  psym->h_link = glvptr;
  glvptr = psym;
}

/*
  Add a local symbol.
*/
addloc(psym, tarray, sc, offs)
struct hashent * psym;
char * tarray;
int sc;
int offs;
{
char * tptr;

  /*
    Process function declarations and externs inside of function.
  */
  if ((tarray != NULL) && (tarray[0] == T_FUNC))
    {
      if ((sc & (SC_DEFAULT | SC_EXTERN)) == 0)
	{
	  Warning("function must be extern");
	}
      sc = SC_EXTERN;
    }
  if (sc & SC_EXTERN)
    {
      addglb(psym, tarray, sc);
      return;
    }

  /*
  if ((tarray != NULL) && (tarray[0] == T_FUNC))
      {
      addglb(psym, NULL, SC_DEFINED | SC_EXTERN);
      return;
      }
  */
  if (psym->h_loc != 0)
    {
      MultDef("local symbol");
      return;
    }
  if (tarray != NULL)
    {
      tptr = Lmalloc(strlen(tarray) + 1);
      strcpy(tptr, tarray);
    }
  else
    {
      tptr = NULL;
    }

  psym->h_loc = sc | SC_DEFINED;
  psym->h_ltptr = tptr;
  psym->h_ldata = offs;

  lvtab[lovptr++] = psym;
}

/*
  eraseloc()
  Erase local variables.
*/
eraseloc()
{
int i;

  i = 0;
  while (i < lovptr)
    {
      lvtab[i++]->h_loc = 0;
    }
  lovptr = 0;
  lsptr = locspace;
}

/*
  hash( s )
  Compute hash value of string s.
*/
#ifdef M6502
#asm
	.globl	_hash
_hash:
	jsr	popax		; get str ptr
	sta	ptr1
	stx	ptr1+1
	ldy	#0
	tya
	clc
	tax
hash1:
	lda	(ptr1),y	; eos?
	beq	hash2
	txa			; get our total back
	adc	(ptr1),y	; add a byte
	tax			; save again in x
	iny
	bne	hash1
hash2:
	txa
	ldx	#0
	and	#$7F
	rts
#endasm
#else
hash(s)
char * s;
{
int h;

#ifndef M6502
  ++tmpx;
  tmpy += strlen(s);
#endif
  h = 0;
  while (*s)
    {
      h += *s++;
    }
  return (h & 0x7F);
}

#endif

#ifdef help_1
/* helper fun for malloc'ers */
xmalloc(nbytes, ptr_p, limit)
int nbytes;
char ** ptr_p;
char * limit;
{
char * ptr;
char * new_ptr;

  if ((new_ptr = (ptr = *ptr_p) + nbytes) > limit)
    return (0);
  else
    {
      *ptr_p = new_ptr;
      return (ptr);
    }
}

#endif

/*
  Gmalloc( nbytes )
  Allocate memory from the global space table.
*/
char * Gmalloc(nbytes)
int nbytes;
#ifndef help_1
{
char * p;

#ifndef M6502
  nbytes = (nbytes + sizeof(int) - 1) & (~(sizeof(int) - 1));
#endif
  p = gsptr;
/*    if ((gsptr += nbytes) - glbspace > GSPACE) */
  if ((gsptr += nbytes) > gblend)
    {
      fatal("out of global memory");
    }
  return (p);
}

#else
{
char * np;

  if (!(np = xmalloc(nbytes, &gsptr, glbspace + GSPACE)))
    fatal("out of global memory");
  return (np);
}

#endif

/*
  Lmalloc( nbytes )
  Allocate nbytes from the local space table.
*/
char * Lmalloc(nbytes)
int nbytes;
#ifndef help_1
{
char * p;

#ifndef M6502
  nbytes = (nbytes + sizeof(int) - 1) & (~(sizeof(int) - 1));
#endif
  p = lsptr;
  if ((lsptr += nbytes) - locspace > LSPACE)
    {
      fatal("out of local memory");
    }
#ifndef M6502
  if (lsptr - locspace > maxloc)
    maxloc = lsptr - locspace;
#endif
  return (p);
}

#else
{
char * np;

  if (!(np = xmalloc(nbytes, &lsptr, locspace + LSPACE)))
    fatal("out of local memory");
  return (np);
}

#endif

/*
  SizeOf( tarray )
  Compute size of object represented by type array.
*/
int SizeOf(tarray)
char * tarray;
{
  struct hashent * p;

  switch (*tarray)
    {
    case T_CHAR:
    case T_UCHAR:
      return (1);
    case T_INT:
    case T_UINT:
    case T_PTR:
      return (2);
    case T_ARRAY:
      return (decode(tarray + 1) * SizeOf(tarray + 4));
    default:
      if (*tarray & T_STRUCT)
	{
	  /* jrd hacked this */
#ifdef M6502
	  p = (struct hashent *) decode(tarray); /* old way */
#else
	  p = (struct hashent *) (((int) decode(tarray)) + (int) gblspace);
	  /* use offset, not addr */
#endif
	  return (p->h_gdata);
	}
#ifndef M6502
      printf("unknown type: %02x\n", *tarray);
#endif
      fatal("unknown type code");
      return (0);
    }
}

/*
  PSizeOf(tptr)
  Compute size of pointer object.
*/
PSizeOf(tptr)
char * tptr;
{
  if (tptr[0] == T_ARRAY)
    tptr += 3;
  return (SizeOf(++tptr));
}

#ifndef M6502
/*
  dumpglbs()
  Dump global symbol table, for debugging.
*/
dumpglbs()
{
int i;
struct hashent * psym;
int sc;

  if (debug)
    {
      printf("\nGlobal Symbol Table\n");
      printf("===================\n");
      for (psym = glvptr; psym; psym = psym->h_link)
	{
	  if (psym->h_glb & SC_STRUCT)
	    continue;
	  printf("%02x, ", psym->h_glb);
	  ptype(psym, psym->h_gtptr);
	}
    }

}

#endif

#ifndef M6502
/*
  dumploc( psym )
  Dump local symbol table, for debugging.
*/
dumploc(pfunc)
struct hashent * pfunc;
{
int i;
struct hashent * psym;

  if (!debug)
    return;
  printf("\nLocal Symbol Table for '%s'\n", pfunc->h_name);
  printf("==================================\n");
  for (i = 0; i < lovptr; ++i)
    {
      psym = lvtab[i];
      printf("%2d, %4d, ", psym->h_loc,
	     psym->h_ldata);
      ptype(psym, psym->h_ltptr);
    }
}

#endif

/*
  dumpnams()
  dump names of globals
*/
dumpnams()
{
  struct hashent * psym;
  int sc;

  for (psym = glvptr; psym; psym = psym->h_link)
    {
      if ((sc = psym->h_glb) & SC_STRUCT)
	continue;
      if (sc & SC_EXTERN)
	outgoe(psym->h_name);
    }
}

#ifndef M6502
/*
  dumpstruct()
  Dump structs/unions.
*/
dumpstruct()
{
int i;
struct hashent * psym;

  if (!debug)
    return;
  printf("\nStruct/union Table\n");
  printf("==================\n");
}

#endif

/*
  encode( p, w )
  Encode p[0] and p[1] so that neither p[0] nore p[1] is zero
*/
encode(p, w)
char * p;
int w;
{
#ifndef M6502
  if (w & 0xFFFF0000)
    {
      fprintf(stderr, "w = %X\n", w);
      fatal("information lost on encode");
    }
#endif
  /*
  p[0] = ((w >> 3) & 0x30) | 0x01;
#ifdef M6502
  *((int *) (p + 1)) = w | 0x0180;
#else
  *((short *) (p + 1)) = (short) w | 0x0180;
#endif
  */
  p[2] = w | 0x80;
  p[1] = (w >> 7) | 0x80;
  p[0] = (w >> 14) | 0x80;
}

/*
  decode( p )
  Decode.
*/
int decode(p)
char * p;
{
/*
#ifdef M6502
    return( (*((int *) ( p + 1)) & (~0x0180)) | ((p[0] & 0xFE) << 3) );
#else
    return( (*((int *) ( p + 1)) & (~0x0180)) | ((p[0] & 0xFE) << 3) );
#endif
*/
  return ((p[2] & 0x7F) | ((p[1] & 0x7F) << 7) | ((p[0] & 0x03) << 14));
}
