/*
** 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
*/
/*
** lslinit.c
**
** Processor for Larch Shared Language Init Files
*/

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

# include "lslscanline.h"
# include "lslinit.h"
# include "shift.h"

# include "lclscan.h"
# include "lclscanline.h"
# include "lcltokentable.h"
# include "lclsyntable.h"
# include "lclinit.h"

# include "llgrammar.h"

# if 0
/*@notfunction@*/
# define TRACE(rule) printf ("Reducing: %s\n", rule)
# else
/*@notfunction@*/
# define TRACE(rule)
# endif

static /*@dependent@*/ ltoken nextToken;
static void InitLines (void) /*@modifies nextToken@*/ ;
static void InitLine (void) /*@modifies nextToken@*/;
static void Classification (void) /*@modifies nextToken@*/;
static void CharClass (void) /*@modifies nextToken@*/;

static void EndCommentChars (void) /*@modifies nextToken@*/ ;
static void IdChars (void) /*@modifies nextToken@*/ ;
static void OpChars (void) /*@modifies nextToken@*/ ;
static void ExtensionChar (void) /*@modifies nextToken@*/ ;
static void SingChars (void) /*@modifies nextToken@*/ ;
static void WhiteChars (void) /*@modifies nextToken@*/ ;
static void EndCommentChar (void) /*@modifies nextToken@*/ ;
static void IdChar (void) /*@modifies nextToken@*/ ;
static void OpChar (void) /*@modifies nextToken@*/ ;
static void SingChar (void) /*@modifies nextToken@*/ ;
static void WhiteChar (void) /*@modifies nextToken@*/ ;

static void TokenClass (void) /*@modifies nextToken@*/ ;
static void QuantifierSymToks (void) /*@modifies nextToken@*/ ;
static void LogicalOpToks (void) /*@modifies nextToken@*/ ;
static void EqOpToks (void) /*@modifies nextToken@*/ ;
static void EquationSymToks (void) /*@modifies nextToken@*/ ;
static void EqSepSymToks (void) /*@modifies nextToken@*/ ;
static void SelectSymToks (void) /*@modifies nextToken@*/ ;
static void OpenSymToks (void) /*@modifies nextToken@*/ ;
static void SepSymToks (void) /*@modifies nextToken@*/ ;
static void CloseSymToks (void) /*@modifies nextToken@*/ ;
static void SimpleIdToks (void) /*@modifies nextToken@*/ ;
static void MapSymToks (void) /*@modifies nextToken@*/ ;
static void MarkerSymToks (void) /*@modifies nextToken@*/ ;
static void CommentSymToks (void) /*@modifies nextToken@*/ ;
static void QuantifierSymTok (void) /*@modifies nextToken@*/ ;
static void LogicalOpTok (void) /*@modifies nextToken@*/ ;
static void EqOpTok (void) /*@modifies nextToken@*/ ;
static void EquationSymTok (void) /*@modifies nextToken@*/ ;
static void EqSepSymTok (void) /*@modifies nextToken@*/ ;
static void SelectSymTok (void) /*@modifies nextToken@*/ ;
static void OpenSymTok (void) /*@modifies nextToken@*/ ;
static void SepSymTok (void) /*@modifies nextToken@*/ ;
static void CloseSymTok (void) /*@modifies nextToken@*/ ;
static void SimpleIdTok (void) /*@modifies nextToken@*/ ;
static void MapSymTok (void) /*@modifies nextToken@*/ ;
static void MarkerSymTok (void) /*@modifies nextToken@*/ ;
static void CommentSymTok (void) /*@modifies nextToken@*/ ;
static void SynClass (void) /*@modifies nextToken@*/ ;
static void OldToken (void) /*@modifies nextToken@*/ ;
static void NewToken (void) /*@modifies nextToken@*/ ;
static void Token (void) /*@modifies nextToken@*/ ;

static void InitReduce (LCLInitRuleCode p_rule) /*@modifies nextToken@*/ ;
static void UpdateXCharKeywords (charCode p_xChar) /*@modifies nextToken@*/ ;
static void ProcessExtensionChar (void) /*@modifies nextToken@*/ ;
static void ProcessEndCommentChar (void) /*@modifies nextToken@*/ ;
static void ProcessSingleChar (charCode p_code) /*@modifies nextToken@*/ ;
static void ProcessToken (ltokenCode p_code) /*@modifies nextToken@*/ ;
static void ProcessSynonym (void) /*@modifies nextToken@*/ ;

static void
  LocalUserError (/*@unused@*/ ltoken p_t, /*@temp@*/ char *p_msg)
  /*@modifies *g_warningstream@*/ ;

/* If TRUE character has been redefined as a singleChar. */
static bool defineSingleChar[LASTCHAR + 1];

static charCode currentExtensionChar;

/* LSL init file keyword tokens.  */

