/*****************************************************************************/
/**                     Microsoft LAN Manager                               **/
/**             Copyright(c) Microsoft Corp., 1987-1999                     **/
/*****************************************************************************/
/*****************************************************************************
File            : gramutil.hxx
Title           : grammar utility module
Description     : contains definitions associated with the grammar and
                : associated routines
History         :
    05-Sep-1990 VibhasC     Created
    11-Sep-1990 VibhasC     Merged gramdefs.hxx into this one for easy
                            maintainability
    20-Sep-1990 NateO       Safeguards against double inclusion, added
                            include of rpctypes, common
*****************************************************************************/
#ifndef __GRAMUTIL_HXX__
#define __GRAMUTIL_HXX__

#include "allnodes.hxx"
#include "symtable.hxx"
#include "idict.hxx"

extern "C" {
#include "lex.h"
}

/***************************************************************************
 *              prototypes of all grammar related utility routines
 ***************************************************************************/
void        BaseTypeSpecAnalysis( struct _type_ana *, short );
void        SignSpecAnalysis( struct _type_ana *, short );
void        SizeSpecAnalysis( struct _type_ana *, short );
void        ParseError( STATUS_T , char *);
STATUS_T    GetBaseTypeNode( node_skl **, short, short, short, short typeAttrib = 0);
STATUS_T    GetBaseTypeNode( node_skl **, struct _type_ana );

/***************************************************************************
 *              general definitions
 ***************************************************************************/
//
// definitions for type specification and analysis
//

// basic types

#define TYPE_UNDEF      (0)
#define TYPE_INT        (1)
#define TYPE_FLOAT      (2)
#define TYPE_DOUBLE     (3)
#define TYPE_VOID       (4)
#define TYPE_BOOLEAN    (5)
#define TYPE_BYTE       (6)
#define TYPE_HANDLE_T   (7)
#define TYPE_PIPE       (8)
#define TYPE_FLOAT80    (9)
#define TYPE_FLOAT128   (10)

// sizes of basic types

#define SIZE_UNDEF      (0)
#define SIZE_CHAR       (1)
#define SIZE_SHORT      (2)
#define SIZE_LONG       (3)
#define SIZE_HYPER      (4)
#define SIZE_SMALL      (5)
#define SIZE_LONGLONG   (6)
#define SIZE_INT64      (7)
#define SIZE_INT32      (8)
#define SIZE_INT3264    (9)
#define SIZE_INT128     (10)

// signs

#define SIGN_UNDEF      (0)
#define SIGN_SIGNED     (1)
#define SIGN_UNSIGNED   (2)

// attribs

#define ATT_NONE        (0)
#define ATT_W64         (1)

#define SET_ATTRIB(x,att)   (x = x | att)
#define SET_TYPE(x,type)    (x = x | (type << 4 ))
#define SET_SIZE(x,size)    (x = x | (size << 8))
#define SET_SIGN(x,sign)    (x = x | (sign << 12))
#define GET_ATTRIB(x)       (x & 0x000f)
#define GET_TYPE(x)         ((x & 0x00f0) >> 4)
#define GET_SIZE(x)         ((x & 0x0f00) >> 8)
#define GET_SIGN(x)         ((x & 0xf000) >> 12)

#define MAKE_TYPE_SPEC(sign,size,type, attrib) ((sign << 12) | (size << 8) | (type << 4) | attrib)

//
// array bounds
//
#define DEFAULT_LOWER_BOUND (0)


/*****************************************************************************
 *      definitions local to the parser
 ****************************************************************************/
struct _type_ana
    {
    short TypeSize;     // char/short/small/hyper/long/etc
    short BaseType;     // int/float/double/void/bool/handle_t ect
    short TypeSign;     // signed/unsigned
    short TypeAttrib;   // vanilla/__w64
    };

class _DECLARATOR
    {
public:
    class node_skl *    pHighest;
    class node_skl *    pLowest;


    void                Init()
                            {
                            pHighest = (node_skl *) NULL;
                            pLowest  = (node_skl *) NULL;
                            };

    void                Init( node_skl * pSoloNode )
                            {
                            pHighest = pSoloNode;
                            pLowest  = pSoloNode;
                            };

    void                Init( node_skl * pTop, node_skl * pBottom)
                            {
                            pHighest = pTop;
                            pLowest  = pBottom;
                            };


    void                ReplTop( node_skl * pTop )
                            {
                            pTop->SetChild( pHighest->GetChild() );
                            pHighest = pTop;
                            };

//  void                MergeBelow( _DECLARATOR & dec );

    };

// declarator lists are maintained as circular lists with a pointer to the
// tail element.  Also, the list pointer is a full entry, not just a pointer.

class _DECLARATOR_SET;
class DECLARATOR_LIST_MGR;

