//------------------------------------------------------------
// SYMBOLS.CPP
// Keith Larson
// TMS320 DSP Applications
// (c) Copyright 1995, 1996, 1997
// Texas Instruments Incorporated
//
// This is unsupported freeware code with no implied warranties or
// liabilities.  See the disclaimer document for details
//------------------------------------------------------------
// SYMBOLS.CPP creates and manages the symbol table arrays
//------------------------------------------------------------
#include <string.h>
#include <stdio.h>
#include "symbols.h"
#include "dsk.h"

float DSK3_rev  = DSK3_ver; // DSK3 version stamp available to all apps

XREF_TABLE SYM[MAX_SYMBOLS];
char symbols[sym_str_tbl_sz];   // large array of symbol strings
char *symbol_ptr = symbols;     // Ptr to string table
char *post_boot_symbols=symbols;// Ptr to string table after bootup
int  post_boot_sym=0;           // Symbol table offset
int  last_ref=0;                // Last symbol entry
int  last_segment=1;            //
int  current_seg = 1;           // Init value keeps exp_anal happy
segments SEG[MAX_SEGMENTS];
//-------------------------------------------------------
// symb_defined() returns a non zero offset+1 into the
// the symbol table if a symbol is defined
//-------------------------------------------------------
int symb_defined(char *ptr)
{
  for(int x=0;x<last_ref;x++)
  {
    if(strexact(ptr, SYM[x].sptr))
      return x+1;  // Can now use to redefine a symbol
  }
  return 0;
}
//==================================================================
// ref_add() adds a symbol at *ptr to the symbol list. The symbol
// list is an array of values and attributes along with a pointer
// to the symbol string stored in the symbol string array 'symbols'.
//==================================================================
MSGS xref_add(char *ptr, ulong value, NUM_TYPE type, SYM_TYPE addressable)
{
  int x;
  for(x=0;x<last_ref;x++)
  {
    if(strexact(ptr, SYM[x].sptr))
    return MULT_REF;
  }
  if(last_ref   >= (MAX_SYMBOLS - 1))                return FATAL_SYM1;
  if(symbol_ptr >  (symbols + sym_str_tbl_sz - 32))  return FATAL_SYM2;
  SYM[last_ref].sptr = symbol_ptr;   // add symbol to ref table
  symbol_ptr += sprintf(symbol_ptr, ptr);
  *symbol_ptr++ = 0;
  SYM[last_ref].value  = value;
  SYM[last_ref].numt   = type;
  SYM[last_ref].symt   = addressable;
  SYM[last_ref+1].numt = NOREF;
  last_ref++;
  return NO_ERR;
}
//==========================================================
// ref_mod only changes the value of a symbol.  None of the
// attributes are changed... use carefully as this can
// cause float and integer types to become confused.
//==========================================================
MSGS ref_mod(char *ptr, ulong value)
{
  int x;
  for(x=0;x<last_ref;x++)
  {
    if(strexact(ptr, SYM[x].sptr)) break;
  }
  if(x>=last_ref) return NO_REF;
  SYM[x].value = value;
//SYM[x].type  = 1;
//SYM[x].a     = 0;
  return NO_ERR;
}
//==========================================================
// Modifies the value and all attribytes of a symbol
//==========================================================
MSGS xref_mod2(char *ptr, ulong value,NUM_TYPE type, SYM_TYPE addressable)
{
  int x;
  for(x=0;x<last_ref;x++)
  {
    if(strexact(ptr, SYM[x].sptr)) break;
  }
  if(x>=last_ref) return NO_REF;
  SYM[x].value = value;
  SYM[x].numt  = type;
  SYM[x].symt  = addressable;
  return NO_ERR;
}
//==================================================================
// Returns the symbol table offset for a symbol, or -1 if not found
//==================================================================
int ref_offs(char *ptr)
{
  int x;
  for(x=0;x<last_ref;x++)
  {
    if(strexact(ptr, SYM[x].sptr)) break;
  }
  if(x>=last_ref) return -1;
  return x;
}
//==================================================================
// Removes .define symbols from the table by setting the string to ""
//==================================================================
void remove_defines(void)
{
  int x;
  for(x=0;x<last_ref;x++)
  {
  //if(SYM[x].numt==SYM_DEF)
    if(SYM[x].symt==SYM_DEF)
      strcpy(SYM[x].sptr,"");
  }
}
//-----------------------------------------------------------------
// argstart() is used by the various parsers to find the beginning
// of string, stripping off the leading WS, TAB and other special
// characters.  Argstart also recognizes other special characters
// to the assembler such as the colon ':' and semi-colon ';'
//-----------------------------------------------------------------
char *argstart(char *ptr)
{ for(int x=0;x<120;x++)
  { switch(*ptr)
    { case  ' ':
      case  ':':
      case  ',':
      case '\t': ptr++; break;
      case '\n':
      case '\r':
      case  ';': *ptr=0; return ptr;
      default  : return ptr;
    }
  }
  *ptr = 0; return ptr;
}
//-----------------------------------------------------------
// argend() finds the last character in a string which is not
// a WS or invalid symbol character.  The string is then terminated
// and a pointer to the end is returned.
//-----------------------------------------------------------
char *argend(char *ptr,char EnColn)
{
  int parrend_count = 0;
  for(int x=0;x<120;x++)
  { switch(*ptr)
    {
      case  ',': if(parrend_count == 0) return ptr;
                 else ptr++; break;
      case  ' ':
      case '\t':
      case  ';':
      case '\n':
      case '\r':
      case   0 : return ptr;
      case  '(': parrend_count++; ptr++; break;
      case  ')': parrend_count--; ptr++; break;
      case  ':': if(EnColn==0) return ptr;
      default  : ptr++; break;
    }
  }
  *ptr = 0; return ptr;
}

