/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 Copyright (c) 1989-1999 Microsoft Corporation

 Module Name:

    ilxlat.cxx

 Abstract:

    Intermediate Language translator

 Notes:


 Author:

    GregJen Jun-11-1993 Created.

 Notes:


 ----------------------------------------------------------------------------*/

/****************************************************************************
 *  include files
 ***************************************************************************/

#include "becls.hxx"
#pragma hdrstop

#include "ilxlat.hxx"
#include "ilreg.hxx"
#include "control.hxx"
#include "tlgen.hxx"

/****************************************************************************
 *  local data
 ***************************************************************************/

// #define trace_cg 1

/****************************************************************************
 *  externs
 ***************************************************************************/

extern  CMD_ARG             *   pCommand;
extern  BOOL                    IsTempName( char *);
extern  ccontrol            *   pCompiler;
extern  REUSE_DICT          *   pReUseDict;
extern  SymTable            *   pBaseSymTbl;

/****************************************************************************
 *  definitions
 ***************************************************************************/

        
void
AddToCGFileList( CG_FILE *& pCGList, CG_FILE * pFile )
{
    if (pFile)
        {
        pFile->SetSibling( pCGList );
        pCGList = pFile;
        }
}

void XLAT_CTXT::InitializeMustAlign( node_skl * pPar ) 
{
    if (pPar)
        {
        if (pPar->GetModifiers().IsModifierSet(ATTR_DECLSPEC_ALIGN))
            {
            GetMustAlign() = true;
            GetMemAlign() = __max(GetMemAlign(),
                                  pPar->GetModifiers().GetDeclspecAlign());
            }
        }
}



//--------------------------------------------------------------------
//
// XLAT_CTXT::~XLAT_CTXT
//
// Notes:  If the node that created this context didn't remove all
//         the attributes it added, force the issue.  This is done
//         mostly because tlb generation short-circuits code
//         generation and tends to leave attributes hanging around.
//         This causes asserts and possibly other problems in random
//         places later on.  Also note that a lot of the top-level
//         stuff (interfaces, etc) don't strip much so you get lots
//         of hits with those.
//
//--------------------------------------------------------------------

XLAT_CTXT::~XLAT_CTXT()
{
    if ( !GetParent() || !GetParent()->HasAttributes() )
        return;
    
    named_node     *pNode = dynamic_cast<named_node *>(GetParent());
    type_node_list  attrs;
    node_base_attr *pAttr;

    MIDL_ASSERT( NULL != pNode);

    pNode->GetAttributeList(&attrs);

    while (ITERATOR_GETNEXT(attrs, pAttr))
    {
#ifdef DUMP_UNEXTRACTED_ATTRIBUTES
        extern void GetSemContextString(char *, node_skl *, WALK_CTXT *);
        char    szContext[1024];

        GetSemContextString(szContext, pNode, this);

        fprintf(
                stderr, 
                "Unextracted attribute: %s: %s\n", 
                pAttr->GetNodeNameString(),
                szContext );
#endif

        ExtractAttribute( pAttr->GetAttrID() );
    }
}



//--------------------------------------------------------------------
//
// IsComplexReturn
//
// Notes:  A complex return value is one that isn't be returned in an
//         ordinary register.  structs, unions, and floating point
//         values are complex
//
//--------------------------------------------------------------------

bool IsComplexReturn(node_skl *node)
{
    // straight dce doesn't support complex returns in intrepreted mode yet

    if ( !pCommand->NeedsNDR64Run() )
        return false;

    node = node->GetNonDefSelf();

    NODE_T kind = node->NodeKind();

    if (   NODE_STRUCT == kind
        || NODE_UNION  == kind
        || NODE_ARRAY  == kind
        || NODE_FLOAT  == kind
        || NODE_DOUBLE == kind 
        || ( NODE_HYPER == kind && pCommand->Is32BitEnv() ) )
    {
        return true;
    }
    
    // REVIEW: NODE_INT64, NODE_LONGLONG

    return false;
}


//--------------------------------------------------------------------
//
// node_file::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_file::ILxlate( XLAT_CTXT * pContext )
{
    node_interface  *   pI = 0;
    CG_CLASS        *   pcgInterfaceList = NULL;
    CG_CLASS        *   pPrevChildCG = NULL;

    CG_PROXY_FILE       *   pProxyCG    = NULL;
    CG_IID_FILE         *   pIidCG      = NULL;
    CG_TYPELIBRARY_FILE *   pLibCG      = NULL; 
    CG_NETMONSTUB_FILE  *   pNetmonCG   = NULL;
    CG_NETMONSTUB_FILE  *   pNetmonObjCG   = NULL;

    CG_CSTUB_FILE           *   pCCG        = NULL;
    CG_SSTUB_FILE           *   pSCG        = NULL;
    CG_HDR_FILE             *   pHCG        = NULL;

    CG_CLASS        *   pChildCG    = NULL;
    CG_FILE         *   pCGList     = NULL;

    char            *   pHdrName    = pCommand->GetHeader();
    XLAT_CTXT           MyContext(this);

    BOOL                HasObjectInterface  = FALSE;
    BOOL                HasRemoteProc       = FALSE;
    BOOL                HasRemoteObjectProc = FALSE;
    BOOL                HasDefs             = FALSE;
    BOOL                HasLibrary          = FALSE;
#ifdef trace_cg
    printf("..node_file,\t%s\n", GetSymName());
#endif

    // don't process for imported stuff
    if ( ImportLevel > 0 )
        {
        return NULL;
        }

    // at this point, there should be no more attributes...

    MIDL_ASSERT( !MyContext.HasAttributes() );

    //////////////////////////////////////////////////////////////////////
    // compute all the child nodes

    for(pI = (node_interface *)GetFirstMember();
        pI;
        pI = (node_interface *)pI->GetSibling())
    {
        // build a linked list of CG_INTERFACE and CG_OBJECT_INTERFACE nodes.
        // Notes: pChildCG points to first node.  pPrevChildCG points to last node.

        MyContext.SetInterfaceContext( &MyContext );
        pcgInterfaceList = pI->ILxlate( &MyContext );
        if(pcgInterfaceList)
            {
            if (pPrevChildCG)
                {
                pPrevChildCG->SetSibling( pcgInterfaceList );
                }
            else
                {
                pChildCG = pcgInterfaceList;
                }
            pPrevChildCG = pcgInterfaceList;
            // advance to the end of the list (skipping inherited interfaces)
            while ( pPrevChildCG->GetSibling() )
                pPrevChildCG = pPrevChildCG->GetSibling();

            switch(pPrevChildCG->GetCGID())
                {
                case ID_CG_INTERFACE:
                    //Check for a remote procedure.
                    if(pPrevChildCG->GetChild())
                        HasRemoteProc = TRUE;
                    HasDefs = TRUE;
                    break;
                case ID_CG_OBJECT_INTERFACE:
                case ID_CG_INHERITED_OBJECT_INTERFACE:
                    HasDefs = TRUE;
                    HasObjectInterface = TRUE;

                    //Check for a remote object procedure or base interface
                    if( pPrevChildCG->GetChild() ||
                        ((CG_OBJECT_INTERFACE *)pPrevChildCG)->GetBaseInterfaceCG() )
                        HasRemoteObjectProc = TRUE;
                    break;
                case ID_CG_LIBRARY:
                    HasLibrary = TRUE;
                    if( pCommand->IsSwitchDefined( SWITCH_HEADER ) )
                        HasDefs = TRUE;
                    break;
                default:
                    break;
                }
            }
    }

    // process the server and client stubs

    // make the list of imported files

    ITERATOR        *   pFileList   = new ITERATOR;
    named_node      *   pCur;

    // make a list of the file nodes included directly by the main file

    // start with the first child of our parent
    pCur = (named_node *)
            ((node_source *) pContext->GetParent())
                ->GetFirstMember();

    while ( pCur )
        {
        if ( ( pCur->NodeKind() == NODE_FILE ) &&
             ( ( (node_file *) pCur )->GetImportLevel() == 1 ) )
            {
            // add all the files imported at lex level 1
            ITERATOR_INSERT( (*pFileList), ((void *) pCur) );
            }
        pCur    = pCur->GetSibling();
        }

    ITERATOR_INIT( (*pFileList) );

    //////////////////////////////////////////////////////////////////////
    // manufacture the header file node

    if ( HasDefs )
        {
        pHCG    = new CG_HDR_FILE( this,
                                    pHdrName,
                                    pFileList);

        pHCG->SetChild( pChildCG );
        }

    //////////////////////////////////////////////////////////////////////
    // manufacture the CG_SSTUB_FILE

    // if the IDL file contains at least one remotable function in a
    // non-object interface, then generate a server stub file.
    //

    if ( HasRemoteProc &&
         (pChildCG != NULL) )   // if server stub desired
        {
        pSCG = new CG_SSTUB_FILE(
                             this,
                             ( pCommand->GenerateSStub() ) ?
                                    pCommand->GetSstubFName():
                                    NULL,
                             pHdrName
                              );

        // plug in the child subtree and add the sstub to the head of the list
        pSCG->SetChild( pChildCG );

        }

    //////////////////////////////////////////////////////////////////////
    // manufacture the CG_CSTUB_FILE

    // if the IDL file contains at least one remotable function in a
    // non-object interface, then generate a client stub file.

    if ( HasRemoteProc &&
         (pChildCG != NULL) )   // if client stub desired
        {
        pCCG = new CG_CSTUB_FILE(
                             this,
                             ( pCommand->GenerateCStub() ) ?
                                    pCommand->GetCstubFName():
                                    NULL,
                             pHdrName
                              );

        pCCG->SetChild( pChildCG );
       
        }

    // If the IDL file contains at least one remotable function in an
    // object interface, then generate a proxy file.
    if ( HasRemoteObjectProc &&
        (pChildCG != NULL) )    // if proxy file desired
        {
        pProxyCG = new CG_PROXY_FILE(
                             this,
                             ( pCommand->GenerateProxy() ) ?
                                    pCommand->GetProxyFName():
                                    NULL,
                             pHdrName
                              );

        pProxyCG->SetChild( pChildCG );

        }


    // If the IDL file contains at least one object interface,
    // then generate an IID file.
    if ( (HasObjectInterface || (HasLibrary && HasDefs) )&&
        (pChildCG != NULL) )    // if IID file desired
        {
        pIidCG = new CG_IID_FILE(
                             this,
                             ( pCommand->GenerateIID() ) ?
                                    pCommand->GetIIDFName():
                                    NULL);

        pIidCG->SetChild( pChildCG );
        }

    // If the IDL file contains a library then gnerate a TYPELIBRARY_FILE
    if (HasLibrary && (NULL != pChildCG) )
        {
#ifdef _WIN64
        bool fGenTypeLib = pCommand->Is64BitEnv() || ( pCommand->Is32BitEnv() && pCommand->IsSwitchDefined( SWITCH_ENV ) );
#else
        bool fGenTypeLib = pCommand->Is32BitEnv() || ( pCommand->Is64BitEnv() && pCommand->IsSwitchDefined( SWITCH_ENV ) );
#endif

        if ( fGenTypeLib && pCommand->GenerateTypeLibrary() )
            {
            pLibCG = new CG_TYPELIBRARY_FILE(
                            this,
                            pCommand->GetTypeLibraryFName() ) ;
            pLibCG->SetChild( pChildCG );
            }
        }

    // If the -netmon switch was used, generate the two NETMONSTUB_FILE's
    if ( pCommand->IsNetmonStubGenerationEnabled() ) 
        {
        if (HasRemoteProc) 
            {
            pNetmonCG = new CG_NETMONSTUB_FILE(
                FALSE,
                this,
                pCommand->GetNetmonStubFName());

            pNetmonCG->SetChild( pChildCG );
            }

        if (HasRemoteObjectProc) 
            {
            pNetmonObjCG = new CG_NETMONSTUB_FILE(
                TRUE,
                this,
                pCommand->GetNetmonStubObjFName());
            pNetmonObjCG->SetChild( pChildCG );
            }
        }

    /////////////////////////////////////////////////////////////////////
    // glue all the parts together by tacking onto the head of the list.
    // the final order is:
    // CStub - SStub - Proxy - IID - Hdr
    // doesn't need to create Hdr & tlb in ndr64 run. 
    pCGList = NULL;

    AddToCGFileList( pCGList, pNetmonObjCG );
    AddToCGFileList( pCGList, pNetmonCG );

    if ( !pCommand->Is2ndCodegenRun() )
        AddToCGFileList( pCGList, pHCG );

    if ( !pCommand->Is2ndCodegenRun() )
        AddToCGFileList( pCGList, pIidCG );
    AddToCGFileList( pCGList, pProxyCG );

    AddToCGFileList( pCGList, pSCG );
    AddToCGFileList( pCGList, pCCG );

    if ( !pCommand->Is2ndCodegenRun() )
        AddToCGFileList( pCGList, pLibCG );

    return pCGList;

};