class _DECLARATOR_SET: public _DECLARATOR
    {

private:
    class _DECLARATOR_SET * pNext;
    friend class DECLARATOR_LIST_MGR;

public:
    void    Init()
                {
                pNext = NULL;
                pHighest = NULL;
                pLowest = NULL;
                };

    void    Init( _DECLARATOR pFirst )
                {
                pHighest = pFirst.pHighest;
                pLowest  = pFirst.pLowest;
                pNext    = NULL;
                };

    void    Add(  _DECLARATOR pExtra )
                {
                // skip empty declarator
                if (pExtra.pHighest == NULL)
                    return;

                // fill in anchor if empty
                if (pHighest == NULL)
                    {
                    Init( pExtra);
                    return;
                    };

                // create a new link node, and fill it in
                _DECLARATOR_SET * pNew = new _DECLARATOR_SET;

                pNew->pHighest = pExtra.pHighest ;
                pNew->pLowest  = pExtra.pLowest ;

                if ( pNext )
                    {
                    // point pNext to list head (tail's tail)
                    // point tail to new one
                    pNew->pNext = pNext->pNext;
                    pNext->pNext = pNew;
                    }
                else
                    {
                    pNew->pNext = pNew;
                    }

                // advance tail pointer
                pNext = pNew;
                };
    };


class DECLARATOR_LIST_MGR
    {
    class   _DECLARATOR_SET *   pCur;
    class   _DECLARATOR_SET *   pAnchor;

public:

                    DECLARATOR_LIST_MGR(_DECLARATOR_SET & First)
                        {
                        _DECLARATOR_SET * pTail = First.pNext;

                        pCur    = NULL;
                        pAnchor = &First;

                        // break the circular list, so first points to head
                        // of list, and tail points to NULL
                        if (pTail)
                            {
                            First.pNext = pTail->pNext;
                            pTail->pNext  = NULL;
                            }
                        };

        // return next element
    _DECLARATOR *   DestructiveGetNext()
                        {
                        _DECLARATOR_SET * pLast = pCur;

                        // delete the element we returned last time (if
                        // not NULL or the Anchor node)
                        if (pCur)
                            {
                            pCur = pCur->pNext;
                            if (pLast != pAnchor)
                                {
                                delete pLast;
                                }
                            }
                        else
                            {
                            pCur = pAnchor;
                            };

                        return pCur;
                        };

    BOOL            NonEmpty()
                        {
                        return ( pAnchor->pHighest != NULL );
                        };


    };

class SIBLING_LIST
    {
    named_node * pTail;
    friend class SIBLING_ITER;

public:

    SIBLING_LIST    Init()
                        {
                        pTail = NULL;
                        return *this;
                        };

    SIBLING_LIST    Init( node_skl * pLoneNode )
                        {
                        named_node * pSoloNode = (named_node *) pLoneNode;

                        pTail = pSoloNode;
                        if ( pSoloNode )
                            {
                            pSoloNode->SetSibling( pSoloNode );
                            };

                        return *this;
                        };

    BOOL            NonNull()
                        {
                        return pTail != NULL;
                        };

    named_node *    Tail()
                        {
                        return pTail;
                        };

    SIBLING_LIST    SetPeer( named_node * pNewNode )
                        {
                        return Add( pNewNode );
                        };

    SIBLING_LIST    Add( named_node * pNewNode ); // add to tail

    SIBLING_LIST    Merge( SIBLING_LIST & NewList );

    named_node *    Linearize();

    void            AddAttributes( ATTRLIST & AList );

    operator void * ()
        {
        return pTail;
        };
    };

class SIBLING_ITER
    {
private:
    named_node * pHead;
    named_node * pCur;

public:
    SIBLING_ITER( SIBLING_LIST & SibList )
        {
        pCur = NULL;
        pHead = (SibList.pTail == NULL) ?
            NULL :
            (named_node *)  SibList.pTail->GetSibling();
        };

    named_node * Next()
        {
        if (pCur == NULL)
            {
            pCur = pHead;
            }
        else
            {
            pCur = (named_node *) pCur->GetSibling();
            pCur = (pCur == pHead) ? NULL : pCur;
            }

        return pCur;
        };

    };


class _decl_spec
    {
public:
    node_skl * pNode;
    MODIFIER_SET modifiers;

    void    Init( node_skl * pOnly )
                {
                pNode = pOnly;
                };
    void    Init( node_skl *pOnly, const MODIFIER_SET & mod )
                {
                pNode = pOnly;
                modifiers = mod;
                }
    };

struct _interface_header
    {
    node_interface * pInterface;    // interface node
    };

struct _numeric
    {
    union
        {
        double  dVal;    // value
        float   fVal;    // value
        long    Val;     // value
        };
    char *pValStr;  // value string as user specified
    };


struct _array_bounds
    {
    class expr_node * LowerBound;   // lower array bound
    class expr_node * UpperBound;   // upper bound
    };

struct _int_body
    {
    SIBLING_LIST Imports;   // import nodes
    SIBLING_LIST Members;   // type graph node below interface node
    };

struct _library_header
    {
    node_library * pLibrary;
    };

struct _disp_header
    {
    node_dispinterface * pDispInterface;
    };

struct _coclass_header
    {
    node_coclass * pCoclass;
    };

struct _module_header
    {
    node_module * pModule;
    };

