/*
** 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 "lslgrammar.h"
# include "lslscan.h"
# include "lslscanline.h"
# include "lsltokentable.h"
# include "lslsyntable.h"
# include "lslinit.h"

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

/* needed to parse init files */
# include "shift.h"

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

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

static /*@only@*/ ltoken nextToken;

static /*@only@*/ /*@null@*/ inputStream s_initFile = inputStream_undefined;

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 (LSLInitRuleCode p_rule) /*@modifies nextToken@*/ ;
static void UpdateXCharKeywords (charCode) /*@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@*/ ;

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

static charCode currentExtensionChar;

/* LSL init file keyword tokens.  */

static /*@dependent@*/ ltoken endCommentCharToken;
static /*@dependent@*/ ltoken idCharToken;
static /*@dependent@*/ ltoken opCharToken;
static /*@dependent@*/ ltoken extensionCharToken;
static /*@dependent@*/ ltoken singleCharToken;
static /*@dependent@*/ ltoken whiteCharToken;
static /*@dependent@*/ ltoken quantifierSymToken;
static /*@dependent@*/ ltoken logicalOpToken;
static /*@dependent@*/ ltoken eqOpToken;
static /*@dependent@*/ ltoken equationSymToken;
static /*@dependent@*/ ltoken eqSepSymToken;
static /*@dependent@*/ ltoken selectSymToken;
static /*@dependent@*/ ltoken openSymToken;
static /*@dependent@*/ ltoken sepSymToken;
static /*@dependent@*/ ltoken closeSymToken;
static /*@dependent@*/ ltoken simpleIdToken;
static /*@dependent@*/ ltoken mapSymToken;
static /*@dependent@*/ ltoken markerSymToken;
static /*@dependent@*/ ltoken commentSymToken;
static /*@dependent@*/ ltoken synonymToken;

static bool
hasFirstChar (ltoken tok)
{
  return (ltoken_isChar (tok)
	  && lscanCharClass (cstring_firstChar (ltoken_unparse (tok))) == SINGLECHAR);
}

void
lslinit_setInitFile (inputStream s)
{
  llassert (inputStream_isUndefined (s_initFile));
  s_initFile = s;
}

/*
**
**  Parsing functions for init file processing, in the same order as the
**  grammar file lslinit.cfg.  This is top-down order, as much as possible.
**
*/

static void lslinit_processInitFile (void)
{
  InitLines ();
  InitReduce (INITFILE1);

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

static void
InitLines (void)
{
  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) == LST_EOL)
    {
     /* Nothing on line. */
      InitReduce (INITLINE1);
    }
  else
    {
      Classification ();
      InitReduce (INITLINE2);
    }

  if (ltoken_getCode (nextToken) != LST_EOL)
    {
      LocalUserError (nextToken, "Unexpected tokens on line");
    }

  ltoken_free (nextToken);
  nextToken = LSLScanNextToken ();	       
}