//--------------------------------------------------------------------
//
// node_implicit::ILxlate
//
// Notes:
//
// This is a little bit different, since it is not a node_skl...
// therefore, it will not set up its own context
//
//--------------------------------------------------------------------

CG_CLASS *
node_implicit::ILxlate( XLAT_CTXT * pContext )
{
    CG_NDR      *   pCG;

    if ( pHandleType->NodeKind() == NODE_HANDLE_T )
        {
        pCG = new CG_PRIMITIVE_HANDLE( pHandleType,
                                         pHandleID,
                                         *pContext );
        }
    else    // assume generic handle
        {
        pCG = new CG_GENERIC_HANDLE( pHandleType,
                                       pHandleID,
                                       *pContext );
        }
#ifdef trace_cg
    printf("..node_implicit,\t\n");
#endif
    return pCG;
}


//--------------------------------------------------------------------
//
// node_proc::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_proc::ILxlate( XLAT_CTXT * pContext )
{
    MEM_ITER            MemIter( this );
    node_param      *   pN;
    CG_PROC         *   pCG;
    CG_CLASS        *   pChildCG        = NULL;
    CG_CLASS        *   pPrevChildCG    = NULL;
    CG_CLASS        *   pFirstChildCG   = NULL;
    CG_RETURN       *   pReturnCG       = NULL;
    CG_CLASS        *   pBinding        = NULL;
    CG_CLASS        *   pBindingParam   = NULL;
    BOOL                fHasCallback    = FALSE;
    BOOL                fNoCode         = FALSE;
    BOOL                fObject;
    BOOL                fRetHresult     = FALSE;
    BOOL                fEnableAllocate;
    XLAT_CTXT           MyContext( this, pContext );
    unsigned short      OpBits          = MyContext.GetOperationBits();
    XLAT_CTXT       *   pIntfCtxt       = (XLAT_CTXT *)
                                                MyContext.GetInterfaceContext();
    node_interface  *   pIntf           = (node_interface *)
                                                pIntfCtxt->GetParent();
    node_base_attr  *   pNotify,
                    *   pNotifyFlag;
    BOOL                HasEncode       = (NULL !=
                                            MyContext.ExtractAttribute( ATTR_ENCODE ) );
    BOOL                HasDecode       = (NULL !=
                                            MyContext.ExtractAttribute( ATTR_DECODE ) );
    node_call_as    *   pCallAs         = (node_call_as *)
                                            MyContext.ExtractAttribute( ATTR_CALL_AS );
    bool                fLocalProc      = MyContext.ExtractAttribute( ATTR_LOCAL ) != 0;
    BOOL                fLocal          = (BOOL ) fLocalProc ||
                                        pIntfCtxt->FInSummary( ATTR_LOCAL );
    BOOL                fLocalCall      = IsCallAsTarget();
    unsigned short      SavedProcCount = 0;
    unsigned short      SavedCallbackProcCount = 0;
    node_param      *   pComplexReturn = NULL;


    MyContext.ExtractAttribute( ATTR_ENTRY );
    MyContext.ExtractAttribute( ATTR_ID );
    MyContext.ExtractAttribute( ATTR_HELPCONTEXT );
    MyContext.ExtractAttribute( ATTR_HELPSTRINGCONTEXT );
    MyContext.ExtractAttribute( ATTR_HELPSTRING );
    MyContext.ExtractAttribute( ATTR_IDLDESCATTR );
    MyContext.ExtractAttribute( ATTR_FUNCDESCATTR );
    MyContext.ExtractAttribute( ATTR_HIDDEN );
    MyContext.ExtractAttribute( ATTR_ASYNC );
    while(MyContext.ExtractAttribute(ATTR_CUSTOM));
    
#ifdef trace_cg
    printf("..node_proc,\t%s\n", GetSymName());
#endif
    BOOL fSupressHeader = FALSE;
    unsigned long ulOptFlags;
    unsigned long ulStackSize = 0;

    node_member_attr * pMA;
    while ( ( pMA = (node_member_attr *)MyContext.ExtractAttribute(ATTR_MEMBER) ) != 0 );

    // do my attribute parsing...
    fHasCallback = (NULL != MyContext.ExtractAttribute( ATTR_CALLBACK ) );

    fObject = (NULL != MyContext.ExtractAttribute( ATTR_OBJECT )) ||
                        pIntfCtxt->FInSummary( ATTR_OBJECT );

    // do my attribute parsing... attributes to ignore here

    MyContext.ExtractAttribute( ATTR_OPTIMIZE );

    MyContext.ExtractAttribute( ATTR_EXPLICIT );

    HasEncode = HasEncode || pIntfCtxt->FInSummary( ATTR_ENCODE );
    HasDecode = HasDecode || pIntfCtxt->FInSummary( ATTR_DECODE );


    pNotify     = MyContext.ExtractAttribute( ATTR_NOTIFY );
    pNotifyFlag = MyContext.ExtractAttribute( ATTR_NOTIFY_FLAG );
    fEnableAllocate = (NULL != MyContext.ExtractAttribute( ATTR_ENABLE_ALLOCATE ));
    fEnableAllocate = fEnableAllocate ||
                      pIntfCtxt->FInSummary( ATTR_ENABLE_ALLOCATE ) ||
                      pCommand->IsRpcSSAllocateEnabled();

    // do my attribute parsing...
    // locally applied [code] attribute overrides global [nocode] attribute
    fNoCode = MyContext.ExtractAttribute( ATTR_NOCODE ) ||
              pIntfCtxt->FInSummary( ATTR_NOCODE );
    fNoCode = !MyContext.ExtractAttribute( ATTR_CODE ) && fNoCode;

    if ( NULL != MyContext.ExtractAttribute( ATTR_CSTAGRTN ) )
        MyContext.SetAncestorBits( IL_CS_HAS_TAG_RTN );

    BOOL fImported = FALSE;
    if ( GetDefiningFile() )
        {
        fImported = GetDefiningFile()->GetImportLevel() != 0;
        }

    if ( fLocalProc && !IsCallAsTarget() && fObject )
        {
        SemError( this, MyContext, LOCAL_NO_CALL_AS, 0 );
        }

    // determine if the proc is local and 
    // determine the proc number (local procs don't bump the number)
    if (fLocalCall || (fLocal && !fObject))
    {
            // return without making anything
            return NULL;
    }
    else
    {
        if ( fHasCallback )
            {
            ProcNum = ( pIntf ->GetCallBackProcCount() )++;
            }
        else
            {
            ProcNum = ( pIntf ->GetProcCount() )++;
            }
    }
   
    if ( fLocal && fObject && !MyContext.AnyAncestorBits(IL_IN_LIBRARY) )
        {

        if ( pIntf->IsValidRootInterface() )
            {
            pCG = new CG_IUNKNOWN_OBJECT_PROC( ProcNum,
                                             this,
                                             GetDefiningFile()->GetImportLevel() > 0,
                                             GetOptimizationFlags(),
                                             fHasDeny );
            }
        else
            {
            pCG = new CG_LOCAL_OBJECT_PROC( ProcNum,
                                             this,
                                             GetDefiningFile()->GetImportLevel() > 0,
                                             GetOptimizationFlags(),
                                             fHasDeny );
            }

        goto done;

        }

    SavedProcCount = pIntf->GetProcCount();
    SavedCallbackProcCount = pIntf->GetCallBackProcCount();

    // add the return type
    if ( HasReturn() )
        {
        node_skl    *   pReturnType = GetReturnType();
        CG_CLASS    *   pRetCG;

        // If the return value is complex it is treated in ndr as if a ref
        // pointer to the complex type was in the parameter list instead of
        // a true return value.  Temporarily add a parameter to the type
        // to get the back-end parameter created.

        if ( IsComplexReturn( pReturnType ) )
            {
            pComplexReturn = new node_param;
            pComplexReturn->SetSymName( RETURN_VALUE_VAR_NAME );
            pComplexReturn->SetChild( new node_pointer( pReturnType) );
            pComplexReturn->GetChild()->GetModifiers().SetModifier( ATTR_TAGREF );
            pComplexReturn->SetAttribute( new node_base_attr( ATTR_OUT ) );

            MemIter.AddLastMember( pComplexReturn );
            ITERATOR_INIT( MemIter );
            }
        else
            {
            pRetCG      = pReturnType->ILxlate( &MyContext );
            fRetHresult = (BOOL) ( pRetCG->GetCGID() == ID_CG_HRESULT );
            pReturnCG   = new CG_RETURN( pReturnType,
                                         MyContext,
                                         (unsigned short) RTStatuses );
            pReturnCG->SetChild( pRetCG );
            }
        }

    // at this point, there should be no more attributes...
    MIDL_ASSERT( !MyContext.HasAttributes() );

    pContext->ReturnSize( MyContext );

    if ( MemIter.GetNumberOfArguments() > 0 )
        {
        //
        // for each of the parameters, call the core transformer.
        //

        while ( ( pN = (node_param *) MemIter.GetNext() ) != 0 )
            {
            // REVIEW: One could argue that hidden status params
            //         aren't on the wire so there shouldn't be a CG node
            //         for them.  The main problem with this is that we
            //         need to be able to calculate a stack offset for the
            //         hidden param and that can only be done in the
            //         back end.

            // Hidden status params are not really [out] params but the way
            // the -Os generator builds up local resources requires them to
            // be.

            if ( pN->IsExtraStatusParam() 
                && ! ( GetOptimizationFlags() & OPTIMIZE_INTERPRETER_V2 ) )
                {
                pN->SetAttribute( ATTR_OUT );
                }

            pChildCG = pN->ILxlate( &MyContext );

#ifdef trace_cg
    printf("back from..node_param %s\n",pN->GetSymName());
    printf("binding is now %08x\n",pBindingParam );
    printf("child is now %08x\n",pChildCG );
#endif

            // pChildCG could be NULL if it's imported from .tlb somewhere else already
            if ( pChildCG )
                {
                // the first binding param gets picked up for binding
                if ( !pBindingParam
                     && pN->IsBindingParam() )
                    {
#ifdef trace_cg
    printf("value for IsBindingParam is %08x\n",pN->IsBindingParam() );
    printf("binding found on node_param %s\n",pN->GetSymName());
    printf("binding is now %08x\n",pBindingParam );
#endif
                    pBindingParam = pChildCG;
                    }
    
                // build up the parameter list
                if( pPrevChildCG )
                    {
                    pPrevChildCG->SetSibling( pChildCG );
                    }
                else
                    {
                    pFirstChildCG = pChildCG;
                    };

            // this is only a calculated guess. We need more information to make an accurate
            // estimate.
                unsigned long ulSize = ( ( CG_PARAM* ) pChildCG )->GetStackSize();
                ulSize += (8 - (ulSize % 8));
                ulStackSize += ulSize;

                pPrevChildCG = pChildCG;
                }
            else
                SemError( this, MyContext, FAILED_TO_GENERATE_PARAM, pN->GetSymName() );
            }
        }

    ulOptFlags = GetOptimizationFlags();
    if ( ( ulOptFlags & OPTIMIZE_INTERPRETER ) &&
         !( ulOptFlags & OPTIMIZE_INTERPRETER_V2 ) &&
         ( ulStackSize > INTERPRETER_THUNK_PARAM_SIZE_THRESHOLD ) )
        {
        if ( ForceNonInterpret() )
            {
            SemError( this, *pContext, OI_STACK_SIZE_EXCEEDED, 0 );
            }
        }
    if ( ulOptFlags & OPTIMIZE_INTERPRETER && ulStackSize > INTERPRETER_PROC_STACK_FRAME_SIZE_THRESHOLD )
        {
        if ( ForceNonInterpret() )
            {
            SemError( this, *pContext, STACK_FRAME_SIZE_EXCEEDED, GetSymName() );
            exit ( STACK_FRAME_SIZE_EXCEEDED );
            }
        }
    if (fForcedI2 && fForcedS)
        {
        // ERROR - Can't force it both ways.
        SemError( this, *pContext, CONFLICTING_OPTIMIZATION_REQUIREMENTS, 0 );
        exit ( CONFLICTING_OPTIMIZATION_REQUIREMENTS );
        }


#ifdef trace_cg
    printf("done with param list for %s\n",GetSymName());
    printf("binding is now %08x\n",pBindingParam );
#endif

    // get the binding information
    if ( pBindingParam )
        {
        pBinding    = pBindingParam;

        while (! ((CG_NDR *) pBinding)->IsAHandle() )
            pBinding = pBinding->GetChild();
        // pBinding now points to the node for the binding handle
        }
    else    // implicit handle or auto handle
        {
        // note: if no implicit handle,
        //      then leave pBinding NULL for auto_handle
        if (pIntfCtxt->FInSummary( ATTR_IMPLICIT ) )
            {
            node_implicit   *   pImplAttr;
            pImplAttr = (node_implicit *) pIntf->GetAttribute( ATTR_IMPLICIT );

            pBinding = pImplAttr->ILxlate( &MyContext );
            }
        }

#ifdef trace_cg
    printf("done with binding for %s",GetSymName());
    printf("binding is now %08x\n",pBinding );
#endif

    // see if thunked interpreter needed for server side
    if ( GetOptimizationFlags() & OPTIMIZE_INTERPRETER )
        {   // check for non-stdcall
        ATTR_T      CallingConv;

        GetCallingConvention( CallingConv );

        if ( ( CallingConv != ATTR_STDCALL ) &&
             ( CallingConv != ATTR_NONE ) )
            {
            SetOptimizationFlags( unsigned short( GetOptimizationFlags() | OPTIMIZE_THUNKED_INTERPRET ) );
            }
        else if ( pCallAs )
            {
            SetOptimizationFlags( unsigned short( GetOptimizationFlags() | OPTIMIZE_THUNKED_INTERPRET ) );
            }
        else if ( pReturnCG )   // check the return type
            {
            CG_NDR  *   pRetTypeCG  = (CG_NDR *) pReturnCG->GetChild();

            if ( !pCommand->NeedsNDR64Run() 
                 && pRetTypeCG->GetCGID() != ID_CG_CONTEXT_HDL )
                {
                // This check is bogus.  First off, it should be checking the
                // memory size, not the wire size.  Secondly, for straight dce
                // mode large (i.e. complex) return types are prohibited in
                // semantic analysis.  Finally, it should be checking the size
                // against the pointer size, not 4.

                if ( ( pRetTypeCG->GetWireSize() > 4 ) ||
                     ( !pRetTypeCG->IsSimpleType() && 
                       !pRetTypeCG->IsPointer() ) )
                    SetOptimizationFlags( unsigned short( GetOptimizationFlags() | OPTIMIZE_THUNKED_INTERPRET ) );
                }
            }

        }

    if ( fHasCallback )
        {
        pCG     = new CG_CALLBACK_PROC(
                                       ProcNum,
                                       this,
                                       (CG_HANDLE *) pBinding,
                                       (CG_PARAM *) pBindingParam,
                                       HasAtLeastOneIn(),
                                       HasAtLeastOneOut(),
                                       HasAtLeastOneShipped(),
                                       fHasStatuses,
                                       fHasFullPointer,
                                       pReturnCG,
                                       GetOptimizationFlags(),
                                       OpBits,
                                       fHasDeny
                                     );
        }
    else if ( fObject )
        {
        BOOL                fInherited = 0;
        if ( GetDefiningFile() )
            {
            fInherited = GetDefiningFile()->GetImportLevel() > 0;
            }
        if ( fInherited )
            {
            pCG     = new CG_INHERITED_OBJECT_PROC(
                                   ProcNum,
                                   this,
                                   (CG_HANDLE *) pBinding,
                                   (CG_PARAM *) pBindingParam,
                                   HasAtLeastOneIn(),
                                   HasAtLeastOneOut(),
                                   HasAtLeastOneShipped(),
                                   fHasStatuses,
                                   fHasFullPointer,
                                   pReturnCG,
                                   GetOptimizationFlags(),
                                   OpBits,
                                   fHasDeny
                                 );
            }
        else
            {
            pCG     = new CG_OBJECT_PROC(
                                   ProcNum,
                                   this,
                                   (CG_HANDLE *) pBinding,
                                   (CG_PARAM *) pBindingParam,
                                   HasAtLeastOneIn(),
                                   HasAtLeastOneOut(),
                                   HasAtLeastOneShipped(),
                                   fHasStatuses,
                                   fHasFullPointer,
                                   pReturnCG,
                                   GetOptimizationFlags(),
                                   OpBits,
                                   fHasDeny
                                 );
            }
        }
    else if ( HasEncode || HasDecode )
        {
        pCG     = new CG_ENCODE_PROC(
                               ProcNum,
                               this,
                               (CG_HANDLE *) pBinding,
                               (CG_PARAM *) pBindingParam,
                               HasAtLeastOneIn(),
                               HasAtLeastOneOut(),
                               HasAtLeastOneShipped(),
                               fHasStatuses,
                               fHasFullPointer,
                               pReturnCG,
                               GetOptimizationFlags(),
                               OpBits,
                               HasEncode,
                               HasDecode,
                               fHasDeny
                             );
        }
    else
        {
        pCG     = new CG_PROC(
                               ProcNum,
                               this,
                               (CG_HANDLE *) pBinding,
                               (CG_PARAM *) pBindingParam,
                               HasAtLeastOneIn(),
                               HasAtLeastOneOut(),
                               HasAtLeastOneShipped(),
                               fHasStatuses,
                               fHasFullPointer,
                               pReturnCG,
                               GetOptimizationFlags(),
                               OpBits,
                               fHasDeny
                             );
        }

    pCG->SetChild( pFirstChildCG );

#ifdef trace_cg
    printf("....returning from %s\n",GetSymName());
#endif
    
    pIntf->GetProcCount() = SavedProcCount;
    pIntf->GetCallBackProcCount() = SavedCallbackProcCount;

done:
    // save a pointer to the interface CG node
    pCG->SetInterfaceNode( (CG_INTERFACE*) pIntf->GetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY) ) );

    if (fSupressHeader)
        pCG->SetSupressHeader();

    // mark nocode procs
    if ( fNoCode )
        pCG->SetNoCode();

    if ( pNotify )
        pCG->SetHasNotify();

    if ( pNotifyFlag )
        pCG->SetHasNotifyFlag();

    if ( fEnableAllocate )
        pCG->SetRpcSSSpecified( 1 );

    if ( fRetHresult )
        pCG->SetReturnsHRESULT();

    if (HasPipes())
        pCG->SetHasPipes(1);

    if ( pCallAs )
        pCG->SetCallAsName( pCallAs->GetCallAsName() );

    if ( HasExtraStatusParam() )
        pCG->SetHasExtraStatusParam();

    if ( HasAsyncHandle() )
        pCG->SetHasAsyncHandle();

    if ( HasAsyncUUID() )
        pCG->SetHasAsyncUUID();

    if ( HasServerCorr() )
        pCG->SetHasServerCorr();

    if ( HasClientCorr() )
        pCG->SetHasClientCorr();

    // A fake parameter was added to the type for complex return values.
    // Remove it.

    if ( pComplexReturn )
        {
        pCG->SetHasComplexReturnType();
        MemIter.RemoveLastMember();
        }

    pCG->SetCSTagRoutine( GetCSTagRoutine() );

    // Typelib generation does not remove ATTR_V1_ENUM.
    MyContext.ExtractAttribute( ATTR_V1_ENUM );
    
    // at this point, there should be no more attributes...
    MIDL_ASSERT( !MyContext.HasAttributes() );

    if (  ( pCG->GetOptimizationFlags() & OPTIMIZE_INTERPRETER ) && 
            !( pCG->GetOptimizationFlags() & OPTIMIZE_INTERPRETER_V2 ) &&
                pCommand->Is64BitEnv() )
        {
        SemError( this, *pContext, NO_OLD_INTERPRETER_64B, GetSymName() );
        exit ( NO_OLD_INTERPRETER_64B );
        }

    return pCG;
}