static /*@exposed@*/ ltoken endCommentCharToken;
static /*@exposed@*/ ltoken idCharToken;
static /*@exposed@*/ ltoken opCharToken;
static /*@exposed@*/ ltoken extensionCharToken;
static /*@exposed@*/ ltoken singleCharToken;
static /*@exposed@*/ ltoken whiteCharToken;

static /*@exposed@*/ ltoken quantifierSymToken;
static /*@exposed@*/ ltoken logicalOpToken;
static /*@exposed@*/ ltoken eqOpToken;
static /*@exposed@*/ ltoken equationSymToken;
static /*@exposed@*/ ltoken eqSepSymToken;
static /*@exposed@*/ ltoken selectSymToken;
static /*@exposed@*/ ltoken openSymToken;
static /*@exposed@*/ ltoken sepSymToken;
static /*@exposed@*/ ltoken closeSymToken;
static /*@exposed@*/ ltoken simpleIdToken;
static /*@exposed@*/ ltoken mapSymToken;
static /*@exposed@*/ ltoken markerSymToken;
static /*@exposed@*/ ltoken commentSymToken;

static /*@exposed@*/ ltoken synonymToken;

static /*@exposed@*/ ltoken
insertSimpleToken (char *s) /*@modifies internalState@*/ 
{
    return (LCLInsertToken (simpleId, lsymbol_fromChars (s), 0, FALSE));
}

static bool
hasFirstChar (ltoken tok) /*@*/ 
{
  return (ltoken_isChar (tok)
	  && ltoken_isSingleChar (cstring_firstChar (ltoken_unparse (tok))));
}

void
lclinit_process (void)
{
  InitLines ();

  InitReduce (INITFILE1);

  if (ltoken_getCode (nextToken) != LEOFTOKEN)
    {
      LocalUserError (nextToken, "unexpected tokens after end-of-file");
    }
}

static void
InitLines (void)
{
  setCodePoint ();
  InitReduce (INITLINES1);

  if (ltoken_getCode (nextToken) != LEOFTOKEN)
    {
      InitLine ();
      InitReduce (INITLINES2);
    }

  while (ltoken_getCode (nextToken) != LEOFTOKEN)
    {
      InitLine ();
      InitReduce (INITLINES3);
    }
}

static void
InitLine (void)
{
  if (ltoken_getCode (nextToken) == LLT_EOL)
    {
      /* Nothing on line. */
      InitReduce (INITLINE1);
    }
  else
    {
      Classification ();
      InitReduce (INITLINE2);
    }

  if (ltoken_getCode (nextToken) != LLT_EOL)
    {
      LocalUserError (nextToken, "Unexpected tokens on line");
    }
  
  nextToken = LCLScanNextToken (); /* Discard EOL	*/
}

static void
Classification (void)
{
  lsymbol ntext = ltoken_getRawText (nextToken);  
    
  if (ntext == ltoken_getText (endCommentCharToken)
      || ntext == ltoken_getText (idCharToken)
      || ntext == ltoken_getText (opCharToken)
      || ntext == ltoken_getText (extensionCharToken)
      || ntext == ltoken_getText (singleCharToken)
      || ntext == ltoken_getText (whiteCharToken))
    {
      CharClass ();
      InitReduce (CLASSIFICATION1);
    }
  else if (ntext == ltoken_getText (quantifierSymToken)
	   || ntext == ltoken_getText (logicalOpToken)
	   || ntext == ltoken_getText (eqOpToken)
	   || ntext == ltoken_getText (equationSymToken)
	   || ntext == ltoken_getText (eqSepSymToken)
	   || ntext == ltoken_getText (selectSymToken)
	   || ntext == ltoken_getText (openSymToken)
	   || ntext == ltoken_getText (sepSymToken)
	   || ntext == ltoken_getText (closeSymToken)
	   || ntext == ltoken_getText (simpleIdToken)
	   || ntext == ltoken_getText (mapSymToken)
	   || ntext == ltoken_getText (markerSymToken)
	   || ntext == ltoken_getText (commentSymToken))
    {
      TokenClass ();
      InitReduce (CLASSIFICATION2);
    }
  else if (ntext == ltoken_getText (synonymToken))
    {
      SynClass ();
      InitReduce (CLASSIFICATION3);
    }
  else
    {
      llbug (message ("Expected character, token, or synonym classification: %s",
		      ltoken_getRawString (nextToken)));
      /* pop off all tokens on this line */
    }
}

