/*==================================================================
=  文件名  : Lex
=  主要功能: 词法分析器
=  修改日期: 2006.10
=  作者    : shen beide
====================================================================*/

#if !defined(_LEX_H)
#define _LEX_H

#include "PubHeader.h"
#include "Lexbase.h"
#include "ObArray.h"
#include "StringObject.h"

/*
#define _LEX_DEBUG_ON_
*/

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// 基本定义规则说明: 字符(集)或SubRULE + 重复次数定义 
//               
// \.  	 匹配除换行符外的任何字符，“.”等于是字符集[^\n\r](Window)或[^\n]( Unix)的简写。
// \b    匹配一个单词的开始或结尾   匹配一个单词边界，也就是指单词和空格间的位置。
// ^ 	 匹配字符串的开始           作为多行匹配的时候，匹配行的开始 '\r\n'或'\n'
// $ 	 匹配字字符串的结尾         作为多行匹配的时候，匹配行的结束。
// \d 	 任何数字
// \c    字母([a-zA-Z]) 
//
// *     重复任意次数            
// +     重复一次或多次 
// ?     重复一次或0次 
// <n>   重复n次 
// <n,m> 重复最少n次，最多m次 
// <n,>  重复最少n次 
//
// ( )   分组操作符。
// [ ]   范围之内, 字符集定义(支持标准的256个ASCII字符), 除]\和第一个字符是^$, 其他的字符不需要转意
// [^]	 范围之外, 除]\之外的字符不需要转意
// |     选择(或)
//
// {name}     引用已定义规则
// {name Id}  引用已定义规则, 并将匹配串以Token中的ParamList[Id]返回
//            如果整个规则集未有自定义的ParamId,则系统默认会将最外层的子分组和引用按顺序返回      
//
// {?[ ]}     遇到范围之内的字符前时停止(范围定义同上), 否则继续, 该定义不支持重复(因为必然为死循环)
// {?=str}    在str前停止, 该定义不支持重复(因为必然为死循环), str必须存在
// {?>str}    在str后停止, 该定义不支持重复, str必须存在
//            尽量采用以上连续分析模式,可以有效减少递归分支数目,提高速度
//
//
// 注: 1. ^$*+?<[()|{} 是具有特殊含义的字符, 
//                     
//                     如果要使用其原始含义,需要在字符前加上转义符\\
//
//        [ ] 中除了首字符可能为^(表示非包含), 以上的特殊含义字符不再具有特殊意义, 但对-(){}需要加上\\
//            可以含\\d \\c \\. 方便表示一个集合
//
//     2. 在*+?<>重复次数定义后, 若再加?, 表示非贪婪模式(重复次数尽可能少)
//
////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
template class CLASS_EXPORT TObArray<LexState>;
template class CLASS_EXPORT CObjectPool_<MatchPattern>;
template class CLASS_EXPORT TObArray<MatchPattern>;  
#endif

//////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class CLASS_EXPORT LexRules
#else
class LexRules
#endif
{
public:
    LexRules();
   ~LexRules();
    
    bool AddRule(long Id, char* szRule);
    bool AddRule(long Id, char* szRuleName, char* szRule);
    int  GetRuleNum();

    LexState* FoundRule(long  Id);
    LexState* FoundRule(char* szName,long* pId=NULL);
    
    bool Optimize();
    
    bool Dump(char* filename,bool bOverWrite=true);
    bool DumpRule(long Id,OTSTR& strRule);

    void Clear();

    OTSTR& GetLastError() { return m_strLastError;  }
    
private:
    LexState* BuildRule(long Id, char* szRule);
    LexState* NewLexState();

    CharSet*  GetCharSet(char* &szRule);
    RepeatAttribute* GetRepeatAttribute(char* &szRule);
    char GetChar(const char*& pFrom,bool& bIsEscape);
    long GetLong(const char*& pFrom);
        
    bool DumpRule (LexState* pEntry, OTSTR& strRule);
    bool CheckRule(LexState* pEntry, bool ParamList[]);
        
private:    
    friend class LexState;
    friend class CLex;

    /////////////////////////////////////////
    TObArray<LexState>  m_RuleEntryList;
    TObArray<LexState>  m_StateObjectList;  // 方便删除
    
    bool                m_bHasCustomReturnParam;
    bool                m_bEnableLineBoundCheck;      
    bool                m_bEnableWordBoundCheck;      
    
    OTSTR    m_strLastError;
};

//////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class CLASS_EXPORT LexToken: public TObject
#else
class LexToken: public TObject
#endif
{
public:
    enum { TOKEN_INVALID=-1, TOKEN_UNMATCH=0 };  // system Reserved TokenId

private:
    long     m_TokenId;     // RuleId
    OTSTR 	 m_TokenName;
    Location m_TokenLocation;
    long     m_TokenLen;

    int      m_ParamNum;
    long     m_ParamLocatList[MAX_LEXPARAM_ID+1][2];   // [2] begin(相对位置),len   initial: -1,-1
    
public:
    LexToken();
    LexToken(long TokenId,char* name,long namelen=-1);

    ////////////////////////////////////////////////
    long      getTokenId()  { return m_TokenId; }
    OTSTR&    getName()     { return m_TokenName;  }
    Location& getLocation() { return m_TokenLocation; }
    long      getTokenLen() { return m_TokenLen;  }
    int       getParamNum() { return m_ParamNum;  }
    bool      getParam(long ParamId, OTSTR& strRet);
    
    bool isToken(long TokenId) { return (m_TokenId==TokenId)? true:false; }
    
    void set(long TokenId,char* name, long namelen=-1);
    void setTokenId(long TokenId);
    void setLocation(long locat,long nline,long ncolumn=-1);
    void setLocation(Location& locat);
    void setTokenLen(long len);

    void operator=(const LexToken& right);
    void clone(const LexToken& right);
    
protected:
    friend class CLex;
};

