/***********************************************************************
     "fld_basic.o": FieLD BASIC functions.
***********************************************************************/

/***********************************
  (C) Copyright 1992-1993; dit/upm
   Distributed under the conditions stated in the
   EPS General Public License (see file LICENSE)
 ***********************************
 $Log: fld_basic.c,v $
 * Revision 1.5  1993/01/12  18:18:48  eps
 * portability issues
 *
 * Revision 1.4  1993/01/12  16:37:10  eps
 * portability issues
 *
 * Revision 1.3  1992/05/06  17:29:03  eps
 * shut up lint complaints about exit()
 *
 * Revision 1.2  92/01/14  15:45:46  eps
 * distribution issues
 *
 * Revision 1.1  91/07/11  12:51:14  eps
 * Initial revision
 *
 ***********************************/

#ifndef lint
static char rcsid[]= "$Id: fld_basic.c,v 1.5 1993/01/12 18:18:48 eps Exp $";
#endif

/* LINTLIBRARY */

#define fld_basic_IMP

/* KJT 12/02/12: Added */
#include <string.h>
#include <stdio.h>
#include "bsc_dcls.hh"
#include "lnt_pass.hh"
#include "err_handl.hh"
#include "prg_error.hh"
#include "mem_alloc.hh"
#include "fld_basic.hh"

/* KJT 22/01/23: added function prototypes */
int is_word ();

typedef struct
{ char **elem;
  int size;
  int level;
  int first;
} tSYM_TBL;	/* symbol table type */

/* user defined symbol table */
PRIVATE tSYM_TBL uds_tbl= { NULL, 0, 0, 1 };

/* dynamically defined symbol table */
PRIVATE tSYM_TBL dds_tbl= { NULL, 0, 0, 0 };

/* start condition of symbol table support */
#define start_sym	(dds_tbl.first == 0)

/* dynamically defined symbol increment */
#define DDS_INC		(BUFSIZ / sizeof(char *))

/**
  * Selecting a Hashing Algorithm
  * B.J. McKenzie, R. Harries and T. Bell
  * Software Practice & Experience
  * vol. 20(2), 209-224, Feb. 1990
 */

#define HASHSIZE 501		/* some odd number */

typedef struct Snode
{ int id;
  char *name;
  struct Snode *next;
} SNODE;

PRIVATE SNODE *hash_tbl[HASHSIZE];	/* hash table */

/* computes a hash index for a symbol */

PRIVATE int
hash (sym)
  char *sym;
{
  int h;

  h= 0;
  while (*sym != '\0')
    h= 4 * h + *(sym++);
  h%= HASHSIZE;
  if (h < 0)
    h+= HASHSIZE;
  return h;
}

/* initializes symbol table support, or returns FALSE if cannot */

PRIVATE int
sym_init ()
{
  static char err_intro[]= "sym_init";
  int i;
  int h;
  SNODE *n;
  int is_good= TRUE;

  abort_if(!start_sym)
  abort_if(uds_tbl.first <= ESYM)
  for (i= 0; i < HASHSIZE; i++)
    hash_tbl[i]= NULL;
  for (i= 0; sym_lst[i] != ESYM; ++i)
  { h= hash(sym_lst[i]);
    for (n= hash_tbl[h]; n != NULL; n= n->next)
      if (sym_lst[i] == NULL || *sym_lst[i] == '\0')
      { is_good= FALSE;
	xerror(0, "%s: missing symbol in symbol list", err_intro);
      }
      else if (!is_sym(sym_lst[i]))
      { is_good= FALSE;
	xerror(0, "%s: incorrect symbol \"%s\" in symbol list",
	       err_intro, sym_lst[i]);
      }
      else if (strcmp(sym_lst[i], n->name) == 0)
      { is_good= FALSE;
	xerror(0, "%s: duplicated symbol \"%s\" in symbol list",
	       err_intro, sym_lst[i]);
      }
    talloc(n, 1);
    n->id= i + uds_tbl.first;
    n->name= sym_lst[i];
    n->next= hash_tbl[h];
    hash_tbl[h]= n;
  }
  uds_tbl.elem= sym_lst;
  uds_tbl.level= uds_tbl.size= i;
  dds_tbl.first= uds_tbl.first + uds_tbl.level;
  abort_if(start_sym)
  return is_good;
}

PUBLIC int
new_sym (sym)
  char *sym;
{
  int h;
  SNODE *n;
  char *strcpy();

  if (start_sym && !sym_init())
    exit(1);
  if (sym == NULL)
    return ESYM;
  h= hash(sym);
  for (n= hash_tbl[h]; n != NULL; n= n->next)
    if (strcmp(sym, n->name) == 0)
      return n->id;
  talloc(n, 1);
  n->id= dds_tbl.first + dds_tbl.level;
  talloc(n->name, strlen(sym) + 1);
  (void) strcpy(n->name, sym);
  n->next= hash_tbl[h];
  hash_tbl[h]= n;
  if (dds_tbl.level == dds_tbl.size)
  { if (dds_tbl.size == 0)
      talloc(dds_tbl.elem, DDS_INC);
    else
      trealloc(dds_tbl.elem, dds_tbl.size + DDS_INC);
    dds_tbl.size+= DDS_INC;
  }
  dds_tbl.elem[dds_tbl.level++]= n->name;
  return n->id;
}

PUBLIC int
sym_id (name)
  char *name;
{
  SNODE *n;

  if (start_sym)
    return ESYM;
  if (name == NULL)
    return ESYM;
  for (n= hash_tbl[hash(name)]; n != NULL; n= n->next)
    if (strcmp(name, n->name) == 0)
      return n->id;
  return ESYM;
}

PUBLIC char *
sym_name (id)
  int id;
{
  if (start_sym)
    return NULL;
  if (id == ESYM)
    return NULL;
  if (id < uds_tbl.first)
    return NULL;
  else if (id < uds_tbl.first + uds_tbl.level)
    return uds_tbl.elem[id - uds_tbl.first];
  else if (id < dds_tbl.first + dds_tbl.level)
    return dds_tbl.elem[id - dds_tbl.first];
  else
    return NULL;
}

PUBLIC int
is_int (str)
  char *str;
{
  if(str == NULL || *str == '\0')
    return FALSE;
  if (*str == '-' && *++str == '\0')
    return FALSE;
  do
    if (*str < '0' || *str > '9')
      return FALSE;
  while (*++str != '\0');
  return TRUE;
}

