/*==================================================================
=  文件名  : GramParser
=  主要功能: 
=  修改日期: 
=  作者    : shen beide
====================================================================*/

#if !defined(_GRAMPARSER_H)
#define _GRAMPARSER_H

#include "PubHeader.h"
#include "Grambase.h"
#include "Lex.h"
#include "Callback.h"

//////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class GramState;
class GramObject;
template class CLASS_EXPORT TObArray<GramState>;
template class CLASS_EXPORT TObArray<GramObject>;
template class CLASS_EXPORT TObArray<TObject>;
#endif

//////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class CLASS_EXPORT CErrHandler
#else
class CErrHandler
#endif
{
public: 
    bool m_bFailStop;

public:
    CErrHandler() 
    { 
        Clear(); 
    }
    virtual ~CErrHandler() {}

    void SetFileName(char* szfilename)
    {
        m_nLastErrorLocat.m_strFilename=szfilename;
    }
    void SetLastError(Location& locat,const char* pszFormat, ...)
    {
        if (locat.m_nLocat>m_nLastErrorLocat.m_nLocat)      //
        {
            m_nLastErrorLocat.m_nLocat =locat.m_nLocat;
            m_nLastErrorLocat.m_nLine  =locat.m_nLine;
            m_nLastErrorLocat.m_nColumn=locat.m_nColumn;
            
            va_list arglist;
            va_start(arglist, pszFormat);
            m_strLastError.Format_(pszFormat, arglist);
            va_end  (arglist);
        }
    }
    void SetLastErrorA(Location& locat,const char* pszFormat, ...)
    {
        if (locat.m_nLocat>=m_nLastErrorLocat.m_nLocat)     //
        {
            m_nLastErrorLocat.m_nLocat =locat.m_nLocat;
            m_nLastErrorLocat.m_nLine  =locat.m_nLine;
            m_nLastErrorLocat.m_nColumn=locat.m_nColumn;
            
            va_list arglist;
            va_start(arglist, pszFormat);
            m_strLastError.Format_(pszFormat, arglist);
            va_end  (arglist);
        }
    }
    void Clear()
    {
        m_bFailStop=false;
        m_nLastErrorLocat.setLocat(NULL,-1,-1,-1);   
        m_strLastError="";
    }

    char*     GetLastError()      { return m_strLastError.GetBuffer();  }
    Location& GetLastErrorLocat() { return m_nLastErrorLocat;  }

    OTSTR DumpLastError(Location* pLocatOffset=NULL)
    {
        OTSTR str;
        str.Format("%s  %s",m_nLastErrorLocat.Dump(pLocatOffset).GetBuffer(),m_strLastError.GetBuffer());
        return str;
    }
    
protected:
    Location  m_nLastErrorLocat;
    OTSTR     m_strLastError;                  
};

//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class CLASS_EXPORT GramRules
#else
class GramRules
#endif
{
public:
    GramRules();
   ~GramRules();

    void SetGramName(char* szGramName);
    void Enable_CaseSensitive(bool bCaseSensitive=true);
 
    bool AddRule(long Id, char* szRule);
    void Clear();

    bool Dump(char* filename,bool bOverWrite=true);
    
    OTSTR& GetLastError() { return m_strLastError;  }
    
private:
    bool ExpandRule(GramState* pCurState,long Id,StringArray& strArray);
    GramState* NewGramState();
    
    GramState* GetRootEntry();
    
    bool FoundRule(long Id);
    bool FoundRule(GramState* pEntry, long Id);

    void DumpRule (FILE* fp, GramState* pEntry, OTSTR& strRule);
    
private:    
    friend class GramState;
    friend class GramParser;
    
    /////////////////////////////////////////
    TObArray<GramState> m_RuleEntryList;
    TObArray<GramState> m_StateObjectList;  // 方便删除

    OTSTR    m_strGramName;
    bool     m_bCaseSensitive;              // default: false
    OTSTR    m_strLastError;
};

////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class CLASS_EXPORT GramMatchPattern
#else
class GramMatchPattern
#endif
{
public:
    GramMatchPattern();
   ~GramMatchPattern();
    
    long GetRuleId();
    long GetObjectNum();
    TObject* GetObject(int nIndex);

    void Clear(bool bClearObjectAlso);
    
private:
    long m_nRuleId;
    TObArray<TObject> m_ObjectList;      // $Func中返回
    
    GramState* m_pCurState;

    /////////////////////////////////////////
    void setRuleId(long Id) { m_nRuleId=Id; }
    
    friend class GramParser;
};

//////////////////////////////////////////////////
//////////////////////////////////////////////////
struct GramFuncTableEnt
{
    char                *szFuncName;
    cCallback::tFunction pFunctionPointer;
};

#ifdef _DLL_PROJECT
class CLASS_EXPORT GramParser
#else
class GramParser
#endif
{
public:
    GramParser(void* handler=NULL, struct GramFuncTableEnt *table=NULL);
   ~GramParser();

    bool RegisterGramFunc(void* handler, struct GramFuncTableEnt *table); 

    bool GramMatching(CLex& Lex, GramRules& Rules);     // result中的GramObject对象需要调用者负责释放
                                                        // 匹配不成功则Lex指针还在初始位置
    bool GramMatching(CLex& Lex, char* szRule, bool bCaseSensitive=true);   
    bool GramMatching(CLex& Lex, char* szGramName, char* szRule, bool bCaseSensitive=true);   
    
    GramMatchPattern& GetResult() { return m_MatchResult; }   // Valid when match successful 

    ////////////////////////////////
    char*     GetLastError()      { return m_ErrHandler.GetLastError();  }
    Location& GetLastErrorLocat() { return m_ErrHandler.GetLastErrorLocat();  }
    
protected:
    void*  m_handler;
    struct GramFuncTableEnt* m_pTable; 
    GramMatchPattern         m_MatchResult;

    //////////////////////////////////////
    CErrHandler m_ErrHandler;                  

    bool   Matching(CLex& Lex, GramRules& Rules, GramMatchPattern& result);   

    static int get_function_index(struct GramFuncTableEnt *table, char* szFuncName);

    ///////////////////////////////////////////////
    // CALLBACK function: [0] (DWORD)(Rules.m_strGramName.GetBuffer()); // 区分GramName, 也就是不同的Gram块
    //                    [1] pLex
    //                    [2] pErrHandler
};


#endif
