#if !defined(_CPLUSANALYSER_H)
#define _CPLUSANALYSER_H

#include "../Include/RunTimeEnv.h"
#include "../Include/GramParser.h"


////////////////////////////////////////////////////
class Program;
class Procedure;
class Statement_while;

#ifdef _DLL_PROJECT
class CLASS_EXPORT CSyntaxObject: public TObject
#else
class CSyntaxObject: public TObject
#endif
{
public:
    enum {  OBJ_NULL        =-1, 
            OBJ_DEFINE      = 1 , OBJ_ENUM =2, 
            OBJ_STRUCTDEF   = 3,  
            OBJ_VARIABLEDEF = 4,
            OBJ_DECLARESTRUC= 5,

            /////////////////////////////
            // SyntaxObject
            OBJ_PROGRAM     = 6,      // pParent =NULL, MAIN_PROGRAM 相互之间跨文件
                                      // pParent!=NULL, SUB_PROGRAM, MAIN_PROGRAM can include many SUB PROGRAM 
            OBJ_PROCEDURE   = 9,
            OBJ_EXPRESSION  = 10,
            OBJ_WHILE       = 11, 
            OBJ_IF          = 12,  
            OBJ_JUMP        = 13,

            OBJ_TYPEDEF     = 20,
    };
    
public:
    CSyntaxObject(CSyntaxObject* pUpLink,CSyntaxObject* pParent);
    virtual ~CSyntaxObject();

    static bool Initial();          // 程序开始时调用一次
    static void Destroy();          // 程序结束时调用一次
    
    void SetParent(CSyntaxObject* pParent);
    CSyntaxObject* GetParent()  { return m_pParent; }

    Program*   GetAdjacentProgram(bool bIncludeThis); // 往上最近的Program, 可包含自身
    Program*   GetMainProgram();                      // 单个文件入口
    Program*   GetRootProgram();                      // 总入口
    Procedure* GetParentProcedure();
    Statement_while* GetAdjacentWhile();

    void setLocatBegin(Location& locat);
    void setLocatEnd(Location& locat);

    Location& getLocation() { return m_location; }
    long      getLen()      { return m_len; }
    
    ///////////////////////////////////////////////////
    virtual bool ValidityCheck(OTSTR& strError) { return true; }    // Variable,struct的名字在生成时候已经做检查, 这里主要对语句中exp,program做检查
    
    virtual bool Execute(ExecuteEnv& Env,long nCurLine=-1) = 0;

protected:
    CSyntaxObject* m_pParent;            
    CSyntaxObject* m_pUpLink;            
    static WORD    m_IdentifyCounter;
    
    static GramRules m_GramRule[10];

    /////////////////////////////////////////////////
    virtual TObject* GetDefinitionOwner() { return NULL; } 

    TObject* GetAdjacentDefinitionOwner(bool bIncludeThis); // 往上最近的VariableDefinition, StructDefinition
    
private:
    Location       m_location;
    long           m_len;
};

///////////////////////////////////////////////
class NewTypeDef: public TObject   
{
    ///////////////////////////////////////////////
    // syntax:  typedef  definedType  newType;          
    ///////////////////////////////////////////////
    
public:
    OTSTR    m_strNewTypeName;
    TObject* m_pOldTypeDefinition;
        
public:
    NewTypeDef()
    {
        m_pOldTypeDefinition=NULL;
    }
    virtual ~NewTypeDef() 
    {
    }

    int ObjectTypeId()  { return CSyntaxObject::OBJ_TYPEDEF; }
};

#ifdef _DLL_PROJECT
class CLASS_EXPORT TypeSpecifier: public TObject
#else
class TypeSpecifier: public TObject
#endif
{
public:
    VariableItemAttr::type_ m_nType;

    VariableItemAttr::type_ m_nExType;
    OTSTR                   m_strTypeName;

    StructDefinition*       m_pStructDefinitionObject; // For STRUCT type

public:
    TypeSpecifier()  { m_pStructDefinitionObject=NULL; }
    TypeSpecifier(TypeSpecifier& pType) { *this=pType; }
   ~TypeSpecifier()  {}

    void operator=(const TypeSpecifier& right)
    {
        this->m_nType  =right.m_nType;
        this->m_nExType=right.m_nExType;
        this->m_strTypeName=right.m_strTypeName;
        this->m_pStructDefinitionObject=right.m_pStructDefinitionObject;
    }
};

///////////////////////////////////////////////////////////////////
/*
 TObject 
   |  |
   |  |-> LexToken
   |      ExprNode
   |      TypeSpecifier
   |      CEnumItem
   |      CEnumItemList
   |      VariableDefinition   
   |      StructDefinition 
   |      DeclareMapItemGrp
   |
   |----> CSyntaxObject
            Program
            Procedure
            Statement_jmp
            Statement_expr
            Statement_while
*/