static void
CharClass (void)
{
  ltoken charClassToken;
  charClassToken = nextToken;
  nextToken = LCLScanNextToken ();		/* Discard char class keyword. */

  if (ltoken_getRawText (charClassToken) == ltoken_getText (endCommentCharToken))
    {
      EndCommentChars ();
      InitReduce (CHARCLASS1);
    }
  else if (ltoken_getRawText (charClassToken) == ltoken_getText (idCharToken))
    {
      IdChars ();
      InitReduce (CHARCLASS2);
    }
  else if (ltoken_getRawText (charClassToken) == ltoken_getText (opCharToken))
    {
      OpChars ();
      InitReduce (CHARCLASS3);
    }
  else if (ltoken_getRawText (charClassToken)
	   == ltoken_getText (extensionCharToken))
    {
      ExtensionChar ();
      InitReduce (CHARCLASS4);
    }
  else if (ltoken_getRawText (charClassToken) == ltoken_getText (singleCharToken))
    {
      SingChars ();
      InitReduce (CHARCLASS5);
    }
  else if (ltoken_getRawText (charClassToken) == ltoken_getText (whiteCharToken))
    {
      WhiteChars ();
      InitReduce (CHARCLASS6);
    }
  else
    {
      LocalUserError (nextToken, "expected character classification");
    }
}

static void
EndCommentChars (void)
{
  EndCommentChar ();
  InitReduce (LRC_ENDCOMMENT1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      EndCommentChar ();
      InitReduce (LRC_ENDCOMMENT2);
    }

}

static void IdChars (void) /*@modifies nextToken@*/
{
  IdChar ();
  InitReduce (IDCHARS1);
  
  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      IdChar ();
      InitReduce (IDCHARS2);
    }
}

static void OpChars (void) /*@modifies nextToken@*/
{
  OpChar ();
  InitReduce (OPCHARS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      OpChar ();
      InitReduce (OPCHARS2);
    }
}

static void ExtensionChar (void) /*@modifies nextToken@*/
{
  if (hasFirstChar (nextToken))
    {
      LSLGenShift (nextToken);
      nextToken = LCLScanNextToken ();
      InitReduce (LRC_EXTENSIONCHAR1);
    }
  else
    {
      LocalUserError (nextToken, "expected only one character");
    }
}

static void SingChars (void) /*@modifies nextToken@*/
{
  SingChar ();
  InitReduce (SINGCHARS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      SingChar ();
      InitReduce (SINGCHARS2);
    }
}

static void WhiteChars (void) /*@modifies nextToken@*/
{
  WhiteChar ();
  InitReduce (WHITECHARS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      WhiteChar ();
      InitReduce (WHITECHARS2);
    }
}

static void EndCommentChar (void) /*@modifies nextToken@*/
{
  if (ltoken_isChar (nextToken))
    {
      LSLGenShift (nextToken);
      nextToken = LCLScanNextToken ();
      InitReduce (LRC_ENDCOMMENTCHAR1);
    }
  else
    {
      LocalUserError (nextToken, "expected only one character");
    }
}

static void IdChar (void) /*@modifies nextToken@*/
{
  if (hasFirstChar (nextToken))
    {
      LSLGenShift (nextToken);
      nextToken = LCLScanNextToken ();
      InitReduce (IDCHAR1);
    }
  else
    {
      LocalUserError (nextToken,
		      "Character is already defined, cannot redefine");
    }
}

static void OpChar (void) /*@modifies nextToken@*/
{
  if (hasFirstChar (nextToken))
    {
      LSLGenShift (nextToken);
      nextToken = LCLScanNextToken ();
      InitReduce (OPCHAR1);
    }
  else
    {
      LocalUserError (nextToken, 
		      "Character is already defined, cannot redefine");
    }
}

static void SingChar (void) /*@modifies nextToken@*/
{
  if (hasFirstChar (nextToken))
    {
      LSLGenShift (nextToken);
      nextToken = LCLScanNextToken ();
      InitReduce (SINGCHAR1);
    }
  else
    {
      LocalUserError (nextToken, 
		      "Character is already defined, cannot redefine");
    }
}

static void WhiteChar (void) /*@modifies nextToken@*/
{
  if (hasFirstChar (nextToken))
    {
      LSLGenShift (nextToken);
      nextToken = LCLScanNextToken ();
      InitReduce (WHITECHAR1);
    }
  else
    {
      LocalUserError (nextToken, "Character is already defined, cannot redefine");
    }
}