//----------------------------------------------------------
// sets *value to the value of a defined symbol.  Returns
// the type on success or NO_REF if the symbol was not found
//----------------------------------------------------------
NUM_TYPE ref_value(char *ptr, long *value)
{ int x;
  ptr = argstart(ptr);              // This line is different
  for(x=0;x<last_ref;x++)
  { if(strexact(SYM[x].sptr, ptr))
    {
      *value = SYM[x].value;
  //  if(SYM[x].a) return INTEGER;
  //  if(SYM[x].numt == SYM_ANNUL)
  //    return NOREF;  // If label... even needed?
      if(SYM[x].symt ==SYM_LBL) return INTEGER; // If label... even needed?
      return SYM[x].numt;                   // SYM_LBL was 1
    }
  }
  return NOREF;
}
//=================================================
// get_label searches for a 32 bit value match to
// addr and if found writes the associated string
// to the char pointer *label. The value lws is
// used to insert leading white space characters.
//
// Also the addressable field SYM[].a is used as a
// filter to only use addresable items
//=================================================
int get_label(char *label,ulong addr, int lws)
{
  char *p;
  for(int j=0; j<last_ref/*MAX_SYMBOLS*/; j++)
  {
//  if(*SYM[j].sptr == 0) break;
    if ( (unsigned long) SYM[j].value == addr)
    {
      if ( SYM[j].symt == SYM_LBL)   // Type is LABEL  SYM_LBL was 1
      {
        //----------------------------------------------------
        // First version simply aborts if a ":" delimiter is
        // found in the symbol.  The ":" indicates that the
        // symbol name is composed of the symbol plus the
        // name of the file it was defined in.  However for
        // example .text appears in the symbol table many times
        // and can be confusing..
        //
        // The second version chops off the file name, making
        // the symbol shorter, but at the risk of appearing to
        // be aliased into many locations.
        //
        // The third version simply copies the entire symbol
        //----------------------------------------------------
        // 1st version
        /*
        if(strstr(SYM[j].sptr,":")==NULL)
        {
          for(;lws>0;lws--) *label++=' '; // insert desired WS
          sprintf(label,"%.12s",SYM[j].sptr);
          return 1;
        }
        */

        // 2nd version
        for(;lws>0;lws--) *label++=' '; // insert desired WS
        sprintf(label,"%.12s",SYM[j].sptr);
        if((p=strstr(label,":"))!=NULL) *p=0;
        return 1;
        /*
        // 3rd version
        for(;lws>0;lws--) *label++=' '; // insert desired WS
        sprintf(label,"%.12s",SYM[j].sptr);
        return 1;
        */
      }
    }
  }
  *label = 0;
  return 0;
}
//=================================================================
// tabstrip() removes tab characters assuming tabs every Nth char
// This function also assumes that the string can be expanded in
// place.  IOW there should unused string space following the string.
//=================================================================
void tabstrip(char *buf,int N)
{
  int x, cnt;
  char tmp[120];
  char *t = tmp, *p=buf;
  cnt = N;
  for(x=0;x<80;x++) // strip a maximum of 80 chars
  {
    switch(*p)
    {
      case    0: break;  // Line termination
      case '\t': for(;cnt>0;cnt--)
                   *t++ = ' ';
                 p++;
                 break;
      default: *t++ = *p++; cnt--; break;
    }
    *t = 0;
    if(*p==0) break;
    if(cnt<=0) cnt = N;
  }
  strcpy(buf,tmp);
}