//--------------------------------------------------------------------
//
// node_param::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_param::ILxlate( XLAT_CTXT * pContext )
{
    CG_PARAM    *   pCG;
    CG_CLASS    *   pChildCG    = NULL;
    expr_node   *   pSwitchExpr = NULL;

#ifdef trace_cg
    printf("..node_param,\t%s\n",GetSymName());
#endif

    PARAM_DIR_FLAGS F = 0;
    XLAT_CTXT   MyContext( this, pContext );

    // make sure all member attributes get processed
    node_member_attr * pMA;

    MyContext.ExtractAttribute(ATTR_IDLDESCATTR);
    MyContext.ExtractAttribute(ATTR_DEFAULTVALUE);
    while(MyContext.ExtractAttribute(ATTR_CUSTOM));

    if ( MyContext.ExtractAttribute(ATTR_FLCID) )
        {
        LCID();
        }

    while ( ( pMA = (node_member_attr *)MyContext.ExtractAttribute(ATTR_MEMBER) ) != 0 )
        {
        switch (pMA->GetAttr())
            {
            case MATTR_RETVAL:
                Retval();
                break;
            case MATTR_OPTIONAL:
            {
                Optional();
            }
                break;
            default:
                char * pAttrName = pMA->GetNodeNameString();
                SemError( this, MyContext, INAPPLICABLE_ATTRIBUTE, pAttrName);
                break;
            }
        }
  
    if( MyContext.ExtractAttribute( ATTR_IN ) )
        {
        F   |= IN_PARAM;
        }

    if( MyContext.ExtractAttribute( ATTR_OUT ) )
        {
        F   |= OUT_PARAM;
        }

    if ( MyContext.ExtractAttribute( ATTR_PARTIAL_IGNORE ) )
        {
        F   |= PARTIAL_IGNORE_PARAM; 
        }

    // default to in
    if ( F == 0 && !IsExtraStatusParam() )
        F   |= IN_PARAM;

    if ( MyContext.FInSummary( ATTR_SWITCH_IS ) )
        {
        node_switch_is  *   pAttr;
         
        if ( pCommand->IsNDR64Run() )
            {
            pAttr = (node_switch_is *) MyContext.GetAttribute( ATTR_SWITCH_IS );
            }
        else 
            {
            pAttr = (node_switch_is *) MyContext.ExtractAttribute( ATTR_SWITCH_IS );
            }
        pSwitchExpr = pAttr->GetExpr();
        }

    BOOL fHasCSSTag = ( NULL != MyContext.ExtractAttribute( ATTR_STAG ) );
    BOOL fHasCSDRTag = ( NULL != MyContext.ExtractAttribute( ATTR_DRTAG ) );
    BOOL fHasCSRTag = ( NULL != MyContext.ExtractAttribute( ATTR_RTAG ) );

    MyContext.SetAncestorBits(
                      ( fHasCSSTag  ? IL_CS_STAG  : 0 )
                    | ( fHasCSDRTag ? IL_CS_DRTAG : 0 )
                    | ( fHasCSRTag  ? IL_CS_RTAG  : 0 ) );

    BOOL HasForceAllocate = ( NULL != MyContext.ExtractAttribute( ATTR_FORCEALLOCATE ) );
    
	pChildCG = GetChild()->ILxlate( &MyContext );

    pContext->ReturnSize( MyContext );

#ifdef trace_cg
    printf("..node_param back.. %s\n",GetSymName());
#endif
    // make sure void parameters get skipped
    if ( !pChildCG )
        return NULL;

    pCG = new CG_PARAM( this,
                        F,
                        MyContext,
                        pSwitchExpr,
                        (unsigned short) Statuses );

#ifdef trace_cg
    printf("..node_param ..... %08x child=%08x\n", pCG, pChildCG );
    fflush(stdout);
#endif

    if ( IsExtraStatusParam() )
        pCG->SetIsExtraStatusParam();

    // only set the bit if there was non-toplevel only
    if ( fDontCallFreeInst == 1 )
        pCG->SetDontCallFreeInst( TRUE );


#ifdef trace_cg
    printf("..node_param ........ %08x child=%08x\n", pCG, pChildCG );
    fflush(stdout);
#endif
    pCG->SetChild( pChildCG );

    if (IsAsyncHandleParam())
        {
        pCG->SetIsAsyncHandleParam();
        }
    if ( IsSaveForAsyncFinish() )
        {
        pCG->SaveForAsyncFinish();
        }

    pCG->SetIsCSSTag( fHasCSSTag );
    pCG->SetIsCSDRTag( fHasCSDRTag );
    pCG->SetIsCSRTag( fHasCSRTag );

    if ( MyContext.AnyAncestorBits( IL_CS_HAS_TAG_RTN ) && pCG->IsSomeCSTag() )
        pCG->SetIsOmittedParam();

#ifdef trace_cg
    printf("..node_param return %s\n",GetSymName());
    fflush(stdout);
#endif
    if ( HasForceAllocate )
        {
    	pCG->SetForceAllocate( );
    	}


    if ( !MyContext.AnyAncestorBits(IL_IN_LIBRARY) )
        {
        SetCG( pCG );
        }

    // REVIEW: There is no concept of switch_type in a library block.
    //         Perhaps issue an error in semantic analysis.

    if ( MyContext.AnyAncestorBits( IL_IN_LIBRARY )
         && MyContext.ExtractAttribute( ATTR_SWITCH_TYPE ) )
        {
        SemError(
                this, 
                MyContext, 
                IGNORE_UNIMPLEMENTED_ATTRIBUTE, 
                "[switch_type] in a library block");
        }

    return pCG;
}