static void
TokenClass (void) /*@modifies nextToken@*/
{
  lsymbol ttext = ltoken_getRawText (nextToken);

  /* Discard token class keyword. */
  nextToken = LCLScanNextToken ();

  if (ttext == ltoken_getText (quantifierSymToken))
    {
      QuantifierSymToks ();
      InitReduce (TOKENCLASS1);
    }
  else if (ttext == ltoken_getText (logicalOpToken))
    {
      LogicalOpToks ();
      InitReduce (TOKENCLASS2);
    }
  else if (ttext == ltoken_getText (eqOpToken))
    {
      EqOpToks ();
      InitReduce (TOKENCLASS3);
    }
  else if (ttext == ltoken_getText (equationSymToken))
    {
      EquationSymToks ();
      InitReduce (TOKENCLASS4);
    }
  else if (ttext == ltoken_getText (eqSepSymToken))
    {
      EqSepSymToks ();
      InitReduce (TOKENCLASS5);
    }
  else if (ttext == ltoken_getText (selectSymToken))
    {
      SelectSymToks ();
      InitReduce (TOKENCLASS6);
    }
  else if (ttext == ltoken_getText (openSymToken))
    {
      OpenSymToks ();
      InitReduce (TOKENCLASS7);
    }
  else if (ttext == ltoken_getText (sepSymToken))
    {
      SepSymToks ();
      InitReduce (TOKENCLASS8);
    }
  else if (ttext == ltoken_getText (closeSymToken))
    {
      CloseSymToks ();
      InitReduce (TOKENCLASS9);
    }
  else if (ttext == ltoken_getText (simpleIdToken))
    {
      SimpleIdToks ();
      InitReduce (TOKENCLASS10);
    }
  else if (ttext == ltoken_getText (mapSymToken))
    {
      MapSymToks ();
      InitReduce (TOKENCLASS11);
    }
  else if (ttext == ltoken_getText (markerSymToken))
    {
      MarkerSymToks ();
      InitReduce (TOKENCLASS12);
    }
  else if (ttext == ltoken_getText (commentSymToken))
    {
            CommentSymToks ();
      InitReduce (TOKENCLASS13);
    }
  else
    {
      LocalUserError (nextToken, "expected token classification");
    }
}

static void
QuantifierSymToks (void) /*@modifies nextToken@*/
{
  QuantifierSymTok ();
  InitReduce (QUANTIFIERSYMTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      QuantifierSymTok ();
      InitReduce (QUANTIFIERSYMTOKS2);
    }
}

static void
LogicalOpToks (void) /*@modifies nextToken@*/
{
  LogicalOpTok ();
  InitReduce (LOGICALOPTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      LogicalOpTok ();
      InitReduce (LOGICALOPTOKS2);
    }
}

static void
EqOpToks (void) /*@modifies nextToken@*/
{
  EqOpTok ();
  InitReduce (LRC_EQOPTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      EqOpTok ();
      InitReduce (LRC_EQOPTOKS2);
    }
}

static void
EquationSymToks (void) /*@modifies nextToken@*/
{
  EquationSymTok ();
  InitReduce (LRC_EQUATIONSYMTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      EquationSymTok ();
      InitReduce (LRC_EQUATIONSYMTOKS2);
    }
}

static void
EqSepSymToks (void) /*@modifies nextToken@*/
{
  EqSepSymTok ();
  InitReduce (LRC_EQSEPSYMTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      EqSepSymTok ();
      InitReduce (LRC_EQSEPSYMTOKS2);
    }
}

static void
SelectSymToks (void) /*@modifies nextToken@*/
{
  SelectSymTok ();
  InitReduce (SELECTSYMTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      SelectSymTok ();
      InitReduce (SELECTSYMTOKS2);
    }
}

static void
OpenSymToks (void) /*@modifies nextToken@*/
{
  OpenSymTok ();
  InitReduce (OPENSYMTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      OpenSymTok ();
      InitReduce (OPENSYMTOKS2);
    }
}

static void
SepSymToks (void) /*@modifies nextToken@*/
{
  SepSymTok ();
  InitReduce (SEPSYMTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      SepSymTok ();
      InitReduce (SEPSYMTOKS2);
    }
}

static void
CloseSymToks (void) /*@modifies nextToken@*/
{
  CloseSymTok ();
  InitReduce (CLOSESYMTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      CloseSymTok ();
      InitReduce (CLOSESYMTOKS2);
    }
}

static void
SimpleIdToks (void) /*@modifies nextToken@*/
{ 
  SimpleIdTok ();
  InitReduce (SIMPLEIDTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      SimpleIdTok ();
      InitReduce (SIMPLEIDTOKS2);
    }
}

static void
MapSymToks (void) /*@modifies nextToken@*/
{
  MapSymTok ();
  InitReduce (MAPSYMTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      MapSymTok ();
      InitReduce (MAPSYMTOKS2);
    }
}

static void
MarkerSymToks (void) /*@modifies nextToken@*/
{
  MarkerSymTok ();
  InitReduce (MARKERSYMTOKS1);

  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
      MarkerSymTok ();
      InitReduce (MARKERSYMTOKS2);
    }
}

static void
CommentSymToks (void) /*@modifies nextToken@*/
{
  CommentSymTok ();
    InitReduce (COMMENTSYMTOKS1);
  
  while (ltoken_getCode (nextToken) != LLT_EOL)
    {
            CommentSymTok ();
            InitReduce (COMMENTSYMTOKS2);
    }
}

static void
QuantifierSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (QUANTIFIERSYMTOK1);
}

static void
LogicalOpTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (LOGICALOPTOK1);
}

static void
EqOpTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (LRC_EQOPTOK1);
}

