/***************************************************************************
* Token.h                                                                  *
*                                                                          *
* The Token class ecapsulates a lexical analyzer for C++-like syntax.      *
* A token instance is associated with one or more text files, and          *
* grabs C++ tokens from them sequentially.  There are many member          *
* functions designed to make parsing easy, such as "==" operators for      *
* strings and characters, and automatic conversion of numeric tokens       *
* into numeric values.                                                     *
*                                                                          *
* Files can be nested via #include directives, and both styles of C++      *
* comments are supported.                                                  *
*                                                                          *
*                                                                          *
*   HISTORY                                                                *
*      Name    Date        Description                                     *
*                                                                          *
*      arvo    10/05/99    Fixed bug in TokFrame string allocation.        *
*      arvo    01/15/95    Added ifdef, ifndef, else, and endif.           *
*      arvo    02/13/94    Added Debug() member function.                  *
*      arvo    01/22/94    Several sections rewritten.                     *
*      arvo    06/19/93    Converted to C++                                *
*      arvo    07/15/89    Rewritten for scene description parser.         *
*      arvo    01/22/89    Initial coding.                                 *
*                                                                          *
*--------------------------------------------------------------------------*
* Copyright (C) 1999, James Arvo                                           *
*                                                                          *
* 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.  See http://www.fsf.org/copyleft/gpl.html      *
*                                                                          *
* This program is distributed in the hope that it will be useful, but      *
* WITHOUT EXPRESS OR IMPLIED WARRANTY of merchantability or fitness for    *
* any particular purpose.  See the GNU General Public License for more     *
* details.                                                                 *
*                                                                          *
***************************************************************************/
#ifndef __TOKEN_INCLUDED__
#define __TOKEN_INCLUDED__

#include <iostream>
#include <stdio.h>

namespace ArvoMath {

	const int MaxTokenLen = 128;

	typedef enum {
		T_null,   
		T_char,       // A string of length 1.
		T_string,
		T_integer,
		T_float,
		T_ident,
		T_other,
		T_numeric,    // Either T_float or T_int (use with == operator).
		T_directive,  // Directives like #include are not returned to the user.
		T_nullmacro
	} TokType;

	typedef enum {
		T_malformed_float,
		T_unterm_string,
		T_unterm_comment,
		T_file_not_found,
		T_unknown_directive,
		T_string_expected,
		T_putback_error,
		T_name_too_long,
		T_no_endif,
		T_extra_endif,
		T_extra_else
	} TokError;

	class TokFrame {
	public:
		TokFrame();
		TokFrame( const TokFrame &frame ) { *this = frame; }
		~TokFrame();
		void operator=( const TokFrame & );
	public:
		TokFrame *next;
		FILE     *source;
		char     *fname;
		int       line;    
		int       column;  
	};

	struct TokPath {
		char    *path;
		TokPath *next;
	};

	struct TokMacro {
		char     *macro;
		char     *repl;
		TokType   type;
		TokMacro *next;
	};

	class Token {

	public:
		// Constructors and destructor.

		Token();
		Token( const char *file_name );
		Token( FILE *file_pointer    );
		~Token();

		// Const data members for querying token information.

		TokType Type()    const { return type;       }  // The type of token found. 
		int     Len()     const { return length;     }  // The length of the token. 
		int     Line()    const { return frame.line; }  // The line it was found on.
		int     Column()  const { return Tcolumn;    }  // The column it began in.  
		long    Ivalue()  const { return ivalue;     }  // Token value if an integer.
		float   Fvalue()  const;                        // Token value if int or float.
		char    Char()    const;                        // The token (if a Len() == 1).

		// Operators.

		int     operator == ( const char* ) const;      // 1 if strings match.
		int     operator != ( const char* ) const;      // 0 if strings match.
		int     operator == ( char        ) const;      // 1 if token is this char.
		int     operator != ( char        ) const;      // 0 if token is this char.
		int     operator == ( TokType     ) const;      // 1 if token is of this type.
		int     operator != ( TokType     ) const;      // 0 if token is of this type.
		Token & operator ++ (             );            // (prefix) Get the next token.
		Token & operator -- (             );            // (prefix) Put back one token.
		Token & operator ++ ( int         );            // (postfix) Undefined.
		Token & operator -- ( int         );            // (postfix) Undefined.

		// State-setting member functions.

		void Open( FILE * );                            // Read already opened file.
		void Open( const char * );                      // Open the named file.
		void CaseSensitive( int on_off );               // Applies to == and != operators.
		void AddPath( const char * );                   // Adds path for <...> includes.
		void ClearPaths();                              // Remove all search paths.

		// Miscellaneous.

		const char* Spelling() const;                   // The token itself.
		const char* FileName() const;                   // Current file being lexed.
		static void Debug( FILE * );                    // Write all token streams to a file.
		static void Args ( int argc, char *argv[] );    // Search args for macro settings.
		void AddMacro( const char*, const char*, TokType type );
		void SearchArgs();

	private:

		// Private member functions.       

		void     Init();
		int      Getc ( int & );
		void     Unget( int c ) { pushed = c; }
		void     Error( TokError error, const char *name = NULL );
		int      NonWhite( int & );
		int      HandleDirective();
		int      NextRawTok();  // No macro substitutions.
		int      NextTok();
		void     PushFrame( FILE *fp, char *fname = NULL );
		int      PopFrame();
		void     GetName( char *name, int max );
		FILE     *ResolveName( const char *name );
		TokMacro *MacroLookup( const char *str ) const;
		int      MacroReplace( char *str, int &length, TokType &type ) const;

		// Private data members.       

		TokPath  *first;
		TokPath  *last;
		TokMacro **table;
		TokFrame frame;
		TokType  type;
		long     ivalue;  
		float    fvalue;  
		int      length;  
		int      Tcolumn;  
		int      put_back;    
		int      case_sensitive;
		int      pushed;
		int      if_nesting;
		char     spelling[ MaxTokenLen ];
		char     tempbuff[ MaxTokenLen ];

		// Static data members.       

		static int  argc;
		static char **argv;
		static FILE *debug;
	};


	// Predicate-style functions for testing token types.

	inline int Null   ( const Token &t ) { return t.Type() == T_null;    }
	inline int Numeric( const Token &t ) { return t.Type() == T_numeric; }
	inline int StringP( const Token &t ) { return t.Type() == T_string;  }
};
#endif
