/*
 *  scanner.cc
 *
 *  This file is part of NEST.
 *
 *  Copyright (C) 2004 The NEST Initiative
 *
 *  NEST 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.
 *
 *  NEST 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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with NEST.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/* 
    scanner.cc
*/
#include "scanner.h"
#include "integerdatum.h"
#include "doubledatum.h"
#include "namedatum.h"
#include "symboldatum.h"
#include "stringdatum.h"
#include <cmath>
#include <sstream>
#include <limits>

/*************************************************************************/
/** Scanner   (implemented as a DFA)                                     */
/* -------                                                               */
/*         Scanner uses a symbol processor which controls all operations */
/*         on symbols (strings with a unique id) instead of a static     */
/*         symbol table.                                                 */
/*                                                                       */
/*          still experimental...                                        */
/*             - uses an explicit transition function, which can         */
/*               not be constructed from regular expression              */
/*               (unlike in lex).                                        */
/*             - no clear interface between the basic functions and a    */
/*               a particular application.                               */
/*             - once we are sure about the final structure of this file */
/*               we will as usual move this comment to scanner.h         */
/*                                                                       */
/* Problems:                                                             */
/*           The scanner puts the newline character back into the        */
/*           stream at the end of a line, thus the next read             */
/*           operation performed on that stream returns the newline      */
/*           character. This case, i.e. a token is terminated by endoln  */
/*           should be treated separately to avoid this.                 */
/*           The current workarount checks for endoln at each unget()    */
/*           call!                                                       */
/*           24. June 1997, Gewaltig                                     */
/*                                                                       */
/*                                                                       */
/* History:                                                              */
/*         (7) 080505, Diesmann. minusst can now be followed by minus    */
/*	       to enable right arrows like -->                           */ 
/*         (6) 071002, Diesmann. Replaced own conversion to double by    */
/*             library function std::atof(). Now compatible with cvd.    */
/*         (5) 8.4.1997, Adaption debuged. Special explicit start entr   */
/*            in switch, to reserve default for errors. Previous version */
/*            did not eat white spaces.                                  */
/*         (4) March 1997, Gewaltig; Adapted for SLI 2.0                 */
/*         (3) 5.8.1994, Diesmann                                        */
/*             We are now trying to bring the project to a state where   */
/*             it can be used by the public.                             */
/*             We noticed that on some compilers the 'put to' operator   */
/*             is not defined for type (long double) and we are not sure */
/*             that it is part of the ANSI standard. As we are currently */
/*             not using this type we haven't implemented it. The        */
/*             'put to' operator for class Token now returns the string  */
/*             "sorry, no 'put to' for (long double)\n" instead.         */
/*         (2) Oct. 1993, applied to sns Gewaltig, Diesmann              */
/*         (1) string introduced by mog. 5.10.93                         */
/*         (0) first version, Summer 1993 diesmann                       */
/*                                                                       */
/*************************************************************************/

/***************************************************************************/