const GUID_STRS DummyGuidStrs( "00000000", "0000", "0000", "0000", "000000000000" );

// helper function for adding a new list to the end of the list of children
inline
void    AddToCGList(
    const CG_CLASS * pCNew,
    CG_CLASS * * ppChild,
    CG_CLASS * * ppLastSibling )
{
    CG_CLASS * pCurrent;
    CG_CLASS * pNew         = (CG_CLASS *) pCNew;

    // hook the head on
    if ( !*ppChild )
        *ppChild = pNew;
    else
        (*ppLastSibling)->SetSibling( pNew );

    // advance the last sibling pointer
    *ppLastSibling = pNew;
    while ( ( pCurrent = (*ppLastSibling)->GetSibling() ) != 0 )
        *ppLastSibling = pCurrent;

}

//--------------------------------------------------------------------
//
// node_interface::ILxlate
//
// Notes: This function returns either a CG_INTERFACE or a
//        CG_OBJECT_INTERFACE node.
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_interface::ILxlate( XLAT_CTXT * pContext )
{
    CG_NDR          *   pcgInterface    = NULL;
    CG_NDR          *   pResultCG       = NULL;
    CG_CLASS        *   pCG             = NULL;
    CG_CLASS        *   pChildCG        = NULL;
    CG_CLASS        *   pPrevChildCG    = NULL;
    MEM_ITER            MemIter( this );
    node_skl        *   pN;
    XLAT_CTXT           MyContext( this, pContext );
    XLAT_CTXT           ChildContext( MyContext );
    node_guid       *   pGuid       = (node_guid *)
                                            MyContext.ExtractAttribute( ATTR_GUID );
    GUID_STRS           GuidStrs;
    node_implicit   *   pImpHdl     = NULL;
    CG_HANDLE       *   pImpHdlCG   = NULL;
    NODE_T              ChildKind;
    BOOL                IsPickle    = MyContext.FInSummary( ATTR_ENCODE ) ||
                                      MyContext.FInSummary( ATTR_DECODE );
    BOOL                fAllRpcSS   = MyContext.FInSummary( ATTR_ENABLE_ALLOCATE ) ||
                                        pCommand->IsRpcSSAllocateEnabled();
    BOOL                fObject     = MyContext.FInSummary( ATTR_OBJECT );

    node_interface  *   pBaseIntf       = GetMyBaseInterface();
    CG_OBJECT_INTERFACE     *   pBaseCG = NULL;
    CG_OBJECT_INTERFACE     *   pCurrentCG  = NULL;
    CG_OBJECT_INTERFACE     *   pLastItfCG = 0;
    BOOL                        fInheritedIntf = NULL;

    MyContext.ExtractAttribute( ATTR_TYPEDESCATTR );
    MyContext.ExtractAttribute( ATTR_HIDDEN );
    MyContext.ExtractAttribute( ATTR_ASYNC );
    MyContext.ExtractAttribute( ATTR_CSTAGRTN );
    while(MyContext.ExtractAttribute(ATTR_CUSTOM));

#ifdef trace_cg
    printf("..node_interface,\t%s\n", GetSymName());
#endif

    if( FInSummary( ATTR_IMPLICIT ) )
        {
        pImpHdl = (node_implicit *) GetAttribute( ATTR_IMPLICIT );
        if (pImpHdl)
            pImpHdlCG = (CG_HANDLE *) pImpHdl->ILxlate( &MyContext );
        }

    if (pGuid)
        GuidStrs = pGuid->GetStrs();
    else
        GuidStrs = DummyGuidStrs;

    // don't pass the interface attributes down...
    // save them off elsewhere

    ChildContext.SetInterfaceContext( &MyContext );

    // if we already got spit out, don't do it again...
    if ( GetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY) ) )
        return NULL;
        
    // start the procnum counting over
    GetProcCount() = 0;
    GetCallBackProcCount() = 0;

    // Generate the interface's CG node first
    if( fObject || MyContext.AnyAncestorBits(IL_IN_LIBRARY))
        {
        // object interfaces need to have their base classes generated, too
        if ( pBaseIntf )
            {
            pBaseCG = (CG_OBJECT_INTERFACE *) pBaseIntf->GetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY) );
            if ( !pBaseCG )
                {
                XLAT_CTXT       BaseCtxt( &ChildContext );

                BaseCtxt.SetInterfaceContext( &BaseCtxt );
                pCurrentCG  = (CG_OBJECT_INTERFACE *)
                                pBaseIntf->ILxlate( &BaseCtxt );
                AddToCGList( pCurrentCG, (CG_CLASS**) &pResultCG, (CG_CLASS**) &pLastItfCG );

                // our base interface made the last one on the list
                pBaseCG = pLastItfCG;
                }

            // start the procnum from our base interface
            GetProcCount()          = pBaseIntf->GetProcCount();
            GetCallBackProcCount()  = pBaseIntf->GetCallBackProcCount();

            }

        if ( GetFileNode() )
            {
            fInheritedIntf = GetFileNode()->GetImportLevel() > 0;
            }

        if ( IsValidRootInterface() )
            {
            pcgInterface = new CG_IUNKNOWN_OBJECT_INTERFACE(this,
                                            GuidStrs,
                                            FALSE,
                                            FALSE,
                                            pBaseCG,
                                            fInheritedIntf);
            }
        else if ( fInheritedIntf )
            {
            pcgInterface = new CG_INHERITED_OBJECT_INTERFACE(this,
                                            GuidStrs,
                                            FALSE,
                                            FALSE,
                                            pBaseCG);
            }
        else
            {
            pcgInterface = new CG_OBJECT_INTERFACE(this,
                                            GuidStrs,
                                            FALSE,
                                            FALSE,
                                            pBaseCG);
            }
        }
    else
        {
        pcgInterface = new CG_INTERFACE(this,
                                        GuidStrs,
                                        FALSE,
                                        FALSE,
                                        pImpHdlCG,
                                        pBaseCG);
        }

    if ( fHasMSConfStructAttr )
        {
        ( (CG_INTERFACE*) pcgInterface)->SetHasMSConfStructAttr();
        }

    // store a pointer to our CG node
    SetCG(  MyContext.AnyAncestorBits(IL_IN_LIBRARY), pcgInterface );

    // if we generated a bunch of new inherited interfaces, link us to the end
    // of the list, and return the list
    AddToCGList( pcgInterface, (CG_CLASS**) &pResultCG, (CG_CLASS**) &pLastItfCG );

    BOOL fImported = FALSE;
    if ( GetDefiningFile() )
        {
        fImported = GetDefiningFile()->GetImportLevel() != 0;
        }

    // if they specified LOCAL, don't generate any CG nodes (except for object)
    if ( MyContext.FInSummary(ATTR_LOCAL) && !fObject )
        {
        return pResultCG;
        }

    //
    // for each of the procedures.
    //

    CG_PROC * pBeginProc = NULL;

    while ( ( pN = MemIter.GetNext() ) != 0 )
        {
        ChildKind = pN->NodeKind();

        // proc nodes may hang under node_id's
        if( ( ChildKind == NODE_PROC )  ||
            (   ( ChildKind == NODE_ID )
             && ( pN->GetChild()->NodeKind() == NODE_PROC ) ) ||
            (   ( ChildKind == NODE_DEF )
             && ( IsPickle ||
                  pN->FInSummary( ATTR_ENCODE ) ||
                  pN->FInSummary( ATTR_DECODE ) ) ) )
            {
            // skip call_as targets
            if (ChildKind == NODE_PROC && ((node_proc *)pN)->IsCallAsTarget())
                continue;

            // translate target of call_as proc
            CG_PROC * pTarget = NULL;
            if (ChildKind == NODE_PROC)
            {
                node_proc * p = ((node_proc *)pN)->GetCallAsType();
                if (p)
                {
                    pTarget = (CG_PROC *) p->ILxlate( &ChildContext);
                }
            }

            // translate CG_NODE
            pChildCG    = pN->ILxlate( &ChildContext );

            // attach target of call_as proc
            if ( pChildCG )
                {
                if (pTarget)
                    ((CG_PROC *)pChildCG)->SetCallAsCG(pTarget);
                    
                AddToCGList( pChildCG, &pCG, &pPrevChildCG );
                }
            
            // Connect Begin and Finish async DCOM procs together.
            // CloneIFAndSplitMethods always places the procedures
            // immediatly under the interface with the Finish proc
            // immediatly following the begin proc.  This code
            // will need to be changed if CloneIFAndSplitMethods
            // changes.
            if ( NODE_PROC == ChildKind ) 
                {

                node_proc *pProc = ( node_proc * ) pN;

                if ( pProc->IsBeginProc() )
                    {

                    MIDL_ASSERT( ( ( CG_NDR * ) pChildCG )->IsProc() );
                    pBeginProc = ( CG_PROC * )pChildCG;
#ifndef NDEBUG                    
                    // assert that the next proc is the finish proc
                    MEM_ITER NewMemIter = MemIter;
                    named_node *pNextNode = NewMemIter.GetNext();
                    MIDL_ASSERT( pNextNode );
                    MIDL_ASSERT( NODE_PROC == pNextNode->NodeKind() );
                    MIDL_ASSERT( ( (node_proc *)pNextNode )->IsFinishProc() );
#endif // NDEBUG
                    }

                else if ( pProc->IsFinishProc() )
                    {
                    
                    MIDL_ASSERT( ( ( CG_NDR * ) pChildCG )->IsProc() );
                    CG_PROC *pFinishProc = ( CG_PROC * )pChildCG;
                                        
                    // Link the begin and finsh procs together
                    pBeginProc->SetIsBeginProc();
                    pBeginProc->SetAsyncRelative( pFinishProc );
                    pFinishProc->SetIsFinishProc();
                    pFinishProc->SetAsyncRelative( pBeginProc );

                    pBeginProc = NULL;
                    }

                }
            
            }

        }

    // make sure we don't have too many procs
    if ( fObject && fInheritedIntf )
        {
        if ( ( GetProcCount() > 256 ) )
            {
            // complain about too many delegated routines
            SemError(this, MyContext, TOO_MANY_DELEGATED_PROCS, NULL);
            }
        else if ( GetProcCount() > 64 )
            {
            pCommand->GetNdrVersionControl().SetHasMoreThan64DelegatedProcs();
            }
        }

        // mark ourselves if we are an all RPC SS interface
    // or if enable is used anywhere within.

    if ( fAllRpcSS )
        {
        ((CG_INTERFACE *)pcgInterface)->SetAllRpcSS( TRUE );
        }
    if ( fAllRpcSS  ||  GetHasProcsWithRpcSs() )
        {
        ((CG_INTERFACE *)pcgInterface)->SetUsesRpcSS( TRUE );
        }

    // consume all the interface attributes
    MyContext.ClearAttributes();
    pContext->ReturnSize( MyContext );

    pcgInterface->SetChild(pCG);

    return pResultCG;
}