static void
Classification (void)
{
  if (ltoken_getRawText (nextToken) == ltoken_getText (endCommentCharToken)
      || ltoken_getRawText (nextToken) == ltoken_getText (idCharToken)
      || ltoken_getRawText (nextToken) == ltoken_getText (opCharToken)
      || ltoken_getRawText (nextToken) == ltoken_getText (extensionCharToken)
      || ltoken_getRawText (nextToken) == ltoken_getText (singleCharToken)
      || ltoken_getRawText (nextToken) == ltoken_getText (whiteCharToken))
    {
      CharClass ();
      InitReduce (CLASSIFICATION1);
    }
  else if (ltoken_getRawText (nextToken) == ltoken_getText (quantifierSymToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (logicalOpToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (eqOpToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (equationSymToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (eqSepSymToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (selectSymToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (openSymToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (sepSymToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (closeSymToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (simpleIdToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (mapSymToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (markerSymToken)
	   || ltoken_getRawText (nextToken) == ltoken_getText (commentSymToken))
    {
      TokenClass ();
      InitReduce (CLASSIFICATION2);
    }
  else if (ltoken_getRawText (nextToken) == ltoken_getText (synonymToken))
    {
      SynClass ();
      InitReduce (CLASSIFICATION3);
    }
  else
    {
      LocalUserError (nextToken,
		      "expected character, token, or synonym classification");
    }
}

static void
CharClass (void)
{
  ltoken charClassToken;

  charClassToken = nextToken;

  nextToken = LSLScanNextToken ();		/* 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");
    }

  ltoken_free (charClassToken);
}

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

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

}

static void
IdChars (void)
{
  IdChar ();
  InitReduce (IDCHARS1);

  while (ltoken_getCode (nextToken) != LST_EOL)
    {
      IdChar ();
      InitReduce (IDCHARS2);
    }
}

static void
OpChars (void)
{
  OpChar ();
  InitReduce (OPCHARS1);

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

static void
ExtensionChar (void)
{
  if (ltoken_isChar (nextToken)
      && lscanCharClass (cstring_firstChar (ltoken_unparse (nextToken))) == SINGLECHAR)
    {
      LSLGenShiftOnly (nextToken);
      nextToken = LSLScanNextToken ();
      InitReduce (LRC_EXTENSIONCHAR1);
    }
  else
    {
      LocalUserError (nextToken, "expected only one character");
    }
}

static void
SingChars (void)
{
  SingChar ();
  InitReduce (SINGCHARS1);

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

static void
WhiteChars (void)
{
  WhiteChar ();
  InitReduce (WHITECHARS1);

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

static void
EndCommentChar (void)
{
  if (ltoken_isChar (nextToken))
    {
      LSLGenShiftOnly (nextToken);
      nextToken = LSLScanNextToken ();
      InitReduce (LRC_ENDCOMMENTCHAR1);
    }
  else
    {
      LocalUserError (nextToken, "expected only one character");
    }
}

static void
IdChar (void)
{
  if (hasFirstChar (nextToken))
    {
      LSLGenShiftOnly (nextToken);
      nextToken = LSLScanNextToken ();
      InitReduce (IDCHAR1);
    }
  else
    {
      LocalUserError (nextToken, "character is already defined, cannot redefine");
    }
}

static void
OpChar (void)
{
  if (hasFirstChar (nextToken))
    {
      LSLGenShiftOnly (nextToken);
      nextToken = LSLScanNextToken ();
      InitReduce (OPCHAR1);
    }
  else
    {
      LocalUserError (nextToken, "character is already defined, cannot redefine");
    }
}

static void
SingChar (void)
{
  if (hasFirstChar (nextToken))
    {
      LSLGenShiftOnly (nextToken);
      nextToken = LSLScanNextToken ();
      InitReduce (SINGCHAR1);
    }
  else
    {
      LocalUserError (nextToken, "character is already defined, cannot redefine");
    }
}

static void
WhiteChar (void)
{
  if (hasFirstChar (nextToken))
    {
      LSLGenShiftOnly (nextToken);
      nextToken = LSLScanNextToken ();
      InitReduce (WHITECHAR1);
    }
  else
    {
      LocalUserError (nextToken, "character is already defined, cannot redefine");
    }
}

static void
TokenClass (void)
{
  ltoken tokenClassToken;

  tokenClassToken = nextToken;

  nextToken = LSLScanNextToken ();

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

  ltoken_free (tokenClassToken);
}

static void
QuantifierSymToks (void)
{
  QuantifierSymTok ();
  InitReduce (QUANTIFIERSYMTOKS1);

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

static void
LogicalOpToks (void)
{
  LogicalOpTok ();
  InitReduce (LOGICALOPTOKS1);

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

static void
EqOpToks (void)
{
  EqOpTok ();
  InitReduce (LRC_EQOPTOKS1);

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

static void
EquationSymToks (void)
{
  EquationSymTok ();
  InitReduce (LRC_EQUATIONSYMTOKS1);

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

static void
EqSepSymToks (void)
{
  EqSepSymTok ();
  InitReduce (LRC_EQSEPSYMTOKS1);

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

static void
SelectSymToks (void)
{
  SelectSymTok ();
  InitReduce (SELECTSYMTOKS1);

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

static void
OpenSymToks (void)
{
  OpenSymTok ();
  InitReduce (OPENSYMTOKS1);

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

static void
SepSymToks (void)
{
  SepSymTok ();
  InitReduce (SEPSYMTOKS1);

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

static void
CloseSymToks (void)
{
  CloseSymTok ();
  InitReduce (CLOSESYMTOKS1);

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

static void
SimpleIdToks (void)
{
  SimpleIdTok ();
  InitReduce (SIMPLEIDTOKS1);

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

static void
MapSymToks (void)
{
  MapSymTok ();
  InitReduce (MAPSYMTOKS1);

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

static void
MarkerSymToks (void)
{
  MarkerSymTok ();
  InitReduce (MARKERSYMTOKS1);

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

static void
CommentSymToks (void)
{
  CommentSymTok ();
  InitReduce (COMMENTSYMTOKS1);

  while (ltoken_getCode (nextToken) != LST_EOL)
    {
      CommentSymTok ();
      InitReduce (COMMENTSYMTOKS2);
    }
}

static void
QuantifierSymTok (void)
{
  Token ();
  InitReduce (QUANTIFIERSYMTOK1);
}

static void
LogicalOpTok (void)
{
  Token ();
  InitReduce (LOGICALOPTOK1);
}

static void
EqOpTok (void)
{
  Token ();
  InitReduce (LRC_EQOPTOK1);
}

static void
EquationSymTok (void)
{
 /* ### EquationSymTok (); ### */
  Token ();
  InitReduce (LRC_EQUATIONSYMTOK1);
}

static void
EqSepSymTok (void)
{
  Token ();
  InitReduce (LRC_EQSEPSYMTOK1);

}

static void
SelectSymTok (void)
{
  Token ();
  InitReduce (SELECTSYMTOK1);
}

static void
OpenSymTok (void)
{
  Token ();
  InitReduce (OPENSYMTOK1);
}

static void
SepSymTok (void)
{
  Token ();
  InitReduce (SEPSYMTOK1);
}

static void
CloseSymTok (void)
{
  Token ();
  InitReduce (CLOSESYMTOK1);
}

static void
SimpleIdTok (void)
{
  Token ();
  InitReduce (SIMPLEIDTOK1);
}

static void
MapSymTok (void)
{
  Token ();
  InitReduce (MAPSYMTOK1);
}

static void
MarkerSymTok (void)
{
  Token ();
  InitReduce (MARKERSYMTOK1);

}

static void
CommentSymTok (void)
{
  Token ();
  InitReduce (COMMENTSYMTOK1);
}


static void
SynClass (void)
{
  if (ltoken_getRawText (nextToken) == ltoken_getText (synonymToken))
    {
      ltoken_free (nextToken);
      nextToken = LSLScanNextToken ();

      OldToken ();
      NewToken ();

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

}

static void
OldToken (void)
{
  Token ();
  InitReduce (OLDTOKEN1);

}

static void
NewToken (void)
{
  Token ();
  InitReduce (NEWTOKEN1);

}

static void
Token (void)
{
  if (ltoken_getCode (nextToken) == LST_EOL
      || ltoken_getCode (nextToken) == LEOFTOKEN)
    {
      LocalUserError (nextToken, "unexpected end-of-line or end-of-file");
    }
  else
    {
      LSLGenShiftOnly (nextToken);
      nextToken = LSLScanNextToken ();
    }
}

/*
** 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 (LSLInitRuleCode rule)
{
  switch (rule)
    {
      case INITFILE1:
      LTRACE ("INITFILE1");
      break;

    case INITLINES1:
      LTRACE ("INITLINES1");
      break;

    case INITLINES2:
      LTRACE ("INITLINES2");
      break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    case QUANTIFIERSYMTOK1:
      LTRACE ("QUANTIFERSYMTOK1");
      ProcessToken (LST_QUANTIFIERSYM);
      break;

    case LOGICALOPTOK1:
      LTRACE ("LOGICALOPTOK1");
      ProcessToken (LST_LOGICALOP);
      break;

    case LRC_EQOPTOK1:
      LTRACE ("LRC_EQOPTOK1");
      ProcessToken (LST_EQOP);
      break;

    case LRC_EQUATIONSYMTOK1:
      LTRACE ("LRC_EQUATIONSYMTOK1");
      ProcessToken (LST_EQUATIONSYM);
      break;

    case LRC_EQSEPSYMTOK1:
      LTRACE ("LRC_EQSEPSYMTOK1");
      ProcessToken (LST_EQSEPSYM);
      break;

    case SELECTSYMTOK1:
      LTRACE ("SELECTSYMTOK1");
      ProcessToken (LST_SELECTSYM);
      break;

    case OPENSYMTOK1:
      LTRACE ("OPENSYMTOK1");
      ProcessToken (LST_OPENSYM);
      break;

    case SEPSYMTOK1:
      LTRACE ("SEPSYMTOK1");
      ProcessToken (LST_SEPSYM);
      break;

    case CLOSESYMTOK1:
      LTRACE ("CLOSESYMTOK1");
      ProcessToken (LST_CLOSESYM);
      break;

    case SIMPLEIDTOK1:
      LTRACE ("SIMPLEIDTOK1");
      ProcessToken (LST_SIMPLEID);
      break;

    case MAPSYMTOK1:
      LTRACE ("MAPSYMTOK1");
      ProcessToken (LST_MAPSYM);
      break;

    case MARKERSYMTOK1:
      LTRACE ("MARKERSYMTOK1");
      ProcessToken (LST_MARKERSYM);
      break;

    case COMMENTSYMTOK1:
      LTRACE ("COMMENTSYMTOK1");
      ProcessToken (LST_COMMENTSYM);
      break;

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

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

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

    default:
      llcontbuglit ("InitReduce: bad switch");
      break;

    }				/* end switch	    */
}				/* end InitReduce () */



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

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

  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]
      && lscanCharClass (firstChar) == SINGLECHAR)
    {
     /* Is a single character that has not been defined before.	    */
     /* Can only have one extension char.  Release old one. */
      lsetCharClass (firstChar, CHC_EXTENSION);
      
      /* this is a (bogus) type bug! caught by splint */
      /* lsetCharClass (currentExtensionChar, SINGLECHAR); */

      lsetCharClass ((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 (LSLIsEndComment (firstChar))
    {
      LocalUserError (stackToken,
		    "already defined as a endCommentChar, cannot redefine");
    }
  else
    {
      lsetEndCommentChar (firstChar, TRUE);
    }
  ltoken_free (stackToken);
}

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

  if (!defineSingleChar[(int)firstChar]
      && lscanCharClass (firstChar) == SINGLECHAR)
    {
      /* Is a single character that has not been defined before.	    */
      /* It's OK to redefine once. */
      lsetCharClass (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
PrintToken (ltoken tok)
{
  char *codStr;
  
  switch (ltoken_getCode (tok)) 
    {
    case NOTTOKEN:          codStr = "*** NOTTOKEN ***"; break;
    case LST_QUANTIFIERSYM: codStr = "QUANTIFIERSYM"; break;
    case LST_LOGICALOP:     codStr = "LOGICALOP: "; break; 
    case LST_SELECTSYM:     codStr = "LST_SELECTSYM"; break;
    case LST_OPENSYM:	    codStr = "LST_OPENSYM"; break;
    case LST_SEPSYM:	    codStr = "SEPSYM"; break;
    case LST_CLOSESYM:	    codStr = "LST_CLOSESYM"; break;
    case LST_SIMPLEID:	    codStr = "LST_SIMPLEID"; break;
    case LST_MAPSYM:	    codStr = "MAPSYM"; break;
    case LST_MARKERSYM:	    codStr = "LST_MARKERSYM"; break;
    case LST_COMMENTSYM:    codStr = "COMMENTSYM"; break;
    case LST_SIMPLEOP:	    codStr = "SIMPLEOP"; break;
    case LST_COLON:         codStr = "LST_COLON"; break;
    case LST_COMMA:	    codStr = "COMMA"; break;
    case LST_LBRACKET:	    codStr = "LST_LBRACKET"; break;
    case LST_LPAR:	    codStr = "LST_LPAR"; break;
    case LST_RBRACKET:	    codStr = "LST_RBRACKET"; break;
    case LST_RPAR:          codStr = "LST_RPAR"; break;
    case LST_EQOP:          codStr = "LST_EQOP"; break;
    case LST_WHITESPACE:    codStr = "WHITESPACE,"; break;
    case LST_EOL:           codStr = "LST_EOL"; break;
    case LST_elseTOKEN:     codStr = "elseTOKEN"; break;
    case LST_ifTOKEN:       codStr = "ifTOKEN"; break;
    case LST_thenTOKEN:     codStr = "thenTOKEN"; break;
    case LST_BADTOKEN:      codStr = "*** BADTOKEN ***"; break;
    case LEOFTOKEN: /* can't reach LEOFTOKEN easily */
      codStr = "LEOFTOKEN"; break;
    default:
      codStr = "*** invalid token code ***";
      break;
    } /* end switch */
  
  /* only used for debugging */
  printf ("%u:%u: Token Code (%u): %s",
	  ltoken_getLine (tok), ltoken_getCol (tok), 
	  ltoken_getCode (tok), codStr);
  if (ltoken_getRawText (tok) != 0) 
    {
      printf (", Token String (%lu): %s\n", 
	      ltoken_getRawText (tok), ltoken_getRawTextChars (tok));
    }
  else printf ("\n");
}

static void
ProcessToken (ltokenCode code)
{
  ltoken stackToken, temp;
  lsymbol sym;

  stackToken = LSLGenTopPopShiftStack ();
  sym = ltoken_getText (stackToken);

  if (LSLIsSyn (sym))
    {
      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.				    */
  temp = LSLGetToken (sym);
  
  if (ltoken_isStateDefined (temp))
    {
      if ((code == LST_OPENSYM && sym == lsymbol_fromChars ("[")) ||
	  (code == LST_CLOSESYM && sym == lsymbol_fromChars ("]")))
	{
	  /* ignore "openSym [" and "closeSym ]" TokenClass */
	  ltoken_free (stackToken);
	  return;
	}
      else
	{
	  LocalUserError (stackToken, "already defined, cannot redefine");
	  PrintToken (temp);
	}
    }
  
  LSLUpdateToken (code, ltoken_getText (stackToken), TRUE);
  ltoken_free (stackToken);
}


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

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

  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, "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");
    }

  LSLAddSyn (ltoken_getText (newtok), ltoken_getText (oldtok));
  ltoken_free (oldtok);
  ltoken_free (newtok);
}


/*
 * Utilities, in alphabetical order
 */

static void
LocalUserError (ltoken t, /*@temp@*/ char *msg)
{
  lldiagmsg (message ("%s %s in the LSL init file:", 
		      ltoken_unparse (t), cstring_fromChars (msg)));

  ltoken_free (nextToken);
  nextToken = LSLScanNextToken ();	       

  while (ltoken_getCode (nextToken) != LST_EOL)
    {
      ltoken_free (nextToken);
      nextToken = LSLScanNextToken ();
    }
}

/*
**  Required initialization and cleanup routines
*/

static /*@exposed@*/ ltoken insertSimpleToken (char *text) 
  /*@modifies internalState@*/
{
  return (LSLInsertToken (LST_SIMPLEID, lsymbol_fromChars (text), 0, FALSE));
}

static void
lslinit_initProcessInitFile (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");			      

  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;

  LSLReportEolTokens (TRUE);
  ltoken_free (nextToken);
  nextToken = LSLScanNextToken ();	       
}

void lslinit_process (void)
  /*@globals undef g_symtab; @*/
  /*@modifies g_symtab, internalState, fileSystem; @*/
{
  /*
  ** Open init file provided by user, or use the default LCL init file 
  */
  
  cstring larchpath = context_getLarchPath ();
  inputStream initstream = inputStream_undefined;

  setCodePoint ();

  if (inputStream_isUndefined (s_initFile))
    {
      s_initFile = inputStream_create (cstring_makeLiteral (INITFILENAME), 
				       cstring_makeLiteralTemp (LCLINIT_SUFFIX),
				       FALSE);
      
      if (!inputStream_getPath (larchpath, s_initFile))
	{
	  lldiagmsg (message ("Continuing without LCL init file: %s",
			      inputStream_fileName (s_initFile)));
	}
      else 
	{
	  if (!inputStream_open (s_initFile))
	    {
	      lldiagmsg (message ("Continuing without LCL init file: %s",
				  inputStream_fileName (s_initFile)));
	    }
	}
    }
  else 
    {
      if (!inputStream_open (s_initFile))
	{
	  lldiagmsg (message ("Continuing without LCL init file: %s",
			      inputStream_fileName (s_initFile)));
	}
    }

  /* Initialize checker */

  lsymbol_initMod ();
  LCLSynTableInit ();

  setCodePoint ();

  LCLSynTableReset ();
  LCLTokenTableInit ();

  setCodePoint ();

  LCLScanLineInit ();
  setCodePoint ();
  LCLScanLineReset ();
  setCodePoint ();
  LCLScanInit ();

  setCodePoint ();

  /* need this to initialize LCL checker */

  llassert (inputStream_isDefined (s_initFile));      
  if (inputStream_isOpen (s_initFile))
    {
      setCodePoint ();

      LCLScanReset (s_initFile);
      lclinit_initMod ();
      lclinit_reset ();

      setCodePoint ();
      lclinit_process ();
      lclinit_cleanup ();

      setCodePoint ();
      check (inputStream_close (s_initFile));
    }
  
  /* Initialize LSL init files, for parsing LSL signatures from LSL */
  
  initstream = inputStream_create (cstring_makeLiteral ("lslinit.lsi"), 
				    cstring_makeLiteralTemp (".lsi"),
				    FALSE);
  
  if (!inputStream_getPath (larchpath, initstream))
    {
      lldiagmsg (message ("Continuing without LSL init file: %s",
			  inputStream_fileName (initstream)));
    }
  else 
    {
      if (!inputStream_open (initstream))
	{
	  lldiagmsg (message ("Continuing without LSL init file: %s",
			      inputStream_fileName (initstream)));
	}
    }
      
  setCodePoint ();
  lsynTableInit ();
  lsynTableReset ();

  setCodePoint ();
  ltokenTableInit ();

  setCodePoint ();
  lscanLineInit ();
  lscanLineReset ();
  LSLScanInit ();

  if (inputStream_isOpen (initstream))
    {
      setCodePoint ();
      LSLScanReset (initstream);
      lslinit_initProcessInitFile ();
      lslinit_processInitFile ();
      check (inputStream_close (initstream));
    }
      
  inputStream_free (initstream);
  
  if (lclHadError ())
    {
      lclplainerror 
	(cstring_makeLiteral ("LSL init file error.  Attempting to continue."));
    }
  
  setCodePoint ();
  g_symtab = symtable_new ();
  
  /* 
  ** sort_init must come after symtab has been initialized 
  */
  sort_init ();
  abstract_init ();
  setCodePoint ();
  
  /* 
  ** Equivalent to importing old spec_csupport.lcl
  ** define immutable LCL type "bool" and bool constants TRUE and FALSE
  ** and initialized them to be equal to LSL's "true" and "false".
  **
  ** Reads in CTrait.syms (derived from CTrait.lsl) on LARCH_PATH.
  */
      
  LCLBuiltins (); 
  LCLReportEolTokens (FALSE);
}