static void EquationSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (LRC_EQUATIONSYMTOK1);
}

static void EqSepSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (LRC_EQSEPSYMTOK1);

}

static void SelectSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (SELECTSYMTOK1);
}

static void OpenSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (OPENSYMTOK1);
}

static void SepSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (SEPSYMTOK1);
}

static void CloseSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (CLOSESYMTOK1);
}

static void SimpleIdTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (SIMPLEIDTOK1);
}

static void
MapSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (MAPSYMTOK1);
}

static void
MarkerSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (MARKERSYMTOK1);

}

static void
CommentSymTok (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (COMMENTSYMTOK1);
}


static void
SynClass (void) /*@modifies nextToken@*/
{
  if (ltoken_getRawText (nextToken) == ltoken_getText (synonymToken))
    {
      nextToken = LCLScanNextToken ();

      OldToken ();
      NewToken ();

      InitReduce (SYNCLASS1);
    }
  else
    {
      LocalUserError (nextToken, "expected synonym classification");
    }

}

static void
OldToken (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (OLDTOKEN1);

}

static void
NewToken (void) /*@modifies nextToken@*/
{
  Token ();
  InitReduce (NEWTOKEN1);

}

static void
Token (void) /*@modifies nextToken@*/
{
  if (ltoken_getCode (nextToken) == LLT_EOL
      || ltoken_getCode (nextToken) == LEOFTOKEN)
    {
      LocalUserError (nextToken, "unexpected end-of-line or end-of-file");
    }
  else
    {
      LSLGenShift (nextToken);
      nextToken = LCLScanNextToken ();
    }
}

/*
** Init File Processing Routines, these routines use the shift-reduce sequence
** produced by the init file parser and update the necessary tables for the
** scanner.
**
** The same shift stack is used that LSL parser uses.  A different reduce
** procedure is used because the init file grammar is different from the LSL
** grammar.
*/