//--------------------------------------------------------------------
//
// node_interface_reference::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_interface_reference::ILxlate( XLAT_CTXT * pContext )
{
    XLAT_CTXT       MyContext( this, pContext );
    CG_CLASS    *   pCG       = NULL;

#ifdef trace_cg
    printf("..node_interface_reference,\t%s\n", GetSymName());
#endif

    pCG = new CG_INTERFACE_POINTER( this,
                                    (node_interface *) GetChild() );

    pContext->ReturnSize( MyContext );

    return pCG;
};

//--------------------------------------------------------------------
//
// node_source::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_source::ILxlate( XLAT_CTXT * pContext )
{
    MEM_ITER        MemIter( this );
    CG_CLASS    *   pCG;
    CG_CLASS    *   pNew;
    CG_CLASS    *   pChildCG        = NULL;
    CG_CLASS    *   pPrevChildCG    = NULL;
    node_skl    *   pN;
    XLAT_CTXT       MyContext( this, pContext );


#ifdef trace_cg
    printf("..node_source,\t%s\n", GetSymName());
#endif

    pCG =  (CG_CLASS *) new CG_SOURCE( this );

    //
    // for each of the children.
    //

    while ( ( pN = MemIter.GetNext() ) != 0 )
        {
        pChildCG    = pN->ILxlate( &MyContext );

        if ( pChildCG )
            {
            if (pPrevChildCG)
                {
                pPrevChildCG->SetSibling( pChildCG );
                }
            else
                {
                pCG->SetChild(pChildCG);
                };

            pPrevChildCG    = pChildCG;
            while ( ( pNew = pPrevChildCG->GetSibling() ) != 0 )
                pPrevChildCG = pNew;
            }
        }

    pContext->ReturnSize( MyContext );

    return pCG;
};


