//-*-C++-*-
/*
**************************************************************************
                                 description
                             --------------------
    copyright            : (C) 2000-2001 by Andreas Zehender
    email                : zehender@kde.org
**************************************************************************

**************************************************************************
*                                                                        *
*  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.                                   *
*                                                                        *
**************************************************************************/


#ifndef PMSCANNER_H
#define PMSCANNER_H

#include <qiodevice.h>
#include <qstring.h>
#include <qasciidict.h>

/**
 * Dictionary of reserved words for fast lookup
 *
 * The class @ref PMScanner has two static dictionaries: one for reserved
 * words and one for directives. The constructor will insert the items.
 */
class PMReservedWordDict : protected QAsciiDict<int>
{
public:
   /** Mode for constructor. */
   enum PMDictMode { PMDReservedWords, PMDDirectives };
   /** Creates a dictionary for povray reserved words or directives. */
   PMReservedWordDict( PMDictMode mode );
   /** Deletes the dictionary */
   ~PMReservedWordDict( );

   /** Returns the token constant for the key if found, otherwise -1 */
   int operator[] ( const char* key ) const { return find( key ); }
   /** Returns the token constant for the key if found, otherwise -1 */
   int find( const char* key ) const
   {
      int* result = QAsciiDict<int>::find( key );
      if( result )
         return *result;
      return -1;
   }
};


/**
 * Scanner that scans povray tokens out of a QIODevice
 */
class PMScanner
{
public:
   /** Creates a scanner that scans the QIODevice device */
   PMScanner( QIODevice* device );
   /** Deletes the scanner */
   ~PMScanner( );

   /** Scans the device for the next token. Returns a value of @ref PMToken
    * ( > 0xFF ) or a single character */
   int nextToken( );
   /** Returns the current token */
   int currentToken( ) const { return m_token; }

   /** Returns the integer value of the current token if currentToken
    * is INTEGER_TOK */
   int iValue( ) const { return m_ivalue; }
   /** Returns the double value of the current token if currentToken
    * is FLOAT_TOK */
   double fValue( ) const { return m_fvalue; }
   /** Returns the string value of the current token if currentToken
    * is ID_TOK, COMMENT_TOK, STRING_TOK */
   const char* sValue( ) const { return m_svalue; }
   /** Returns the current line number */
   int currentLine( ) const { return m_line; }
   /** Returns the error string if current token is SCANNER_ERROR_TOK */
   QString error( ) const { return m_error; }
   /** Returns a pointer to a dictionary with reserved words */
   static PMReservedWordDict* reservedWords( ) { return &m_reservedWords; }
   /** Returns a pointer to a dictionary with directives */
   static PMReservedWordDict* directives( ) { return &m_directives; }
private:
   /**
    * returns true if c is one of the following characters:
    * space, tab, newline, '{', '}', '<', '>', '+', '-', '*', '/', ',',
    * '(', ')', '=', '[', ']', ';'
    */
   inline bool isseparation( int c );
   /** Called on unexpected character */
   void scanError( int c );
   /** Reads the next character out of the device */
   inline void nextChar( );
   /** Adds the char to m_svalue */
   inline void addChar( char c );
   /** Clears m_svalue */
   inline void clearSValue( );
   
   static PMReservedWordDict m_reservedWords;
   static PMReservedWordDict m_directives;
   
   /** States for the state machine of the scanner */
   enum PMScanStates
   {
      START_ST = 0, ID_ENDST, INTEGER_ENDST,
      FLOAT1_ST, FLOAT_ENDST, FLOAT_EXP1_ST, FLOAT_EXP2_ST, FLOAT_EXP_ENDST,
      POINT_ST,
      DIRECTIVE1_ST, DIRECTIVE_ENDST,
      STRING1_ST, STRINGBS_ST,
      SLASH_ST, LINE_COMMENT_FIRST_ST, LINE_COMMENT_ST,
      C_COMMENT_ST, COMMENT_ST_ST, COMMENT_SL_ST, COMMENT_NEW_LINE_ST,
      PMNAME_ST,
      RAW_POVRAY_FIRST_ST, RAW_POVRAY_LB_ST, RAW_POVRAY_ST, RAW_POVRAY_END_ST,
      RAW_POVRAY_END_END_ST,
      TOKEN_END_ST
   };
   
   QIODevice* m_pDevice;

   int m_char;
   int m_token;
   int m_ivalue;
   double m_fvalue;
   char* m_svalue;
   char* m_lastChar;
   char* m_lastAlloc;
   unsigned int m_svalueAlloc;
   int m_indentation;
   int m_rawIndentation;
   int m_rawPovrayEnd;
   
   int m_line;
   QString m_error;
};


#endif
