/*
** Splint - annotation-assisted static program checker
** Copyright (C) 1994-2002 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 shared language synonym table
**
**	This table stores synonyms for the Larch Shared Language.  It is
**	essentially a array of token-handles indexed by string-handles.
**	Therefore, synonyms (strings) can be converted to the actual token.
**
**  AUTHORS:
**	J.P. Wild
*/

# include "splintMacros.nf"
# include "basic.h"
# include "tokentable.h"
# include "syntable.h"

/*@+ignorequals@*/

typedef lsymbol *lsymbolTable;

static /*@only@*/ /*@null@*/ lsymbolTable SynTable;	
static unsigned long int SynTableEntries;

static void SynTable_grow (int p_size);

/*
**++
**  FUNCTION NAME:
**
**      LSLAddSyn ()
**
**  FORMAL PARAMETERS:
**
**      otok  - token-handle for token associated with oldToken
**	ntok  - string-handle for the string to be a synonym with oldToken.
**
**  RETURN VALUE:
**
**  INVARIANTS:
**
**      A context must be established.
**
**  DESCRIPTION:
**
**    This routine inserts a synonym into the synonym table.  The synonym table
**    is used to define synonyms in the form:
**
**	    synonym oldToken newToken
**
**    The table associates the string for newToken with the token for oldToken.
**    This table is used to find the the actual token (oldToken) from a synonym
**    string (newToken).
**
**    A new SynTable is allocated when:
**	. The SynTable[] is empty (initial case)
**      . The location where to insert the synonym is not in SynTable[]
**
**  IMPLICIT INPUTS/OUTPUT:
**
**    SynTable      - (input/output) SynTable array
**
**  EXCEPTIONS:
**    A synonym already exists at the location where the it is to be added.
**
**--
*/

void
LSLAddSyn (lsymbol ntok, lsymbol otok)
{
  if (ntok >= SynTableEntries) /* was otok */
    {
      SynTable_grow (otok);
    }

  llassert (SynTable != NULL);

  if (SynTable[ntok] == (lsymbol) 0)
    {				/* Entry is empty. Fill it in. */
      SynTable[ntok] = otok;
      LSLSetTokenHasSyn (otok, TRUE);	/* Mark oldToken as having a synonym. */
    }
  else
    {
      llbuglit ("LSLAddSyn: duplicate SynTable entry");
    }
}

/*@exposed@*/ ltoken
LSLGetTokenForSyn (lsymbol ntok)
{
  llassert (SynTable != NULL);
  llassert (!(!((ntok < SynTableEntries) || (SynTable[ntok] != 0))));

  return LSLGetToken (SynTable[ntok]);
}

bool
LSLIsSyn (lsymbol str)
{
  if (str < SynTableEntries)
    {
      llassert (SynTable != NULL);
      return (SynTable[str] != 0);
    }
  else
    {
      return FALSE;
    }
}

static void
SynTable_grow (int size)
{
  int oldSize;
  int i;
  lsymbolTable oldSynTable = SynTable;
  
  llassert (oldSynTable != NULL);
  oldSize = SynTableEntries;
  
  if (size <= oldSize)
    {
      llcontbuglit ("SynTable_grow: goal size is smaller than oldSize");
      return;
    }
  
  if (size < (oldSize + SYNTABLE_BASESIZE))
    {
      size = oldSize + SYNTABLE_BASESIZE;
    }

  SynTable = (lsymbolTable) dmalloc (size * sizeof (*SynTable));
  SynTableEntries = size;

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

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

  /*@+loopexec@*/
  for (i = oldSize; i < size; i++)
    {
      SynTable[i] = (lsymbol) 0;
    }
  /*@=loopexec@*/

  sfree (oldSynTable);
/*@-compdef@*/ } /*=compdef@*/

void
lsynTableInit (void) /*@globals undef SynTable; @*/
{
  int i;

  SynTable = (lsymbolTable) dmalloc (sizeof (*SynTable) * SYNTABLE_BASESIZE);

  /*@+loopexec@*/
  for (i = 0; i < SYNTABLE_BASESIZE; i++)
    {
      SynTable[i] = (lsymbol) 0;
    }
  /*@=loopexec@*/

  SynTableEntries = SYNTABLE_BASESIZE;
/*@-compdef@*/ } /*@=compdef@*/

void
lsynTableReset (void)
{
}

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