///////////////////////////////////////////////////////////////////
class CProcedure;
class DeclareMapItemGrp;
class AttributeDefinition;

class Program: public CSyntaxObject
{
protected:
    ///////////////////////////////////////////////
    EnumItemList                 m_DefineList;       // data_content is Number|string
    
    TObArray<TObject>            m_ItemList;         // Elements Sequence (sub program and statement) -> for execute
                                                     //                    other define enum 
                                                     //                    mainprogram(included)
                                                     // Ptr + locatline
    TObArray<TObject>            m_ItemObjectList;   // 对象实体   // Include, Procedure, struct

    TObArray<StructDefinition>   m_PreDefinedStructList;
    TObArray<Procedure>          m_PreDefinedProcedureList;

public:
    Program(CSyntaxObject* pUpLink,CSyntaxObject* pParent,bool bAttachedProgram=false);
    virtual ~Program();

    virtual Program* NewProgram(CSyntaxObject* pUpLink,CSyntaxObject* pParent,bool bAttachedProgram=false);
    virtual VariableDefinition*  NewVariableDefinition(StructDefinition* pParent,WORD nIdentifierId);
    virtual AttributeDefinition* NewAttributeDefiniton(TObject* pOwner,CSyntaxObject* pUpLink,CSyntaxObject* pParent);
    virtual StructDefinition*    NewStructDefiniton(WORD nIdentifierId);
    virtual void DeleteStructDefiniton(StructDefinition* pStructDefinition);

    /////////////////////////////////////////////////////
    int  ObjectTypeId()  { return OBJ_PROGRAM; }
    bool isMainProgram() { return (m_pParent==NULL)? true:false; }
    
    bool Analysis(CPlusLex& Lex, bool bValidityCheck, OTSTR& strErr);
    
    bool Execute(ExecuteEnv& Env,long nCurLine=-1);
    
    bool Dump(char* filename, bool bHasHeader=true, bool bCompactMode=false);

    ////////////////////////////////////////////////
    CEnumItem*          Get_ConstItem(char* szName, bool bOnlyInCurrentProgram=false, long nLineLimit=-1);
                                      //    szName: EnumName::ItemName  ( search in EnumItemList )
                                      //            ItemName            ( search in DefineList   )
    VariableDefinition* Get_VariableDefinition(char* varname, bool bOnlyInCurrentProgram=false, long nLineLimit=-1);   // 取得距离最近的Var
    StructDefinition*   Get_StructDefinition(char* name, bool bOnlyInCurrentProgram=false, long nLineLimit=-1);        
    DeclareMapItemGrp*  Get_DeclareMapItemGrp(char* name, bool bOnlyInCurrentProgram=false, long nLineLimit=-1);     
    Procedure*          Get_Procedure(char* name, bool bOnlyInCurrentProgram=false, long nLineLimit=-1);     
    CEnumItem*          Get_DefineItem  (char* szItemName, bool bOnlyInCurrentProgram=false, long nLineLimit=-1);
    EnumItemList*       Get_EnumItemList(char* szEnumName, bool bOnlyInCurrentProgram=false, long nLineLimit=-1);

    long                Get_DefinitionNum(long ObjectTypeId);        

    TObject*            Get_DefinitionObject(WORD nIdentifierId, bool bOnlyInCurrentProgram=false); 

    void                Add_SyntaxObject(TObject* pObject, long nLine, bool bTrueObject);
    void                Rmv_SyntaxObject(TObject* pObject, bool bDeleteObject);
    
    //////////////////////////////////////////////////////////
    static DWORD GetConstValueProc(void* pParent, unsigned int params_num, DWORD params[]); //Syntax: A  or  A::B

    static DWORD Func_Program       (void* pParent, unsigned int params_num, DWORD params[]);
    static DWORD Func_Statement     (void* pParent, unsigned int params_num, DWORD params[]);
    static DWORD Func_Type_specifier(void* pParent, unsigned int params_num, DWORD params[]);
    static DWORD Func_Expression    (void* pParent, unsigned int params_num, DWORD params[]);
    static DWORD Func_InitializerExp(void* pParent, unsigned int params_num, DWORD params[]);
    static DWORD Func_StatementExp  (void* pParent, unsigned int params_num, DWORD params[]);
        
protected:
    OTSTR  m_strRemarkBegin;
    OTSTR  m_strRemarkEnd;
    
    bool   m_bAttachedProgram;
    