static void
InitReduce (LCLInitRuleCode rule) /*@modifies nextToken@*/
{
  switch (rule)
    {
    case INITFILE1:
      TRACE ("INITFILE1");
      break;
      
    case INITLINES1:
      TRACE ("INITLINES1");
      break;
      
    case INITLINES2:
      TRACE ("INITLINES2");
      break;

    case INITLINES3:
      TRACE ("INITLINES3");
      break;

    case INITLINE1:
      TRACE ("INITLINE1");
      break;

    case INITLINE2:
      TRACE ("INITLINE2");
      break;

    case CLASSIFICATION1:
      TRACE ("CLASSIFICATION1");
      break;

    case CLASSIFICATION2:
      TRACE ("CLASSIFICATION2");
      break;

    case CLASSIFICATION3:
      TRACE ("CLASSIFICATION3");
      break;

    case CHARCLASS1:
      TRACE ("CHARCLASS1");
      break;

    case CHARCLASS2:
      TRACE ("CHARCLASS2");
      break;

    case CHARCLASS3:
      TRACE ("CHARCLASS3");
      break;

    case CHARCLASS4:
      TRACE ("CHARCLASS4");
      break;

    case CHARCLASS5:
      TRACE ("CHARCLASS5");
      break;

    case CHARCLASS6:
      TRACE ("CHARCLASS6");
      break;

    case LRC_ENDCOMMENT1:
      TRACE ("LRC_ENDCOMMENT1");
      break;

    case LRC_ENDCOMMENT2:
      TRACE ("LRC_ENDCOMMENT2");
      break;

    case IDCHARS1:
      TRACE ("IDCHARS1");
      break;

    case IDCHARS2:
      TRACE ("IDCHARS2");
      break;

    case OPCHARS1:
      TRACE ("OPCHARS1");
      break;

    case OPCHARS2:
      TRACE ("OPCHARS2");
      break;

    case LRC_EXTENSIONCHAR1:
      TRACE ("LRC_EXTENSIONCHAR1");
      ProcessExtensionChar ();
      break;

    case SINGCHARS1:
      TRACE ("SINGCHARS1");
      break;

    case SINGCHARS2:
      TRACE ("SINGCHARS2");
      break;

    case WHITECHARS1:
      TRACE ("WHITECHARS1");
      break;

    case WHITECHARS2:
      TRACE ("WHITECHARS2");
      break;

    case LRC_ENDCOMMENTCHAR1:
      TRACE ("LRC_ENDCOMMENTCHAR1");
      ProcessEndCommentChar ();
      break;

    case IDCHAR1:
      TRACE ("IDCHAR1");
      ProcessSingleChar (IDCHAR);
      break;

    case OPCHAR1:
      TRACE ("OPCHAR1");
      ProcessSingleChar (OPCHAR);
      break;

    case SINGCHAR1:
      TRACE ("SINGCHAR1");
      ProcessSingleChar (SINGLECHAR);
      break;

    case WHITECHAR1:
      TRACE ("CHAR1");
      ProcessSingleChar (WHITECHAR);
      break;

    case TOKENCLASS1:
      TRACE ("TOKENCLASS1");
      break;

    case TOKENCLASS2:
      TRACE ("TOKENCLASS2");
      break;

    case TOKENCLASS3:
      TRACE ("TOKENCLASS3");
      break;

    case TOKENCLASS4:
      TRACE ("TOKENCLASS4");
      break;

    case TOKENCLASS5:
      TRACE ("TOKENCLASS5");
      break;

    case TOKENCLASS6:
      TRACE ("TOKENCLASS6");
      break;

    case TOKENCLASS7:
      TRACE ("TOKENCLASS7");
      break;

    case TOKENCLASS8:
      TRACE ("TOKENCLASS8");
      break;

    case TOKENCLASS9:
      TRACE ("TOKENCLASS9");
      break;

    case TOKENCLASS10:
      TRACE ("TOKENCLASS10");
      break;

    case TOKENCLASS11:
      TRACE ("TOKENCLASS11");
      break;

    case TOKENCLASS12:
      TRACE ("TOKENCLASS12");
      break;

    case TOKENCLASS13:
      TRACE ("TOKENCLASS13");
      break;

    case QUANTIFIERSYMTOKS1:
      TRACE ("QUALIFERSYMTOKS1");
      break;

    case QUANTIFIERSYMTOKS2:
      TRACE ("QUANTIFIERSYMTOKS2");
      break;

    case LOGICALOPTOKS1:
      TRACE ("LOGICALOPTOKS1");
      break;

    case LOGICALOPTOKS2:
      TRACE ("LOGICALOPTOKS2");
      break;

    case LRC_EQOPTOKS1:
      TRACE ("LRC_EQOPTOKS1");
      break;

    case LRC_EQOPTOKS2:
      TRACE ("LRC_EQOPTOKS2");
      break;

    case LRC_EQUATIONSYMTOKS1:
      TRACE ("LRC_EQUATIONSYMTOKS1");
      break;

    case LRC_EQUATIONSYMTOKS2:
      TRACE ("LRC_EQUATIONSYMTOKS2");
      break;

    case LRC_EQSEPSYMTOKS1:
      TRACE ("LRC_EQSEPSYMTOKS1");
      break;

    case LRC_EQSEPSYMTOKS2:
      TRACE ("LRC_EQSEPSYMTOKS2");
      break;

    case SELECTSYMTOKS1:
      TRACE ("SELECTSYMTOKS1");
      break;

    case SELECTSYMTOKS2:
      TRACE ("SELECTSYMTOKS2");
      break;

    case OPENSYMTOKS1:
      TRACE ("OPENSYMTOKS1");
      break;

    case OPENSYMTOKS2:
      TRACE ("OPENSYMTOKS2");
      break;

    case SEPSYMTOKS1:
      TRACE ("SEPSYMTOKS1");
      break;

    case SEPSYMTOKS2:
      TRACE ("SEPSYMTOKS2");
      break;

    case CLOSESYMTOKS1:
      TRACE ("CLOSESYMTOKS1");
      break;

    case CLOSESYMTOKS2:
      TRACE ("CLOSESYMTOKS2");
      break;

    case SIMPLEIDTOKS1:
      TRACE ("SIMPLEIDTOKS1");
      break;

    case SIMPLEIDTOKS2:
      TRACE ("SIMPLEIDTOKS2");
      break;

    case MAPSYMTOKS1:
      TRACE ("MAPSYMTOKS1");
      break;

    case MAPSYMTOKS2:
      TRACE ("MAPSYMTOKS2");
      break;

    case MARKERSYMTOKS1:
      TRACE ("MARKERSYMTOKS1");
      break;

    case MARKERSYMTOKS2:
      TRACE ("MARKERSYMTOKS2");
      break;

    case COMMENTSYMTOKS1:
      TRACE ("COMMENTSYMTOKS1");
      break;

    case COMMENTSYMTOKS2:
      TRACE ("COMMENTSYMTOKS2");
      break;

    case QUANTIFIERSYMTOK1:
      TRACE ("QUANTIFERSYMTOK1");
      ProcessToken (quantifierSym);
      break;

    case LOGICALOPTOK1:
      TRACE ("LOGICALOPTOK1");
      ProcessToken (logicalOp);
      break;

    case LRC_EQOPTOK1:
      TRACE ("LRC_EQOPTOK1");
      ProcessToken (eqOp);
      break;

    case LRC_EQUATIONSYMTOK1:
      TRACE ("LRC_EQUATIONSYMTOK1");
      ProcessToken (equationSym);
      break;

    case LRC_EQSEPSYMTOK1:
      TRACE ("LRC_EQSEPSYMTOK1");
      ProcessToken (eqSepSym);
      break;

    case SELECTSYMTOK1:
      TRACE ("SELECTSYMTOK1");
      ProcessToken (selectSym);
      break;

    case OPENSYMTOK1:
      TRACE ("OPENSYMTOK1");
      ProcessToken (openSym);
      break;

    case SEPSYMTOK1:
      TRACE ("SEPSYMTOK1");
      ProcessToken (sepSym);
      break;

    case CLOSESYMTOK1:
      TRACE ("CLOSESYMTOK1");
      ProcessToken (closeSym);
      break;

    case SIMPLEIDTOK1:
      TRACE ("SIMPLEIDTOK1");
      ProcessToken (simpleId);
      break;

    case MAPSYMTOK1:
      TRACE ("MAPSYMTOK1");
      ProcessToken (mapSym);
      break;

    case MARKERSYMTOK1:
      TRACE ("MARKERSYMTOK1");
      ProcessToken (markerSym);
      break;

    case COMMENTSYMTOK1:
      TRACE ("COMMENTSYMTOK1");
      ProcessToken (commentSym);
      break;

    case SYNCLASS1:
      TRACE ("SYNCLASS1");
      ProcessSynonym ();
      break;

    case OLDTOKEN1:
      TRACE ("OLDTOKEN1");
      break;

    case NEWTOKEN1:
      TRACE ("NEWTOKEN1");
      break;

    default:
      llcontbuglit ("InitReduce: bad case");
      break;
    }
}	