//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class CLASS_EXPORT CLex
#else
class CLex
#endif
{
public:
    enum { UNRETURN_RULE_BEGIN_ID=1000, //GetToken时不作为Token返回, 合法Token, 但忽略
           INTERNAL_RULE_BEGIN_ID=2000  //内部子流程(由其他流程调用),不作为词法分析入口
    };   

    enum { GET_TOKEN_EOF=0, GET_TOKEN_SUCC=1, GET_TOKEN_FAIL=-1 };

public:
    CLex();
    virtual ~CLex();

    virtual char* GetName() { return ""; }
    virtual char* GetPath() { return ""; }
    virtual char* GetAbsoluteFilename() { return ""; }
    
    void  setRules(LexRules* pLexRules);
    bool  FoundRule(long  Id);
    bool  FoundRule(char* szName,long* pId=NULL);
    
    void  Enable_OverlapMatch(bool bEnableOverlapMatch=true);    // 否则每次GetToken会清空MatchPatternList
    void  Enable_ReturnUnMatchedContent(bool bReturnUnMatchedContent=true);  // match and unmatch(TokenType=Other)
    void  Enable_CaseSensitive(bool bCaseSensitive=true);
    void  SetWordBoundMode(int mode);  //  mode=0  (0x20 <ch< 0x7F)与其他字符的交界认为是Wordbound
                                       //      =1  (0x00<=ch<=0x20)与其他字符的交界认为是Wordbound,用于中文识别

    void  setLocatOffset(Location& locat);
    Location& getLocatOffset();
    
    void  setBuffer(char* pbuf, long buflen=-1);
    char* getBuffer() { return m_pbuf;   }
    long  getBufLen() { return m_buflen; }

    virtual void Reset(bool bResetBuffer);
    
    /////////////////////////////////////////////////////////////////////
    // Params: bJustPreview=false  Get & move out next Token
    //         bJustPreview=true   Just read next Token (not move out)
    virtual int  GetToken(LexToken& Token, bool bJustPreview=false);   
    virtual int  GetToken(LexToken& Token, WORD nExFlag, bool bJustPreview);
    virtual bool GetSpecificToken(LexToken& Token, long TokenId); // 0<TokenId
    
    bool  Fetch_string(char* szLeftOperator, char* szRightOperator, bool bStartWithLeftOperator, // 考虑了配对的() [], 当前buf必须以LeftOperator开头
                       bool bReturnBetween, OTSTR& strReturn);  // bReturnBetween决定返回串是否包含Left & Right Operator
                                                                // bStartWithLeftOperator只有当szLeftOperator!=NULL时有效
    bool  ForwardLocatTo(long nLocat);

    virtual Location& getLocation() { return m_location; }
    virtual bool  setLocation(Location& locat);

    OTSTR& GetLastError()   { return m_strLastError;  }
    
private:
    int   GetToken_(LexToken& Token, long RuleId, bool bJustPreview);   

    bool  TryFrom(Location& Locat, long RuleId=-1); // 广度优先
    bool  PriTryFrom(Location& Locat);              // 深度优先
    bool  InputChar (long nCurLocat,short eChar,bool& bContinue);
    bool  Transition(long nCurLocat,short eChar,bool bCaseSensitive=true,short eCharReverse=0);

    void  DumpStack(char* filename,bool bOverWrite=true);
    
    bool  isWordBound(unsigned char charLeft,unsigned char charRight);
    short CharReverse(short eChar);

    void  Clear_MatchPatternList(TObArray<MatchPattern>& PatternList);

    void  CreateTokenFromPattern(MatchPattern& Pattern, LexToken& Token);

    ////////////////////////////////////////////
    CObjectPool_<MatchPattern>  m_MatchPatternPool;
    
    MatchPattern* New_MatchPattern(MatchPattern* pClonePattern=NULL);
    void  Delete_MatchPattern(MatchPattern* pPattern);
    
protected:
    enum { CHECK_TOP_STATE=300 };
    
    char*     m_pbuf;
    long      m_buflen;
    Location  m_location;
    
    LexRules* m_pLexRules;
    bool      m_bUserOptimizedMode;
    bool      m_bReturnUnMatchedContent;    // default: true
    bool      m_bEnableOverlapMatch;        // default: false
    bool      m_bCaseSensitive;             // default: true
    int       m_nWordBoundCheckMode;        // default: 1
    Location  m_locationOffset;

    OTSTR     m_strLastError;
    
    TObArray<MatchPattern>  m_MatchPatternList;  

    //////////////////////////////////
    friend class GramParser;
};

/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
#ifdef _DLL_PROJECT
class CLASS_EXPORT LexPattern
#else
class LexPattern
#endif
{
public:
    LexPattern(char* szRule=NULL);
   ~LexPattern();

    bool AddRule(bool bMainAccess,char* szRule);  // bMainAccess区分是入口还是非入口(内部Rule)
    bool AddRule(bool bMainAccess,char* szRuleName,char* szRule);
    void Clear();

    void Enable_CaseSensitive(bool bCaseSensitive) { m_bCaseSensitive=bCaseSensitive; }
    
    bool Matching(char* szString,OtstrArray* lpParamArray=NULL);

    OTSTR& GetLastError() { return m_strLastError;  }
    
protected:
    LexRules m_Rules;
    CLex     m_Lex;
    bool     m_bCaseSensitive;      // default: true
    
    OTSTR    m_strLastError;
    
private:
    long     m_InternalRuleCounter;
};


#endif