//--------------------------------------------------------------------
//
// node_echo_string::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_echo_string::ILxlate( XLAT_CTXT* )
{

#ifdef trace_cg
    printf("..node_echo_string,\t%s\n", GetSymName());
#endif

return 0;
};


//--------------------------------------------------------------------
//
// node_error::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_error::ILxlate( XLAT_CTXT* )
{

#ifdef trace_cg
    printf("..node_error,\t%s\n", GetSymName());
#endif

return 0;
};


CG_CLASS *
Transform(
    IN              node_skl    *   pIL )
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 Routine Description:

    This routine performs the translation from the type graph into the
    code generation classes.

 Arguments:

    pIL     - a pointer to the il tranformer controlling structure.

 Return Value:

    A pointer to the new code generator class.

 Notes:

    This method should be called only on placeholder nodes like struct / proc
    interface, file etc.

----------------------------------------------------------------------------*/

{
    XLAT_CTXT   MyContext;

#ifdef trace_cg
    printf("transforming...\n");
#endif

    pReUseDict  = new REUSE_DICT;
    
    return pIL->ILxlate( &MyContext );
};


//--------------------------------------------------------------------
//
// node_library::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_library::ILxlate( XLAT_CTXT * pContext )
{
    MEM_ITER MemIter(this);
#ifdef trace_cg
    printf("..node_library,\t%s\n", GetSymName());
#endif
    XLAT_CTXT MyContext( this, pContext);

    if ( pCommand->IsNDR64Run() )
        {
        if ( !pCommand->NeedsNDRRun() )
            {
            
            SemError( this, MyContext , NDR64_ONLY_TLB, GetSymName() );        
            }
        return NULL;
        }

    MyContext.SetAncestorBits(IL_IN_LIBRARY);
    XLAT_CTXT  ChildContext( MyContext );

    // don't pass the interface attributes down...
    // save them off elsewhere

    ChildContext.SetInterfaceContext( &MyContext );

    CG_LIBRARY * pLib = new CG_LIBRARY(this, MyContext);

    named_node * pN;

    CG_CLASS * pLast    = NULL;
    CG_CLASS * pChild   = 0;

    while ( ( pN = MemIter.GetNext() ) != 0 )
    {
        switch(pN->NodeKind())
        {
        case NODE_FORWARD:
            {
                node_interface_reference * pIRef = (node_interface_reference *)pN->GetChild();
                if (pIRef)
                    {
                    if (pIRef->NodeKind() == NODE_INTERFACE_REFERENCE)
                        {
                            // create a CG_INTEFACE_REFERENCE node that points to this node
                            pChild = new CG_INTERFACE_REFERENCE(pIRef, ChildContext);
                            // make sure that the interface gets ILxlated.
                            CG_CLASS * pRef = pIRef->GetRealInterface()->ILxlate(&ChildContext);
                            pChild->SetSibling(pRef);
                        }
                    else 
                        {
                        if (pIRef->NodeKind() == NODE_COCLASS)
                            {
                                // don't process this type early
                                pChild = NULL;
                            }
                        else
                            {
                                pChild = pN->ILxlate(&ChildContext);
                                if (pChild && pChild->GetSibling())
                                    pChild = NULL;
                            }
                        }
                    }
                else
                    {
                    pChild = 0;
                    }
            }
            break;
        case NODE_INTERFACE:
            {
                pChild = pN->ILxlate(&ChildContext);
                // skip over inherited interfaces
                while (pChild && pChild->GetCGID() == ID_CG_INHERITED_OBJECT_INTERFACE)
                    pChild=pChild->GetSibling();
            }
            break;
        default:
            // create the appropriate CG node
            pChild = pN->ILxlate(&ChildContext);
            if (pChild && pChild->GetSibling())   // We must have already entered this one.
                pChild = NULL; 
            break;
        }
        // attach the CG_NODE to the end of my child list
        if (NULL != pChild && pChild != pLast)
        {
            if (pLast)
            {
                pLast->SetSibling(pChild);
            }
            else
            {
                pLib->SetChild(pChild);
            }
            pLast = pChild;
            // advance past the end of the list
            while (pLast->GetSibling())
                pLast = pLast->GetSibling();
        }
    }

    SetCG(FALSE, pLib);
    SetCG(TRUE, pLib);

    return pLib;
}

