/*
** Splint - annotation-assisted static program checker
** Copyright (C) 1994-2003 University of Virginia,
**         Massachusetts Institute of Technology
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
** Free Software Foundation; either version 2 of the License, or (at your
** option) any later version.
** 
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** The GNU General Public License is available from http://www.gnu.org/ or
** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
** MA 02111-1307, USA.
**
** For information on splint: info@splint.org
** To report a bug: splint-bug@splint.org
** For more information: http://www.splint.org
*/
/*
** syntable.c
**
** Larch/C Interface language synonym table
**
**	This table stores synonyms for the Larch/C Interface Language.  It is
**	essentially an array of token-handles indexed by string-handles.
**	Therefore, synonyms (strings) can be converted to the actual token.
**
**  AUTHORS:
**	J.P. Wild
**
**
**  CREATION DATE:  90.08.10
*/

# include "splintMacros.nf"
# include "basic.h"
# include "lcltokentable.h"
# include "lclsyntable.h"

static long unsigned MaxSyn;	/* size of SynTable[]              */
static /*@only@*/ /*@reldef@*/ /*@null@*/ lsymbol *SynTable;
static void
  AllocSynTable (void)
  /*@globals SynTable, MaxSyn@*/
  /*@modifies *SynTable, MaxSyn@*/;

void
LCLAddSyn (lsymbol ntok, lsymbol otok)
{
  while (otok >= MaxSyn)
    {
      /* No more space available.  Allocate more. */
      AllocSynTable ();
    }

  llassert (SynTable != NULL);

  if (SynTable[ntok] == 0)
    {
     /* Entry is empty. Fill it in. */
      SynTable[ntok] = otok;

      /* Mark oldToken as having a synonym. */
      LCLSetTokenHasSyn (otok, TRUE);
    }
  else
    {
      llbuglit ("LCLAddSyn: invalid argument");
    }
}

/*@exposed@*/ ltoken
LCLGetTokenForSyn (lsymbol ntok)
{
  llassert (SynTable != NULL);

  if (!((ntok < MaxSyn) || (SynTable[ntok] != 0)))
    llbuglit ("LCLGetSyn: bad argument");

  return LCLGetToken (SynTable[ntok]);
}

bool
LCLIsSyn (lsymbol str)
{
  if (MaxSyn == 0)
    {
      return FALSE;
    }
  else
    {
      llassert (SynTable != NULL);

      if (str < MaxSyn)
	{
	  /* Check for synonym entry in table. */
	  return (SynTable[str] != 0);
	}
      else
	{
	  /* No token for synonym.  Return FALSE. */
	  return FALSE;
	}
    }
}
  
static void
AllocSynTable (void) /*@globals SynTable; @*/
{
  long unsigned newSize, oldSize;
  long unsigned int i;

  oldSize = MaxSyn;

  if (oldSize == 0)
    {
      /* First time SynTable allocated.  Set initial size. */
      newSize = INITSYNTABLE;
      SynTable = (lsymbol *) dmalloc 
	(size_fromLongUnsigned (newSize * sizeof (*SynTable)));
    }
  else
    {
      lsymbol *oldSynTable = SynTable; 

      llassert (oldSynTable != NULL);

      /* Synonym table already allocated.  Calulate extension size. */
      newSize = (unsigned long) (DELTASYNTABLE * oldSize);
      SynTable = (lsymbol *) dmalloc 
	(size_fromLongUnsigned (newSize * sizeof (*SynTable)));

      for (i = 0; i < oldSize; i++)
	{
	  SynTable[i] = oldSynTable[i];
	}
      
      sfree (oldSynTable);
    }

  /* Zero out new allocated space.  Need to detect when cells are empty     */
  /* and do this by checking that SynTable[x] == 0.			    */

  /* ###  Should the "for" loop be replaced with the following?	            */
  /* # include <string.h>;						    */
  /*									    */
  /* memset (SynTable[oldSize], 0,					    */
  /*	      (newSize - oldSize) * sizeof (*SynTable));	            */
  
  for (i = oldSize; i < newSize; i++)
    {
      SynTable[i] = 0;
    }

  MaxSyn = newSize;
}


void
LCLSynTableInit (void)
{
  MaxSyn = 0;
}

void
LCLSynTableReset (void)
{
}

void
LCLSynTableCleanup (void)
{
  sfree (SynTable);
  SynTable = NULL;
}