    OTSTR m_strAbsoluteFilename;
    OTSTR m_strDisplayFilename;
    OTSTR m_strFileName;            // 纯文件名
    void  setDisplayFileName(char* filename) { m_strDisplayFilename=filename;  }
    void  setIncludeFileName(char* AbsoluteFilename,char* filename) { m_strAbsoluteFilename=AbsoluteFilename; m_strFileName=filename;  }
    
    virtual bool Analysis(CPlusLex& Lex, CErrHandler& ErrHandler);
    
    bool  proc_Include(CPlusLex& Lex, CErrHandler& ErrHandler);
    bool  Proc_TypeDef(CPlusLex& Lex, CErrHandler& ErrHandler);
    bool  Proc_Enum   (CPlusLex& Lex, CErrHandler& ErrHandler);
    bool  Proc_Define (CPlusLex& Lex, CErrHandler& ErrHandler);
    bool  proc_Struct (CPlusLex& Lex, CErrHandler& ErrHandler);
    bool  proc_VarDefinition (CPlusLex& Lex, CErrHandler& ErrHandler,bool bisExtern); // try
    bool  proc_ProcDefinition(CPlusLex& Lex, CErrHandler& ErrHandler,bool bisExtern); // try
    bool  proc_Statement (CPlusLex& Lex, CErrHandler& ErrHandler);                    // try
    bool  proc_DeclareMap(CPlusLex& Lex, CErrHandler& ErrHandler);    
    
    virtual bool proc_CustomAttrib(CPlusLex& Lex, CErrHandler& ErrHandler);  

    DWORD DoFunction(cCallback::tFunction pFunction,CPlusLex& Lex, CErrHandler& ErrHandler);
        
    ////////////////////////////////////////////////
    Program*     Get_IncludedProgram(char* szfilename);
    bool         isNetWorkTranMode_L_TO_H();

    ////////////////////////////////////////////////
    // Used for Definition
    bool is_Identifier_Used(char* name, bool bOnlyInCurrentProgram, bool bAlsoCheckProcName=true);  
    StructDefinition* Get_PreDefined_Struct(char* name,bool bRemoveOut);  
    Procedure* Get_PreDefined_Procedure(char* name,bool bRemoveOut);  
    
    /////////////////////////////////////
    bool ValidityCheck(OTSTR& strError);
    bool ValidityCheck_StructLoop(StructDefinition* pStructDefinition);

    bool Check_Expression(Location Locat, char* szExpression, WORD nTokenExStyle,  CErrHandler& ErrHandler);  // nLineLocat=nLineLimit
    bool Check_Expression(ExprNode* pExprNode, CErrHandler& ErrHandler);
    virtual bool Check_varIdent(StructDefinition* pCurStructDefinition, Location Locat, char* varString, CErrHandler& ErrHandler);   // A.B[..].C[.f().].D
    
    bool isTrueObject(TObject* pObject,long nLine);

    /////////////////////////////////////////
    void Clear();
    
    void Dump(FILE* fp, OTSTR strHeader, bool bCompactMode);
    void DumpStatement(FILE* fp, CSyntaxObject* pObject, long nLine, long MaxLineIdLen,
                       char* sItemHeaderFormat, char* sItemFormat, OTSTR& strHeader,OTSTR& strNextHeader, bool bCompactMode);
    void DumpStatement(FILE* fp, CSyntaxObject* pObject, long nLine, long MaxLineIdLen, OTSTR strHeader,  bool bCompactMode);

    virtual void DumpCustomAttrib(FILE* fp, char* sItemHeaderFormat, char* sItemFormat, OTSTR& strHeader,OTSTR& strNextHeader, bool bCompactMode) {}
    
    long GetMaxLineIdLen();

    bool m_bLoopMark;
    
private:
    friend class ExecuteEnv;
    friend class RunTimeStk;
    friend class GramParser;
    friend class Procedure;
    friend class Statement_expr;
    friend class Statement_jump;
    friend class Statement_if;
    friend class Statement_while;
};

/////////////////////////////////////////////////////////////////
class Statement_expr: public CSyntaxObject
{
protected:
    ///////////////////////////////////////////////
    // syntax:  exp;
    //          ;
    ///////////////////////////////////////////////

    ExprNode*  m_pExprNode;
    
public:
    Statement_expr(CSyntaxObject* pUpLink,CSyntaxObject* pParent);
   ~Statement_expr();
        
    int  ObjectTypeId()  { return OBJ_EXPRESSION; }

    void Combine(ExprNode* pExpr);

    /////////////////////////////////
    bool Execute(ExecuteEnv& Env,long nCurLine=-1);

private:
    bool ValidityCheck(OTSTR& strError);
    