Scanner::Scanner(std::istream* is)
        : in(is), code(std::numeric_limits<unsigned char>::max(),invalid),
	  line(0),
	  col(0),
          space(32),tab(9),endoln(10),cr(13),endof(4), ds(),
          BeginArraySymbol("/BeginArraySymbol"), // these symbol-names cannot be entered
          EndArraySymbol("/EndArraySymbol"),     // by keyboard! This is important to ensure
          BeginProcedureSymbol("/BeginProcedureSymbol"), // the integrity of the scanner/parser
          EndProcedureSymbol("/EndProcedureSymbol"),     // interaction: Non-terminal symbols
          EndSymbol("/EndSymbol")
{

    for(size_t s = start; s < lastscanstate; ++s)
        for(size_t  c = invalid; c < lastcode; ++c)
            trans[s][c]=error;
        
    code[space]=whitespace;
    code[tab  ]=whitespace;
    code[endof]=eof;

    code['+']=plus;
    code['-']=minus;

    code['[']=openbracket;
    code[']']=closebracket;     // see Kernighan p.7
    code['{']=openbrace;
    code['}']=closebrace;
    code['(']=openparenth;     // for string implementation
    code[')']=closeparenth;     // for string implementation

    code['.']=decpoint;
    code['0']=null;
    code.Group(expntl,"Ee");
    code.Group(digit,"123456789");
    
    code.Group(alpha,"ABCDFGHIJKLMNOPQRSTUVWXYZ");
    code.Group(alpha,"abcdfghijklmopqrsuvwxyz");
    code.Range(alpha,(char)161,(char)255);
    code['_']=alpha;
    code.Group(alpha,"~`!@#$^&=|:;'<,>?\""); // according to PS

    code['/']=slash;
    code['\\']=backslash;        // used for escapes in strings
    code['n']=newline;           // newline escape \n
    code['t']=tabulator;         // tabulator escape \t

    code['*']=asterisk;
    code['%']=percent;
    code[endoln]=eoln;
    code[cr]=eoln;



    trans[start][whitespace]=start;
    trans[start][eoln]=start;
    trans[start][minus]=minusst;
    trans[start][plus]=plusst;
    trans[start][digit]=intdgtst;
    trans[start][null]=nullst;
    trans[start][decpoint]=decpfirstst;
    trans[start][openbracket]=openbracketst;
    trans[start][closebracket]=closebracketst;
    trans[start][openbrace]=openbracest;
    trans[start][closebrace]=closebracest;
    trans[start][alpha]=alphast;
    trans[start][asterisk]=alphast;    
    trans[start][newline]=alphast;
    trans[start][tabulator]=alphast;
    trans[start][backslash]=alphast;
    trans[start][expntl]=alphast;
    trans[start][slash]=slashst;
    trans[start][percent]=percentst;
    trans[start][eof]=eofst;
    trans[start][openparenth]=startstringst;
    
    trans[minusst][digit]=intdgtst;
    trans[minusst][null]=nullst;
    trans[minusst][decpoint]=decpfirstst;
    trans[minusst][alpha]=sgalphast;
    trans[minusst][minus]=sgalphast;         // must be name
    trans[minusst][newline]=sgalphast;
    trans[minusst][tabulator]=sgalphast;
    trans[minusst][backslash]=sgalphast;
    trans[minusst][expntl]=alphast;
    trans[minusst][whitespace]=aheadsgst;
    trans[minusst][eoln]=aheadsgst;
    trans[minusst][openbracket]=aheadsgst; 
    trans[minusst][openbrace]=aheadsgst; 
    trans[minusst][closebracket]=aheadsgst;
    trans[minusst][closebrace]=aheadsgst; 
    trans[minusst][percent]=aheadsgst;
    trans[minusst][openparenth]=aheadsgst;
    trans[minusst][slash]=aheadsgst;
    trans[minusst][eof]=aheadsgst; 

    trans[plusst][digit]=intdgtst;
    trans[plusst][null]=nullst;
    trans[plusst][decpoint]=decpfirstst;
    trans[plusst][alpha]=sgalphast;
    trans[plusst][newline]=sgalphast;
    trans[plusst][tabulator]=sgalphast;
    trans[plusst][backslash]=sgalphast;
    trans[plusst][expntl]=alphast;
    trans[plusst][whitespace]=aheadsgst;
    trans[plusst][eoln]=aheadsgst;
    trans[plusst][openbracket]=aheadsgst; 
    trans[plusst][openbrace]=aheadsgst; 
    trans[plusst][closebracket]=aheadsgst;
    trans[plusst][closebrace]=aheadsgst; 
    trans[plusst][percent]=aheadsgst;
    trans[plusst][openparenth]=aheadsgst;
    trans[plusst][slash]=aheadsgst;
    trans[plusst][eof]=aheadsgst; 

 
    trans[startstringst][closeparenth]=closeparst; // empty string
    trans[startstringst][openparenth]=openparst;
    trans[startstringst][backslash]=backslashst;   // string escape
    trans[startstringst][digit]=stringst;
    trans[startstringst][null]=stringst;
    trans[startstringst][expntl]=stringst;
    trans[startstringst][decpoint]=stringst;
    trans[startstringst][plus]=stringst;
    trans[startstringst][minus]=stringst;
    trans[startstringst][whitespace]=stringst;
    trans[startstringst][eoln]=stringst; // eoln is included!
    trans[startstringst][openbracket]=stringst;
    trans[startstringst][closebracket]=stringst;
    trans[startstringst][openbrace]=stringst;
    trans[startstringst][closebrace]=stringst;
    trans[startstringst][alpha]=stringst;
    trans[startstringst][newline]=stringst;
    trans[startstringst][tabulator]=stringst;
    trans[startstringst][slash]=stringst;
    trans[startstringst][percent]=stringst;
    trans[startstringst][asterisk]=stringst;

    trans[stringst][closeparenth]=closeparst;
    trans[stringst][openparenth]=openparst;
    trans[stringst][backslash]=backslashst;   // string escape
    trans[stringst][digit]=stringst;
    trans[stringst][null]=stringst;
    trans[stringst][expntl]=stringst;
    trans[stringst][decpoint]=stringst;
    trans[stringst][plus]=stringst;
    trans[stringst][minus]=stringst;
    trans[stringst][whitespace]=stringst;
    trans[stringst][eoln]=stringst;
    trans[stringst][openbracket]=stringst; 
    trans[stringst][closebracket]=stringst; 
    trans[stringst][openbrace]=stringst;
    trans[stringst][closebrace]=stringst;
    trans[stringst][alpha]=stringst;
    trans[stringst][newline]=stringst;
    trans[stringst][tabulator]=stringst;
    trans[stringst][slash]=stringst;
    trans[stringst][percent]=stringst;
    trans[stringst][asterisk]=stringst;

// Escape sequences inside a string
    trans[backslashst][newline]=newlinest;
    trans[backslashst][tabulator]=tabulatorst;
    trans[backslashst][backslash]=backslashcst;
    trans[backslashst][openparenth]=oparenthcst;
    trans[backslashst][closeparenth]=cparenthcst;

    trans[intdgtst][digit]=intdgtst;
    trans[intdgtst][null]=intdgtst;
    trans[intdgtst][expntl]=intexpst;
    trans[intdgtst][decpoint]=decpointst;
    trans[intdgtst][whitespace]=aheadintst; 
    trans[intdgtst][openbracket]=aheadintst; 
    trans[intdgtst][openbrace]=aheadintst; 
    trans[intdgtst][closebrace]=aheadintst;
    trans[intdgtst][closebracket]=aheadintst;
    trans[intdgtst][percent]=aheadintst;
    trans[intdgtst][slash]=aheadintst;
    trans[intdgtst][alpha]=aheadintst;	// this is a bit questionable, but still unique
    trans[intdgtst][newline]=aheadintst;
    trans[intdgtst][tabulator]=aheadintst;
    trans[intdgtst][backslash]=aheadintst;  
    trans[intdgtst][openparenth]=aheadintst;
    trans[intdgtst][eoln]=aheadintst;
    trans[intdgtst][eof]=aheadintst;

    trans[nullst][decpoint]=decpointst;
    trans[nullst][expntl]=expntlst;        
    trans[nullst][whitespace]=aheadintst;
    trans[nullst][openbracket]=aheadintst; 
    trans[nullst][openbrace]=aheadintst; 
    trans[nullst][closebrace]=aheadintst;
    trans[nullst][closebracket]=aheadintst;
    trans[nullst][percent]=aheadintst;
    trans[nullst][slash]=aheadintst;
    trans[nullst][openparenth]=aheadintst;
    trans[nullst][alpha]=aheadintst;	// this is a bit questionable, but still unique
    trans[nullst][tabulator]=aheadintst;
    trans[nullst][newline]=aheadintst;  
    trans[nullst][backslash]=aheadintst;  
    trans[nullst][eoln]=aheadintst;
    trans[nullst][eof]=aheadintst;


    trans[decpfirstst][digit]=decpdgtst;
    trans[decpfirstst][alpha]=dotalphast;
    trans[decpfirstst][asterisk]=dotalphast;
    trans[decpfirstst][null]=decpdgtst;
 
    trans[decpointst][digit]=fracdgtst;
    trans[decpointst][null]=fracdgtst;
    trans[decpointst][expntl]=expntlst;
    trans[decpointst][whitespace]=aheadfracst;
    trans[decpointst][eoln]=aheadfracst;
    trans[decpointst][openbracket]=aheadfracst; 
    trans[decpointst][openbrace]=aheadfracst; 
    trans[decpointst][closebracket]=aheadfracst;
    trans[decpointst][closebrace]=aheadfracst;
    trans[decpointst][percent]=aheadfracst;
    trans[decpointst][slash]=aheadfracst;
    trans[decpointst][openparenth]=aheadfracst;
    trans[decpointst][alpha]=aheadfracst;	// this is a bit questionable, but still unique
    trans[decpointst][tabulator]=aheadfracst;  
    trans[decpointst][newline]=aheadfracst;  
    trans[decpointst][backslash]=aheadfracst;  
    trans[decpointst][eof]=aheadfracst;

 
    trans[fracdgtst][digit]=fracdgtst;
    trans[fracdgtst][null]=fracdgtst;  
    trans[fracdgtst][expntl]=expntlst; 
    trans[fracdgtst][whitespace]=aheadfracst;
    trans[fracdgtst][eoln]=aheadfracst;
    trans[fracdgtst][openbracket]=aheadfracst; 
    trans[fracdgtst][openbrace]=aheadfracst; 
    trans[fracdgtst][closebracket]=aheadfracst;
    trans[fracdgtst][closebrace]=aheadfracst;
    trans[fracdgtst][percent]=aheadfracst;
    trans[fracdgtst][slash]=aheadfracst;
    trans[fracdgtst][openparenth]=aheadfracst;
    trans[fracdgtst][alpha]=aheadfracst;	// this is a bit questionable, but still unique
    trans[fracdgtst][tabulator]=aheadfracst;  
    trans[fracdgtst][newline]=aheadfracst;  
    trans[fracdgtst][backslash]=aheadfracst;  
    trans[fracdgtst][eof]=aheadfracst;
 
    trans[expntlst][digit]=expdigst;
    trans[expntlst][null]=expdigst;
    trans[expntlst][plus]=plexpst;
    trans[expntlst][minus]=mnexpst;

    trans[plexpst][digit]=expdigst;
    trans[plexpst][null]=expdigst;

    trans[mnexpst][digit]=expdigst;
    trans[mnexpst][null]=expdigst;

    trans[expdigst][digit]=expdigst;
    trans[expdigst][null]=expdigst;
    trans[expdigst][whitespace]=aheadfracst;
    trans[expdigst][eoln]=aheadfracst;
    trans[expdigst][openbracket]=aheadfracst; 
    trans[expdigst][openbrace]=aheadfracst; 
    trans[expdigst][closebracket]=aheadfracst;
    trans[expdigst][closebrace]=aheadfracst;
    trans[expdigst][percent]=aheadfracst;
    trans[expdigst][slash]=aheadfracst;
    trans[expdigst][openparenth]=aheadfracst;
    trans[expdigst][alpha]=aheadfracst;	// this is a bit questionable, but still unique
    trans[expdigst][newline]=aheadfracst;  
    trans[expdigst][tabulator]=aheadfracst;  
    trans[expdigst][backslash]=aheadfracst;  
    trans[expdigst][eof]=aheadfracst;


    trans[alphast][whitespace]=aheadalphst;
    trans[alphast][eoln]=aheadalphst;
    trans[alphast][alpha]=alphast;
    trans[alphast][asterisk]=alphast;    
    trans[alphast][newline]=alphast;
    trans[alphast][tabulator]=alphast;
    trans[alphast][backslash]=alphast;
    trans[alphast][expntl]=alphast;
    trans[alphast][digit]=alphast;
    trans[alphast][null]=alphast;
    trans[alphast][plus]=alphast;
    trans[alphast][minus]=alphast;
    trans[alphast][decpoint]=alphast;
    trans[alphast][openbracket]=aheadalphst; 
    trans[alphast][openbrace]=aheadalphst; 
    trans[alphast][closebracket]=aheadalphst;
    trans[alphast][closebrace]=aheadalphst; 
    trans[alphast][percent]=aheadalphst;
    trans[alphast][openparenth]=aheadalphst;
    trans[alphast][slash]=aheadalphst;
    trans[alphast][eof]=aheadalphst;

// PostScript comments are like white space

    trans[percentst][eoln]=start;
    trans[percentst][backslash]=percentst;
    trans[percentst][whitespace]=percentst;
    trans[percentst][openparenth]=percentst;
    trans[percentst][closeparenth]=percentst;
    trans[percentst][digit]=percentst;
    trans[percentst][null]=percentst;
    trans[percentst][decpoint]=percentst;
    trans[percentst][plus]=percentst;
    trans[percentst][minus]=percentst;
    trans[percentst][openbracket]=percentst;
    trans[percentst][closebracket]=percentst;
    trans[percentst][openbrace]=percentst;
    trans[percentst][closebrace]=percentst;
    trans[percentst][alpha]=percentst;
    trans[percentst][newline]=percentst;
    trans[percentst][tabulator]=percentst;
    trans[percentst][expntl]=percentst;
    trans[percentst][slash]=percentst;
    trans[percentst][percent]=percentst;
    trans[percentst][asterisk]=percentst;
    trans[percentst][eof]=eofst;

// ccommentst treats c like comments.

    trans[slashst][asterisk]=ccommentst;
    trans[slashst][backslash]=literalst;
    trans[slashst][alpha]=literalst;
    trans[slashst][newline]=literalst;
    trans[slashst][tabulator]=literalst;
    trans[slashst][minus]=literalst;
    trans[slashst][plus]=literalst;
    trans[slashst][expntl]=literalst;
    trans[slashst][digit]=literalst;
    trans[slashst][decpoint]=literalst;
    trans[slashst][null]=literalst;

    trans[literalst][whitespace]=aheadlitst;
    trans[literalst][eoln]=aheadlitst;
    trans[literalst][alpha]=literalst;
    trans[literalst][asterisk]=literalst;    
    trans[literalst][newline]=literalst;
    trans[literalst][tabulator]=literalst;
    trans[literalst][backslash]=literalst;  
    trans[literalst][expntl]=literalst;
    trans[literalst][digit]=literalst;
    trans[literalst][null]=literalst;
    trans[literalst][plus]=literalst;
    trans[literalst][minus]=literalst;
    trans[literalst][decpoint]=literalst;
    trans[literalst][openbracket]=aheadlitst;
    trans[literalst][closebracket]=aheadlitst;
    trans[literalst][openbrace]=aheadlitst; 
    trans[literalst][closebrace]=aheadlitst;
    trans[literalst][openparenth]=aheadlitst; 
    trans[literalst][percent]=aheadlitst;
    trans[literalst][slash]=aheadlitst;
    trans[literalst][eof]=aheadlitst;


    trans[ccommentst][eoln]=ccommentst;
    trans[ccommentst][whitespace]=ccommentst;
    trans[ccommentst][openparenth]=ccommentst;
    trans[ccommentst][closeparenth]=ccommentst;
    trans[ccommentst][backslash]=ccommentst;
    trans[ccommentst][digit]=ccommentst;
    trans[ccommentst][null]=ccommentst;
    trans[ccommentst][decpoint]=ccommentst;
    trans[ccommentst][plus]=ccommentst;
    trans[ccommentst][minus]=ccommentst;
    trans[ccommentst][percent]=ccommentst;
    trans[ccommentst][openbracket]=ccommentst;
    trans[ccommentst][closebracket]=ccommentst;
    trans[ccommentst][openbrace]=ccommentst;
    trans[ccommentst][closebrace]=ccommentst;
    trans[ccommentst][alpha]=ccommentst;
    trans[ccommentst][newline]=ccommentst;
    trans[ccommentst][tabulator]=ccommentst;
    trans[ccommentst][expntl]=ccommentst;
    trans[ccommentst][slash]=ccommentst;
    trans[ccommentst][asterisk]=asteriskst;

    trans[asteriskst][slash]=start;
    trans[asteriskst][eoln]=ccommentst;
    trans[asteriskst][backslash]=ccommentst;
    trans[asteriskst][whitespace]=ccommentst;
    trans[asteriskst][openparenth]=ccommentst;
    trans[asteriskst][closeparenth]=ccommentst;
    trans[asteriskst][digit]=ccommentst;
    trans[asteriskst][null]=ccommentst;
    trans[asteriskst][decpoint]=ccommentst;
    trans[asteriskst][plus]=ccommentst;
    trans[asteriskst][minus]=ccommentst;
    trans[asteriskst][openbracket]=ccommentst;
    trans[asteriskst][closebracket]=ccommentst;
    trans[asteriskst][openbrace]=ccommentst;
    trans[asteriskst][closebrace]=ccommentst;
    trans[asteriskst][alpha]=ccommentst;
    trans[asteriskst][newline]=ccommentst;
    trans[asteriskst][tabulator]=ccommentst;
    trans[asteriskst][expntl]=ccommentst;
    trans[asteriskst][percent]=ccommentst;
    trans[asteriskst][asterisk]=asteriskst; // changed from ccommentst, 25.8.1995
} 