struct _enlab
    {
    class expr_node * pExpr;
    class node_label * pLabel;
    unsigned short fSparse;
    };

struct _enlist
    {
    class SIBLING_LIST NodeList;
    class node_label * pPrevLabel;
    unsigned short fSparse;
    };

struct _en_switch
    {
    class node_skl * pNode;
    class node_switch_is * pSwitch;
    char * pName;
    };

struct _nu_caselabel
    {
    class expr_node * pExpr;
    node_base_attr * pDefault;
    };

struct _nu_cllist
    {
    class expr_list * pExprList;
    class node_base_attr * pDefault;
    short DefCount;
    };

struct _nu_cases
    {
    SIBLING_LIST CaseList;
    short DefCount;
    };

union s_lextype {
    short                       yy_short;
    USHORT                      yy_ushort;
    int                         yy_int;
    long                        yy_long;
    MODIFIER_SET                yy_modifiers;
    enum _operators             yy_operator;
    char                    *   yy_pSymName;
    char                    *   yy_string;
    _type_ana                   yy_type;
    node_skl                *   yy_graph;
    _DECLARATOR                 yy_declarator;
    _DECLARATOR_SET             yy_declarator_set;
    _decl_spec                  yy_declspec;
    _interface_header           yy_inthead;
    type_node_list          *   yy_tnlist;
    _array_bounds               yy_abounds;
    _int_body                   yy_intbody;
    expr_node               *   yy_expr;
    expr_list               *   yy_exprlist;
    _numeric                    yy_numeric;
    _enlab                      yy_enlab;
    _enlist                     yy_enlist;
    expr_init_list          *   yy_initlist;
    ATTR_T                      yy_attrenum;
    class SIBLING_LIST          yy_siblist;
    class ATTRLIST              yy_attrlist;
    class node_base_attr    *   yy_attr;
    struct _en_switch           yy_en_switch;
    struct _nu_caselabel        yy_nucaselabel;
    struct _nu_cllist           yy_nucllist;
    struct _nu_cases            yy_nucases;
    _library_header             yy_libhead;
    _disp_header                yy_disphead;
    _module_header              yy_modulehead;
    _coclass_header             yy_coclasshead;
    token_t                     yy_tokentype;
};

typedef union s_lextype lextype_t;

//
// the parse stack depth
//
#define YYMAXDEPTH 150

/////////////////////////////////////////////////////////////////////////////
// predefined type node data base
/////////////////////////////////////////////////////////////////////////////

struct  _pre_type
    {
    unsigned short TypeSpec;
    class node_skl * pPreAlloc;
    };

#define PRE_TYPE_DB_SIZE    (36)
class pre_type_db
    {
private:
    struct _pre_type TypeDB[ PRE_TYPE_DB_SIZE ];
public:
                pre_type_db( void );
    STATUS_T    GetPreAllocType(node_skl **, unsigned short);
    };

//
// A structure which carries the interface information while the interface
// is being processed. This is necessary since the interface node and the
// type graph gets joined after the interface declarations are fully processed
// and the interface declarations need this while it is being processed.
//

typedef struct _iInfo
    {
    node_interface  *   pInterfaceNode;
    short               CurrentTagNumber;
    unsigned short      IntfKey;
    ATTR_T              InterfacePtrAttribute;
    BOOL                fPtrDefErrorReported;
    BOOL                fPtrWarningIssued;
    BOOL                fLocal;
    } IINFO ;

class IINFODICT : public ISTACK
    {
private:
    BOOL                fBaseLocal;
    ATTR_T              BaseInterfacePtrAttribute;
    node_interface  *   pBaseInterfaceNode;
public:

    IINFODICT() : ISTACK( 5 )
        {
        BaseInterfacePtrAttribute = ATTR_NONE;
        }

    BOOL                IsPtrWarningIssued();

    void                SetPtrWarningIssued();

    void                StartNewInterface();

    void                EndNewInterface();

    void                SetInterfacePtrAttribute( ATTR_T A );

    ATTR_T              GetInterfacePtrAttribute();

    ATTR_T              GetBaseInterfacePtrAttribute();

    void                SetInterfaceLocal();

    BOOL                IsInterfaceLocal();

    void                SetInterfaceNode( node_interface *p );

    node_interface  *   GetInterfaceNode();

    SymTable        *   GetInterfaceProcTable()
                            {
                            return GetInterfaceNode()->GetProcTbl();
                            }

    char            *   GetInterfaceName()
                            {
                            return GetInterfaceNode()->GetSymName();
                            }

    short               GetCurrentTagNumber();

    void                IncrementCurrentTagNumber();

    void                SetPtrDefErrorReported();

    BOOL                IsPtrDefErrorReported();

    };


class nsa : public gplistmgr
    {
    short               CurrentLevel;
public:
                        nsa(void);
                        ~nsa(void) { };
    STATUS_T            PushSymLevel( class SymTable ** );
    STATUS_T            PopSymLevel( class SymTable ** );
    short               GetCurrentLevel( void );
    class SymTable *    GetCurrentSymbolTable( void );
    };

#endif