//---------------------------------------------------------------------------

#ifndef lexanH
#define lexanH

#include <fstream>
#include <list>
#include <stdexcept>
#include <string>
#include "hub/err.h"
class Lexan;
// ----------------------- exception components -----------------
class TokenReason {			// expected some tokens but other came
    int got_, exp1_, exp2_, exp3_;
    Lexan& lx_;
public:
    static const int none_;
    TokenReason (Lexan&, int, int, int =none_, int =none_);
    TokenReason (const TokenReason&);
    std::string tell (void) const; 
};
//---------------------------------------------------------------------------
class KWReason {
    Lexan& lx_;
public:
    KWReason (Lexan&);
    KWReason (const KWReason&);
    std::string tell (void) const; 
};//---------------------------------------------------------------------------
class NotYetReason {
    std::string feature_;
public:
    NotYetReason (const std::string&);
    NotYetReason (const NotYetReason&);
    std::string tell (void) const; 
};
// ==========================================================================
typedef hub::CException <std::runtime_error, TokenReason,  hub::FilePosition> SyntaxException;
typedef hub::CException <std::runtime_error, KWReason,     hub::FilePosition> KWException;
typedef hub::CException <std::runtime_error, NotYetReason, hub::FilePosition> NotYetException;
// ==========================================================================
class LexPosition;

class Lexan {
protected:

   // ----------------------- error reporting -----------------------
    friend class hub::IOReason;
    friend class TokenReason;
    friend class LexPosition;

    std::list<std::pair<int,std::string> > keywords;
    std::list<std::pair<int,std::string> > symbols;
    std::istream* in_;
    std::string fileid_;
    int rowcount_;
 
public:
    const std::string& DecodeSymbol(int);
    // ----------------------- output -------------------------------
    int Lex_AInt;
    double Lex_AReal;
    std::string Lex_AStr;

    Lexan (std::istream&, const std::string&);
    Lexan (){};
    virtual ~Lexan(){}

    void init(std::istream&, const std::string&);		// open input 
    virtual int NextToken()=0;		                    // give next token
    static const int none_;			                    // get next token and check against 1-3 values
    int CheckNextToken (int, int =none_, int =none_);
	int CheckNextToken (bool chk (int), int);
    int CheckToken     (int, int, int =none_, int =none_);

    int rowcount (void) const { return rowcount_; }
    const std::string& fileid (void) const { return fileid_; }
    void fileid (const std::string& fi) { fileid_ = fi; }
};

//---------------------------------------------------------------------------
class LexPosition: public hub::FilePosition {
public:
    LexPosition (Lexan& lx): FilePosition (lx.fileid(), lx.rowcount()) {}
};

#endif