//--------------------------------------------------------------------
//
// node_module::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_module::ILxlate( XLAT_CTXT * pContext )
{
#ifdef trace_cg
    printf("..node_module,\t%s\n", GetSymName());
#endif

    CG_NDR          *   pcgModule    = NULL;
    CG_CLASS        *   pCG             = NULL;
    CG_CLASS        *   pChildCG        = NULL;
    CG_CLASS        *   pPrevChildCG    = NULL;
    MEM_ITER            MemIter( this );
    node_skl        *   pN;
    XLAT_CTXT           MyContext( this, pContext );
    XLAT_CTXT           ChildContext( MyContext );
    
    MyContext.ExtractAttribute( ATTR_GUID );
    MyContext.ExtractAttribute(ATTR_TYPEDESCATTR);
    MyContext.ExtractAttribute( ATTR_HIDDEN );
    while(MyContext.ExtractAttribute(ATTR_CUSTOM));
    
    while (MyContext.ExtractAttribute(ATTR_TYPE));
    // clear member attributes
    while (MyContext.ExtractAttribute(ATTR_MEMBER));

    // don't pass the interface attributes down...
    // save them off elsewhere

    ChildContext.SetInterfaceContext( &MyContext );

    // if we already got spit out, don't do it again...
    if ( GetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY) ) )
        return NULL;

    // generate our CG node

    pcgModule = new CG_MODULE(this, MyContext);

    // store a pointer to our CG node
    SetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY), pcgModule );

    //
    // for each of the members.
    //

    while ( ( pN = MemIter.GetNext() ) != 0 )
    {
        pChildCG    = pN->ILxlate( &ChildContext );

        if ( pChildCG )
        {
            if (NODE_PROC == pN->NodeKind())
            {
                ((CG_PROC *)pChildCG)->SetProckind(PROC_STATIC);
            }
            AddToCGList( pChildCG, &pCG, &pPrevChildCG );
        }
    }

    // consume all the interface attributes
    MyContext.ClearAttributes();
    pContext->ReturnSize( MyContext );

    pcgModule->SetChild(pCG);

    return pcgModule;
}

//--------------------------------------------------------------------
//
// node_coclass::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_coclass::ILxlate( XLAT_CTXT * pContext )
{
#ifdef trace_cg
    printf("..node_coclass,\t%s\n", GetSymName());
#endif
    CG_NDR          *   pcgCoclass    = NULL;
    CG_CLASS        *   pCG             = NULL;
    CG_CLASS        *   pChildCG        = NULL;
    CG_CLASS        *   pPrevChildCG    = NULL;
    MEM_ITER            MemIter( this );
    node_skl        *   pN;
    XLAT_CTXT           MyContext( this, pContext );
    XLAT_CTXT           ChildContext(MyContext);
    MyContext.ExtractAttribute( ATTR_GUID );
    MyContext.ExtractAttribute(ATTR_TYPEDESCATTR);
    MyContext.ExtractAttribute( ATTR_HIDDEN );
    while(MyContext.ExtractAttribute(ATTR_CUSTOM));
    
    while (MyContext.ExtractAttribute(ATTR_TYPE));
    // clear member attributes
    while (MyContext.ExtractAttribute(ATTR_MEMBER));
    
    // don't pass the interface attributes down...
    // save them off elsewhere

    ChildContext.SetInterfaceContext( &MyContext );
    // if we already got spit out, don't do it again...
    if ( GetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY) ) )
        return NULL ;

    // generate our CG node

    pcgCoclass = new CG_COCLASS(this, MyContext);

    // store a pointer to our CG node
    SetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY), pcgCoclass );

    //
    // for every member of the coclass
    //

    node_skl * pChild = 0;
    while ( ( pN = MemIter.GetNext()) != 0 )
        {
        pChild = pN;
        while(NODE_FORWARD == pChild->NodeKind() || NODE_HREF == pChild->NodeKind())
            {
            pChild = pChild->GetChild();
            if ( !pChild )
                {
                XLAT_CTXT ChildErrContext( pN, &MyContext ); 
                SemError( pN, ChildErrContext, UNSATISFIED_FORWARD, pN->GetSymName() );
                exit( UNSATISFIED_FORWARD );
                }
            }
        pChildCG    = pChild->ILxlate( &ChildContext );
        if (pChild->IsInterfaceOrObject())
        {
//            pChildCG = ((node_interface * )pChild)->GetCG(TRUE);
            pChildCG = new CG_INTERFACE_POINTER(this, (node_interface *)pChild );
        }
/*
        if ( pChildCG && NODE_DISPINTERFACE == pChild->NodeKind())
        {
            pChildCG = new CG_INTERFACE_POINTER(this, pChild, NULL);
            //((node_dispinterface *) pChild)->GetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY) );
        }
*/
        if ( pChildCG )
            AddToCGList( pChildCG, &pCG, &pPrevChildCG );
        }

    // consume all the interface attributes
    MyContext.ClearAttributes();
    pContext->ReturnSize( MyContext );

    pcgCoclass->SetChild(pCG);

    return pcgCoclass;
}