void Scanner::source(std::istream* in_s)
{
  if(in != in_s)
  {
    in=in_s;
    line=0;
    col=0;
    old_context.clear();
    context.clear();
    context.reserve(255);
  }
}

bool Scanner::operator()(Token& t)
{
    static const int base=10;
    ScanStates state=start;
    std::string s; s.reserve(255);
    context.reserve(255);

    unsigned char c='\0';
    unsigned char sgc='\0';

    long l=0L;
    double d=0.0;
    int sg=1;
    int e=0;
    int parenth=0;    // to handle PS parenthesis in strings
    double p=1.;

    
    t.clear();

    do {

      if(!in->eof() && !in->good())
	{
	  std::cout << "I/O Error in scanner input stream." << std::endl;
	  state=error;
	  break;
	}
 
      // according to Stroustrup 21.3.4, std::istream::get(char&), 
      // so we cannot use unsigned char c as argument.  The
      // get() is not picky.  --- HEP 2001-08-09
      //     in->get(c);    
      c = in->get();

      if(col++ == 0)
	++line;

      if(c=='\0' || in->bad())
	c=endof;

      if(in->eof())
	c= endof;
      else
	assert(in->good());

      if(c != endof)
	context+=c;
      
      if(c==endoln)
      {
	col=0;
	old_context.clear();
	old_context.swap(context);
	context.reserve(256);
      }
	
      state= trans[state][code(c)];

      switch (state) {
//	  case start        :
//            break;
      case intdgtst   :
	l=sg*(std::labs(l)*base+digval(c));
        ds.push_back(c);
	break;

      case aheadintst :
      {
	IntegerDatum id(l);
	t=id;
	if(c != endoln && c != endof)
	{
	  in->unget();
	  --col;
	}

        ds.clear();
	state=end;
      }
      break;


      case expntlst :
        ds.push_back('e');
        break;
          
      case intexpst   :
        d= (double)l;
	ds.push_back('e');
	state=expntlst;
        break;

      case decpointst :
	d= (double)l;
        ds.push_back('.');
	break;

      case decpdgtst  : 
	/* This state is entered when a number starts with a decimal point.
	   in this case the next character must be null or digit, everything
	   else is an invalid transition. This is why decpdgtst and fracdgtst
	   are separate states. */ 
        ds.push_back('.');
	state=fracdgtst;
      case fracdgtst  :
	p/=base;
	d+=sg*p*digval(c);
        ds.push_back(c);
	break;

      case aheadfracst:
      {
	// cast base to double to help aCC with overloading
        // the first arg to pow is always a double, Stroustrup 22.3
        // HEP 2001-08--09

        // traditional
        // Token doubletoken(new DoubleDatum(d * std::pow((double)base,es*e)));

        Token doubletoken(new DoubleDatum( std::atof(ds.c_str())  ));
        ds.clear();
     
	t.move(doubletoken);
	if(c != endoln && c != endof)
	{
	  in->unget();
	  --col;
	}
	state=end;
      }
      break;

      case minusst    :
	sg=-1; 
        ds.push_back('-');
      case plusst     :
	sgc=c;
	break;

      case mnexpst    :
//	es=-1;
        ds.push_back('-');
	break;

      case expdigst   :
	e=e*base+digval(c);
        ds.push_back(c);
	break;

      case openparst  :
	parenth++;
	s.append(1,c);
	state=stringst;
	break;
      case closeparst :                     // this is not meant for a DEA!
	if(parenth)          // if parenth>0 we are still
	{                    //  inside the string
	  s.append(1,c); // the last ) is not included.
	  parenth--;
	  state=stringst;
	}
	else
	{
	  Token temptoken(new StringDatum(s));
	  t.move(temptoken);
	  state=end;
	}
	break;
      case dotalphast:
          s.append(1,'.');
          s.append(1,c);
          state=alphast;
          break;
      case sgalphast  :
	assert(sgc=='+' || sgc=='-');
	s.append(1,sgc);
	state=alphast;
      case literalst  :
      case stringst   :
      case alphast    :                    // let's optimize this at some point
	s.append(1,c);  // string of fixed length sl
	break;              // append to s every sl characters
      case newlinest  : 
	s.append("\n");  
	state=stringst;
	break;
      case tabulatorst: 
	s.append("\t");
	state=stringst;
	break;
      case backslashcst: 
	s.append("\\");
	state=stringst;
	break;
      case oparenthcst: 
	s.append("(");
	state=stringst;
	break;
      case cparenthcst: 
	s.append(")");
	state=stringst;
	break;
      case aheadsgst  : 
	s.append(1,sgc);                  
      case aheadalphst:
      {
	if(c != endoln && c != endof)
	{
	  in->unget();
	  --col;
	}
	NameDatum nd(s);
	t=nd;
      }
      state=end;
      break;
      
      case aheadlitst :
      {
	if(c != endoln && c != endof)
	{
	  in->unget();
	  --col;
	}
	LiteralDatum nd(s);
	t=nd;
	state=end;
      }
      break;
      
      case openbracest:
      {
	t=BeginProcedureSymbol;
	state=end;
      }
      break;
      
      case openbracketst:
      {
	t=BeginArraySymbol;
	state=end;
      }
      break;
      
      case closebracest:
      {
	t=EndProcedureSymbol;
	state=end;
      }
      break;
      
      case closebracketst:
      {
	t=EndArraySymbol;
	state=end;
      }
      break;
      
      case eofst      :
      {
	t=EndSymbol;
	state=end;
      }
      break;
      
      case error : 
	print_error("");
	break;
      default:
	break;
	
      }
    } while ((state!=error) && (state!=end));
    return(state==end);
}

void Scanner::print_error(const char *msg)
{
  std::cout << "% parser: At line " << line << " position " << col << ".\n"
	    << "% parser: Syntax Error: " << msg << "\n";
  std::cout<< "% parser: Context preceding the error follows:\n" 
	   << old_context << std::endl
	   << context << std::endl;
}