/*
** Reset the first character of the predefined extensionChar keywords when  
** the extensionChar changes.  e.g. "extensionChar @" changes "\forall" to  
** "@forall".								    
*/

static void
UpdateXCharKeywords (charCode xChar)
{
  char *str;
  char xchar = (char)xChar;

  str = ltoken_getTextChars (ltoken_forall);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_and);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_or);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_implies);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_eq);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_neq);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_equals);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_eqsep);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_select);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_open);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_sep);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_close);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_id);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_arrow);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_marker);
  *str = xchar;

  str = ltoken_getTextChars (ltoken_comment);
  *str = xchar;
}

/* Different from ProcessCharClass because only allow one extension	    */
/* character. Therefore, the present extension character must be set to a   */
/* singleChar.								    */

static void
ProcessExtensionChar (void)
{
  ltoken stackToken = LSLGenTopPopShiftStack ();
  char firstChar = cstring_firstChar (ltoken_unparse (stackToken));

  if (!defineSingleChar[(int)firstChar]
      && ltoken_isSingleChar (firstChar))
    {
      /*
      ** Is a single character that has not been defined before.	   
      ** Can only have one extension char.  Release old one. 
      */

      LCLSetCharClass (firstChar, CHC_EXTENSION);
      LCLSetCharClass ((char) currentExtensionChar, SINGLECHAR);
      currentExtensionChar = (charCode) firstChar;
      UpdateXCharKeywords (currentExtensionChar);
    }
  else
    {
      /* Already redefined.  Don't allow to be redefined. */
      LocalUserError (stackToken, "Character is already defined, cannot redefine");
    }

  ltoken_free (stackToken);
}

/* Different from ProcessSingleChar because allow any characters to be	    */
/* endCommentChar and also set a different part of the scanner structure.   */

static void
ProcessEndCommentChar (void)
{
  ltoken stackToken = LSLGenTopPopShiftStack ();
  char firstChar = cstring_firstChar (ltoken_unparse (stackToken));

  if (LCLIsEndComment (firstChar))
    {
      LocalUserError (stackToken,
		    "already defined as a endCommentChar, cannot redefine");
    }
  else
    {
      LCLSetEndCommentChar (firstChar, TRUE);
    }
  ltoken_free (stackToken);
}

static void
ProcessSingleChar (charCode code)
{
  ltoken stackToken = LSLGenTopPopShiftStack ();
  char firstChar = cstring_firstChar (ltoken_unparse (stackToken));

  if (!defineSingleChar[(int)firstChar]
      && ltoken_isSingleChar (firstChar))
    {
      /* Is a single character that has not been defined before.	    */
      /* It's OK to redefine once. */
      LCLSetCharClass (firstChar, code);
      /* OK to mark as a defined singleChar even if not.  Only check	    */
      /* defineSingleChar[] if defining a singleChar.			    */
      defineSingleChar[(int)(firstChar)] = TRUE;
    }
  else
    {
      LocalUserError (stackToken, "Character is already defined, cannot redefine");
    }
  
  ltoken_free (stackToken);
}

static void
ProcessToken (ltokenCode code)
{
  ltoken stackToken, ptok;

  stackToken = LSLGenTopPopShiftStack ();

  
  if (LCLIsSyn (ltoken_getText (stackToken)))
    {
      LocalUserError (stackToken, "already defined as a synonym, cannot redefine");
    }

  /*
  ** Get the token from the token table, so can check if the token    
  ** was updated by a previous token.				    
  */

  ptok = LCLGetToken (ltoken_getText (stackToken));

  if (ltoken_isStateDefined (ptok))
    {
            LocalUserError (stackToken, "already defined, cannot redefine");
    }

    LCLUpdateToken (code, ltoken_getText (stackToken), TRUE);
  ltoken_free (stackToken);
}