    friend class Program;
};

/////////////////////////////////////////////////////////////////
class Statement_jump: public CSyntaxObject
{
protected:
    ///////////////////////////////////////////////
    // syntax:  return [Expr];
    //          break;
    //          continue;
    ///////////////////////////////////////////////
    
    OTSTR      m_strJumpName;
    ExprNode*  m_pExprNode;
    
public:
    Statement_jump(CSyntaxObject* pUpLink,CSyntaxObject* pParent);
   ~Statement_jump();
    
    int  ObjectTypeId()  { return OBJ_JUMP; }
    
    void Combine(char* szJumpName,ExprNode* pExpr=NULL);
    
    /////////////////////////////////
    bool Execute(ExecuteEnv& Env,long nCurLine=-1);
    
private:
    bool ValidityCheck(OTSTR& strError);
    
    friend class Program;
};

/////////////////////////////////////////////////////////////////
class Statement_if: public CSyntaxObject
{
protected:
    ///////////////////////////////////////////////
    // syntax:  if (Exp) statement
    //          if (Exp) statement else statement
    ///////////////////////////////////////////////
    
    ExprNode*       m_pExprNode;
    CSyntaxObject*  m_pStatement1;     
    CSyntaxObject*  m_pStatement2;     
    
public:
    Statement_if(CSyntaxObject* pUpLink,CSyntaxObject* pParent);
   ~Statement_if();
    
    int  ObjectTypeId()  { return OBJ_IF; }
    
    void Combine(ExprNode* pExpr,CSyntaxObject* pStatement1,CSyntaxObject* pStatement2);
    
    /////////////////////////////////
    bool Execute(ExecuteEnv& Env,long nCurLine=-1);
    
private:
    bool ValidityCheck(OTSTR& strError);
    
    friend class Program;
};

/////////////////////////////////////////////////////////////////
class Statement_while: public CSyntaxObject
{
protected:
    ///////////////////////////////////////////////
    // syntax:  while (Exp) Program
    ///////////////////////////////////////////////
    
    ExprNode*       m_pExprNode;
    CSyntaxObject*  m_pStatement;     
    
public:
    Statement_while(CSyntaxObject* pUpLink,CSyntaxObject* pParent);
   ~Statement_while();
    
    int  ObjectTypeId()  { return OBJ_WHILE; }
    
    void Combine(ExprNode* pExpr,CSyntaxObject* pStatement);
    
    /////////////////////////////////
    bool Execute(ExecuteEnv& Env,long nCurLine=-1);
    
private:
    bool ValidityCheck(OTSTR& strError);
    
    friend class Program;
};

/////////////////////////////////////////////////////////////////
#define PROCEDURE_RETNAME        "Return"

#ifdef _DLL_PROJECT
class CLASS_EXPORT Procedure: public CSyntaxObject
#else
class Procedure: public CSyntaxObject
#endif
{
protected:
    ///////////////////////////////////////////////
    // syntax:  simple_type ProcName(...,...)
    //          {
    //             ......
    //          }
    ///////////////////////////////////////////////
    
public:
    Procedure(CSyntaxObject* pUpLink,CSyntaxObject* pParent);
   ~Procedure();

    int    ObjectTypeId()  { return OBJ_PROCEDURE; }

    OTSTR& GetProcName() { return m_strProcName; }
    
    long   GetVarParamsCount() { return m_VariableParamsDefList.GetVariableCount(); }
    int    GetProcReturnType() { return m_ReturnType.m_nType; }

    bool   setReturn(ExecuteEnv& Env,char* szData);       // 置返回值
    bool   setReturn(ExecuteEnv& Env,CVarient& retData);  // 置返回值
    
protected:
    Location            m_Location;
    bool                m_bExtern;
    OTSTR               m_strProcName;
    TypeSpecifier       m_ReturnType;               // 返回变量 size always=1
    StructDefinition    m_VariableParamsDefList;    // 参量定义
    bool                m_bHasDynamicArgList;

    Program*            m_pProgram;                 // Procedure body
    
    void   Combine(bool bExtern,char* szProcName,TypeSpecifier& ReturnType,StructDefinition* pVariableParamsList, bool bHasDynamicArgList);
    void   SetProcBody(Program* pProgram);
    void   SetLocation(Location& locat) { m_Location=locat; }   // setBody location

    bool   ValidityCheck(OTSTR& strError);
    
    bool   Execute(ExecuteEnv& Env,long nCurLine=-1);

    OTSTR  DumpHeader();
    static OTSTR DumpHeader(bool bExtern, char* szProcName,TypeSpecifier& ReturnType,StructDefinition* pVariableParamsList,bool bHasDynamicArgList);

private:
    friend class Program;
    friend class ExecuteEnv;
    
    bool GenerateProcParamsList(RunTimeStk* pRunTimeStk,char* szParams,TObArray<CVariableItem>& ReturnParamsList,TObArray<CVarient>& ProcedureArgList);

};