//--------------------------------------------------------------------
//
// node_dispinterface::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_dispinterface::ILxlate( XLAT_CTXT * pContext )
{
#ifdef trace_cg
    printf("..node_dispinterface,\t%s\n", GetSymName());
#endif

    CG_NDR          *   pcgInterface    = NULL;
    CG_CLASS        *   pCG             = NULL;
    CG_CLASS        *   pChildCG        = NULL;
    CG_CLASS        *   pPrevChildCG    = NULL;
    CG_CLASS        *   pcgDispatch     = NULL;
    MEM_ITER            MemIter( this );
    node_skl        *   pN;
    XLAT_CTXT           MyContext( this, pContext );
    XLAT_CTXT           BaseContext( MyContext );  // context passed to IDispatch
    XLAT_CTXT           ChildContext( MyContext );
    node_guid       *   pGuid       = (node_guid *)
                                            MyContext.ExtractAttribute( ATTR_GUID );
    GUID_STRS           GuidStrs;
    NODE_T              ChildKind;

    node_interface          *   pBaseIntf;
    MyContext.ExtractAttribute(ATTR_TYPEDESCATTR);
    MyContext.ExtractAttribute( ATTR_HIDDEN );
    while(MyContext.ExtractAttribute(ATTR_CUSTOM));
    
    while (MyContext.ExtractAttribute(ATTR_TYPE));
    // clear member attributes
    while (MyContext.ExtractAttribute(ATTR_MEMBER));

    if (pGuid)
        GuidStrs = pGuid->GetStrs();

    // don't pass the interface attributes down...
    // save them off elsewhere

    BaseContext.SetInterfaceContext( &MyContext );
    ChildContext.SetInterfaceContext( &MyContext );

    // if we already got spit out, don't do it again...
    if ( GetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY) ) )
        return NULL;

    //
    // ILxlate IDispatch
    //
    pcgDispatch = GetIDispatch()->ILxlate(&BaseContext);
    pcgDispatch = ((node_interface *)GetIDispatch())->GetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY) );

    // generate our CG node

    pcgInterface = new CG_DISPINTERFACE(this, GuidStrs,(CG_OBJECT_INTERFACE *)pcgDispatch);

    // store a pointer to our CG node
    SetCG( MyContext.AnyAncestorBits(IL_IN_LIBRARY), pcgInterface );

    // Either we have a single base interface, or we have no base interface.

    pN = MemIter.GetNext();
    if (pN)
    {
        ChildKind = pN->NodeKind();
        if (ChildKind == NODE_FORWARD)
        {
            // We have a base interface
            pBaseIntf = (node_interface *)GetMyBaseInterfaceReference();
            // process the base interface
            if (pBaseIntf)
            {
                pChildCG = pBaseIntf->ILxlate(&ChildContext);
                if ( pChildCG )
                    AddToCGList( pChildCG, &pCG, &pPrevChildCG );
            }
        }
    }

    //
    // for each of the procedures.
    //

    while( pN )
        {
        ChildKind = pN->NodeKind();

        // proc nodes may hang under node_id's
        if( (ChildKind == NODE_FIELD) ||
            ( ChildKind == NODE_PROC )  ||
            ( ( ChildKind == NODE_ID ) && ( pN->GetChild()->NodeKind() == NODE_PROC ) ) )
            {
            pChildCG    = pN->ILxlate( &ChildContext );

            if ( pChildCG )
                AddToCGList( pChildCG, &pCG, &pPrevChildCG );
            }

        pN = MemIter.GetNext();
        }

    // consume all the interface attributes
    MyContext.ClearAttributes();
    pContext->ReturnSize( MyContext );

    pcgInterface->SetChild(pCG);

    return pcgInterface;
}

//--------------------------------------------------------------------
//
// node_pipe::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_pipe::ILxlate( XLAT_CTXT * pContext )
{
#ifdef trace_cg
    printf("..node_pipe,\t%s\n", GetSymName());
#endif

    CG_CLASS     *  pChildCG;
    XLAT_CTXT       MyContext( this, pContext );
    CG_PIPE      *  pCG = new CG_PIPE   (
                                        this,
                                        MyContext
                                        );
    // if /deny is not specified, ignore [range]
    // if [range] is not ignored, new format string is
    // generated for pipes.
    if ( pCommand->IsSwitchDefined( SWITCH_ROBUST ) )
        {
        pCG->SetRangeAttribute( ( node_range_attr* ) MyContext.ExtractAttribute( ATTR_RANGE ) );
        }
    pChildCG = GetChild()->ILxlate( &MyContext );

    pContext->ReturnSize( MyContext );
    pCG->SetChild( pChildCG );

    return pCG;
};

//--------------------------------------------------------------------
//
// node_safearray::ILxlate
//
// Notes:
//
//
//
//--------------------------------------------------------------------

CG_CLASS *
node_safearray::ILxlate( XLAT_CTXT * pContext )
{
#ifdef trace_cg
    printf("..node_safearray,\t%s\n", GetSymName());
#endif

    CG_CLASS     *  pChildCG;
    XLAT_CTXT       MyContext( this, pContext );
    CG_SAFEARRAY *  pCG = new CG_SAFEARRAY(this, MyContext);

    // SAFEARRAY, being defined in the public IDL files, has a known
    // alignment of 4. Now the struct etc. that embeds the SAFEARRAY
    // may have a different alignment but the struct code will make it
    // right by choosing min(ZeePee, max(children)).
    // The child of the node is a type specifier from SAFEARRAY(type).
    // The type alias is the LPSAFEARRAY

    pCG->SetMemoryAlignment( 4 );

    MyContext.GetMemAlign() = 4;
    pContext->ReturnSize( MyContext );

    pChildCG = GetChild()->ILxlate( &MyContext );

    pCG->SetChild( pChildCG );

    // If the SAFEARRAY was not used in a proxy, just pass up the SAFEARRAY class.  
    if ( ! fInProxy )
        return pCG;

    // If the SAFEARRAY was used in a proxy, pass up the the annoted node for
    // LPSAFEARRAY.

    CG_NDR *pTypeAliasCG = (CG_NDR*) ( GetTypeAlias()->ILxlate( pContext ) );

    MIDL_ASSERT( pTypeAliasCG->GetCGID() == ID_CG_USER_MARSHAL );

    CG_USER_MARSHAL *pUserMarshalCG = (CG_USER_MARSHAL *)pTypeAliasCG;

    pUserMarshalCG->SetTypeDescGenerator( pCG );
    
    return pUserMarshalCG;
}


CG_CLASS*
node_async_handle::ILxlate(  XLAT_CTXT * pContext )
{
#ifdef trace_cg
    printf("..node_async_handle,\t%s\n", GetSymName());
#endif
    XLAT_CTXT           MyContext( this, pContext );
    CG_ASYNC_HANDLE*    pAsyncHdl = new CG_ASYNC_HANDLE( this, MyContext );

    return pAsyncHdl;
}

CG_CLASS*
node_midl_pragma::ILxlate( XLAT_CTXT* )
{
    return 0;
}

CG_CLASS*
node_decl_guid::ILxlate( XLAT_CTXT* )
{
    return 0;
}