static void
ProcessSynonym (void)
{
  ltoken newtok;
  ltoken oldtok;

  
  newtok = LSLGenTopPopShiftStack ();
  oldtok = LSLGenTopPopShiftStack ();

  
 /* ignore synonyms: Bool -> bool
    and:             bool -> Bool */
 /*
     if ((ltoken_getText (newtok) == lsymbol_Bool ||
          ltoken_getText (newtok) == lsymbol_bool) &&
         (ltoken_getText (oldtok) == lsymbol_Bool ||
          ltoken_getText (oldtok) == lsymbol_bool)) return;
 */

  if (ltoken_wasSyn (newtok))
    {
     /*
     ** The token has a synonym.  This means that the synonym was in the 
     ** init file, so complain about redefining as a synonym again	 
     */

      LocalUserError (newtok, "already is a synonym, cannot redefine");
    }

  if (ltoken_hasSyn (newtok))
    {
      /*
      ** newtok already has a synonym defined for it.  Do not allow	   
      ** synonyms to be chained.					    
      */

      LocalUserError (newtok,
		      "newtok already has a synonym, cannot chain synonyms");
    }

  if (ltoken_isStateDefined (newtok))
    {
      LocalUserError (newtok, "newtok already defined, cannot redefine");
    }

    LCLAddSyn (ltoken_getText (newtok), ltoken_getText (oldtok));

  ltoken_free (newtok);
  ltoken_free (oldtok); 
}


/*
** Utilities, in alphabetical order
*/

static void
  LocalUserError (ltoken t, char *msg)
{
  lclplainerror (message ("%s %s in the LCL init file.  Ignoring line.", 
			  ltoken_unparse (t), cstring_fromChars (msg)));

  /* discard the whole current line */

  nextToken = LCLScanNextToken ();		/* Discard bad token	*/

  while (ltoken_getCode (nextToken) != LLT_EOL 
	 && ltoken_getCode (nextToken) != LEOFTOKEN)
    {
      nextToken = LCLScanNextToken ();
    }
}


/*
 *  Required initialization and cleanup routines
 */

void
lclinit_initMod (void)
{
  int i;

  /*
  ** Insert the init file keywords into the token table as undefined	    
  ** SIMPLEIDs.  They are defined as simpleIds since they must be treated 
  ** that way if they do not appear as the first token on a line, and	    
  ** they must be treated that way for the actual LSL parsing. Save the   
  ** tokens so can recognize as init file keywords when necessary.	    
  */

  endCommentCharToken = insertSimpleToken ("endCommentChar");
  idCharToken = insertSimpleToken ("idChar");
  opCharToken = insertSimpleToken ("opChar");
  extensionCharToken = insertSimpleToken ("extensionChar");
  singleCharToken = insertSimpleToken ("singleChar");
  whiteCharToken = insertSimpleToken ("whiteChar");

  quantifierSymToken = insertSimpleToken ("quantifierSym");
  logicalOpToken = insertSimpleToken ("logicalOp");
  eqOpToken = insertSimpleToken ("eqOp");
  equationSymToken = insertSimpleToken ("equationSym");
  eqSepSymToken = insertSimpleToken ("eqSepSym");
  selectSymToken = insertSimpleToken ("selectSym");
  openSymToken = insertSimpleToken ("openSym");
  sepSymToken = insertSimpleToken ("sepSym");
  closeSymToken = insertSimpleToken ("closeSym");
  simpleIdToken = insertSimpleToken ("simpleId");
  mapSymToken = insertSimpleToken ("mapSym");
  markerSymToken = insertSimpleToken ("markerSym");
  commentSymToken = insertSimpleToken ("commentSym");

  synonymToken = insertSimpleToken ("synonym");

  /*
  ** Initialize defineSingleChar array to all FALSE to signal that no	    
  ** characters have been redefined as singleChar. 
  */

  for (i = 0; i <= LASTCHAR; i++)
    {
      defineSingleChar[i] = FALSE;
    }

  /* 
  ** Record the current extension character so can redefine back to	    
  ** singleChar if a new extension character is redefined.		    
  */

  currentExtensionChar = (charCode) CHAREXTENDER;
  
  /* Init file processing needs to have EOL reported. */

  LCLReportEolTokens (TRUE);

  /* Not: context_getBoolName () */

  LCLAddSyn (lsymbol_fromChars ("Bool"),
	     lsymbol_fromChars ("bool"));
}

void
lclinit_reset (void)
{
  nextToken = LCLScanNextToken ();	  
}

void
lclinit_cleanup (void)
{
  ;
}