////////////////////////////////////////////////////////////////
class DeclareMapItemGrp: public TName, public TObject
{
public:
    enum { MAP_ITEM=0, MAP_IMPLICITITEM=1 };

protected:
    ///////////////////////////////////////////////
    // syntax:  varname [nTag] type
    //          varname [nTag] structname
    //          varname [nTag] TypeOf structname 
    ///////////////////////////////////////////////

    int  m_MapType;
    TObArray<VariableDefinition> m_ItemMap;

public:
    DeclareMapItemGrp(CSyntaxObject* pParent);
   ~DeclareMapItemGrp();
    
    int  ObjectTypeId() { return CSyntaxObject::OBJ_DECLARESTRUC; }

    void setMapType(int type) { m_MapType=type; }
    int  getMapType() { return m_MapType; }
    
    int  GetCount();
    void RemoveAll(bool bDeleteObject=true);

    void Add(VariableDefinition* pItem, long  nTag, StructDefinition*  pTypeOfStructDefinition=NULL);

    bool GetAt(int nIndex, long* pTag, VariableDefinition** pItem, StructDefinition** pTypeOfStructDefinition=NULL);
    bool Find(long nTag, VariableDefinition** pItem=NULL, StructDefinition** pTypeOfStructDefinition=NULL); 
    VariableDefinition* GetVariableDefinition(WORD nIdentifierId); 
    
protected:
    CSyntaxObject* m_pParent;
};

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
#define TYPEOF           "TypeOF"        // FOR struct's varItem
#define DUMPOF           "DumpOF"        // FOR struct's varItem  only for number
#define PROC_TRANSLATE   "Translate"     // FOR struct's varItem  ( 如果有typeOf, translate不允许)
#define CHOICEMAP        "ChoiceMap"     // FOR struct's varItem(choice)
#define PROC_DUMP        "Dump"          // FOR struct or vaItem,  pri > var's dump
#define PROC_INTEGRATE   "Integrate"     // FOR struct
#define INTEGRATEOF      "="             // FOR struct

#define AttributeNum     8

class AttributeDefinition: public Program
{
public:
    enum { TYPEOF_ID=0, DUMPOR_ID=1, DUMPEQL_ID=2, PROC_TRANSLATE_ID=3, PROC_INTEGRATE_ID=4, PROC_DUMP_ID=5, 
           INTEGRATEOF_ID=6, CHOICEMAP_ID=7 };
    
public:
    AttributeDefinition(TObject* pOwner,CSyntaxObject* pUpLink,CSyntaxObject* pParent);
   ~AttributeDefinition();

    static bool Initial();

    DWORD GetAttrData(int AttrId);
    bool  SetAttrData(int AttrId, DWORD Data);
    char* GetAttrName(int AttrId);
        
    bool  proc_CustomAttrib(CPlusLex& Lex, CErrHandler& ErrHandler);  
    bool  Check_varIdent(StructDefinition* pCurStructDefinition, Location Locat, char* varString, CErrHandler& ErrHandler);

    bool  CompleteIt(OTSTR& strError);   // Check Relate Procedure
        
    void  DumpCustomAttrib(FILE* fp, char* sItemHeaderFormat, char* sItemFormat, OTSTR& strHeader,OTSTR& strNextHeader, bool bCompactMode);
    
protected:
    TObject*  m_pOwner;
    DWORD     m_AttrDataList[AttributeNum];
    
    static GramRules m_AttribRule[1];

    /////////////////////////////////////////////////
    TObject* GetDefinitionOwner() { return m_pOwner; }  
    
private:
    friend class TVariableDefinition;
};

//////////////////////////////////////////////////////
class TVariableDefinition: public VariableDefinition
{
public:
    TVariableDefinition();
    TVariableDefinition(StructDefinition* pParent,WORD nIdentifierId);
    virtual ~TVariableDefinition();
    
    StructDefinition* GetTypeOf();
};

class TStructDefinition: public StructDefinition
{
public:
    TStructDefinition();
    TStructDefinition(WORD nIdentifierId);
    virtual ~TStructDefinition();
    
protected:
    bool GetIntegratedType(int* type=NULL);
    
    bool CompleteIt(OTSTR& strError);   // Check Attribute 
    
    friend class Program;
};


#endif






















