opovload.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,248 行 · 第 1/3 页

C
1,248
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include "plusplus.h"
#include "cgfront.h"
#include "errdefns.h"
#include "fnovload.h"
#include "memmgr.h"
#include "name.h"
#include "ring.h"
#include "fold.h"
#include "initdefs.h"
#include "pcheader.h"
#include "stats.h"
#include "class.h"


typedef enum                    // Used to control scalar operand types
{   GETOP_CONST     = 0x01      // - make type const
,   GETOP_NOVOID    = 0x02      // - don't allow void *
,   GETOP_VOLATILE  = 0x04      // - make type volatile
,   GETOP_DEFAULT   = 0x00      // - default behaviour
} GETOP_CONTROL;

#define OPM_NOAMB        ( OPM_QUEST  | OPM_FUN )


#define OPPRO( code ) __PASTE( OPPRO_NO_, code )
typedef enum
#include "ppopscnv.h"
OP_PROTO_NO;
#undef OPPRO

#define OPPRO( code ) __PASTE( OPM_, code ) = 1 << __PASTE( OPPRO_NO_, code )
typedef enum
#include "ppopscnv.h"
OP_MASK;
#undef OPPRO

#define OPBASIC( arg1, arg2, mask ) NULL
static SYMBOL ovfuns[] =
#include "ppopscnv.h"
;
#undef OPBASIC

#define MAX_FUN_PROTOS ( sizeof(ovfuns) / sizeof(ovfuns[0]) )


#define OPBASIC( arg1, arg2, mask ) mask
static OP_MASK opfun_mask[] =
#include "ppopscnv.h"
;
#undef OPBASIC

#define OPBASIC( arg1, arg2, mask ) { __PASTE( TYP_, arg1 ) , \
                                      __PASTE( TYP_, arg2 ) }
static type_id op_basic_arg[][2] =
#include "ppopscnv.h"
;
#undef OPBASIC

#define OPCNV( code, protos ) protos
static OP_MASK opr_masks[] =
#include "ppopscnv.h"
;
#undef OPCNV

#define MAX_OPR_TYPES ( sizeof( fun_protos ) / sizeof( fun_protos[0] ) )

// If we get an ambiguity between an user-defined operator and a built-in
// operator, for Microsoft compatibility we try again, but this time use
// four void * functions in cv-pairs
// i.e. (void *, void*)
//      (const void *, const void*)
//      (volatile void *, volatile void*)
//      (const volatile void *, const volatile void*)
// but this time check for cv-qualification matches, and rank accordinly
// this appears to be what Microsoft does -- LMW
#define OPBASIC_EXTRA( arg1, arg2, mask, ctl ) NULL
static SYMBOL ovfuns_extra[] =
#include "ppopscnv.h"
;
#undef OPBASIC_EXTRA

#define MAX_FUN_PROTOS_EXTRA ( sizeof(ovfuns_extra) / sizeof(ovfuns_extra[0]) )

#define OPBASIC_EXTRA( arg1, arg2, mask, ctl ) mask
static OP_MASK opfun_mask_extra[] =
#include "ppopscnv.h"
;
#undef OPBASIC_EXTRA

#define OPBASIC_EXTRA( arg1, arg2, mask, ctl ) { __PASTE( TYP_, arg1 ) , \
                                                 __PASTE( TYP_, arg2 ) }
static type_id op_basic_arg_extra[][2] =
#include "ppopscnv.h"
;
#undef OPBASIC_EXTRA

#define OPBASIC_EXTRA( arg1, arg2, mask, ctl ) ctl
static GETOP_CONTROL extra_ctl[] =
#include "ppopscnv.h"
;
#define OPM_REF_MASK (OPM_RA|OPM_RI|OPM_RP)

typedef struct {                    // OVOP -- operand types
    PTREE operand;                  // - operand
    TYPE node_type;                 // - NodeType for node
    TYPE user_type;                 // - NULL, class, enum type
    TYPE class_type;                // - NULL, class type
} OVOP;

typedef struct {                    // OLINF -- overload information
    PTREE expr;                     // - expression
    OVOP left;                      // - operand classification: left
    OVOP right;                     // - operand classification: right
    SYMBOL scalars;                 // - scalars list
    SEARCH_RESULT *result_mem;      // - search result (member)
    SEARCH_RESULT *result_nonmem;   // - search result (non-member)
    SEARCH_RESULT *result_nonmem_namespace;   // - search result (non-member)
    OP_MASK mask;                   // - mask for operator
    PTO_FLAG flags;                 // - flags for operand
    unsigned scalar_overloadable:1; // - TRUE ==> scalar overloadable
    unsigned repeat_overload    :1; // - TRUE ==> repeat overloading (->)
    unsigned have_class_type    :1; // - TRUE ==> have a class operand
    unsigned have_user_type     :1; // - TRUE ==> have a class,enum operand
} OLINF;


ExtraRptCtr( ctrBoolConv );
ExtraRptCtr( ctrBoolRes );
ExtraRptCtr( ctrOverloads );
ExtraRptCtr( ctrRepeats );
ExtraRptCtr( ctrOverloadOps );
ExtraRptCtr( ctrResolveOps );
ExtraRptCtr( ctrResolveFun );
ExtraRptCtr( ctrResolveNone );
ExtraRptCtr( ctrResolveMember );
ExtraRptCtr( ctrResolveScalar );
ExtraRptCtr( ctrResolveNaked );


static void setupOVOP(          // SETUP OVOP
    OLINF* olinf,               // - overload information
    PTREE node,                 // - node for operand
    OVOP* ovop )                // - to be filled in
{
    TYPE node_type;             // - NodeType for operand
    TYPE user_type;             // - NULL, class, enum type
    TYPE class_type;            // - NULL, class type

    ovop->operand = node;
    class_type = NULL;
    if( NULL == node ) {
        node_type = NULL;
        user_type = NULL;
    } else {
        node_type = NodeType( node );
        user_type = UserDefTypeForType( node_type );
        if( user_type != NULL ) {
            olinf->have_user_type = TRUE;
            if( user_type->id == TYP_CLASS ) {
                olinf->have_class_type = TRUE;
                class_type = user_type;
            }
        }
    }
    ovop->node_type = node_type;
    ovop->user_type = user_type;
    ovop->class_type = class_type;
}


static boolean initOLINF(       // INITIALIZE OVERLOAD INFORMATION
    PTREE node,                 // - overload node
    OLINF* olinf )              // - overload information
{
    unsigned cnv;               // - conversion number for operator
    OP_MASK mask;               // - conversion mask
    boolean scov;               // - TRUE ==> needs scalar overload processing

    olinf->expr = node;
    olinf->flags = PTreeOpFlags( node );
    olinf->have_class_type = FALSE;
    olinf->have_user_type = FALSE;
    setupOVOP( olinf, node->u.subtree[0], &olinf->left );
    cnv = ( olinf->flags & PTO_CNV ) >> PTO_CNV_SHIFT;
    if( cnv == 0 ) {
        mask = 0;
        scov = FALSE;
    } else {
        mask = opr_masks[ cnv - 1 ];
        scov = ( mask & OPM_NOAMB ) ? FALSE : TRUE;
    }
    olinf->mask = mask;
    olinf->scalar_overloadable = FALSE;
    olinf->repeat_overload = FALSE;
    if( scov ) {
        olinf->scalar_overloadable = TRUE;
    }
    return scov || ( olinf->flags & PTO_OVLOAD );
}


static PTREE build_fun_name(    // BUILD NAME FOR A FUNCTION
    SEARCH_RESULT *result )     // - search result
{
    SYMBOL_NAME sym_name;

    sym_name = result->sym_name;
    return( NodeSymbolNoRef( PTreeId( sym_name->name )
                           , sym_name->name_syms
                           , result ) );
}

enum                            // Used for ":" overloading
{   COLON_OP1       = 0x01      // - use( type1, type1 )
,   COLON_OP2       = 0x02      // - use( type2, type2 )
,   COLON_NOTSAME2  = 0x04      // - use( type2, type2 ) if type1 != type2
,   COLON_NOTREF1   = 0x08      // - use( type2, type2 ) if ref(1) != type2
,   COLON_NOTREF2   = 0x10      // - use( type2, type2 ) if type1 ! refd(2)
};

static uint_8 colonTable[3][3]= // Used to determine overloading for ":"
{   COLON_OP1 | COLON_NOTSAME2  // - ( ref : ref )
,   COLON_OP1 | COLON_NOTREF1   // - ( ref : class )
,   COLON_OP1                   // - ( ref : other )
,   COLON_OP1 | COLON_NOTREF2   // - ( class : ref )
,   COLON_OP1 | COLON_NOTSAME2  // - ( class : class )
,   COLON_OP1                   // - ( class : other )
,   COLON_OP2                   // - ( other : ref )
,   COLON_OP2                   // - ( other : ref )
,   0                           // - ( other : other )
};

enum                            // Used to check for enumeration operands
{   ENUM_IGNORE                 // - always include
,   ENUM_MATCH_1                // - include if oper op(1) matches enum(1)
,   ENUM_MATCH_2                // - include if oper op(2) matches enum(2)
,   ENUM_MATCH_1_FUN            // - include if func op(1) matches enum(1)
,   ENUM_MATCH_2_FUN            // - include if func op(2) matches enum(2)
,   ENUM_MATCH_BOTH             // - include if oper op(1,2) matches enum(1,2)
,   ENUM_MATCH_MAX              // - include if oper op(1,2) matches max.enum.s
};


static unsigned colonIndex(     // COMPUTE INDEX FOR COLON OVERLOADING
    TYPE type )                 // - type of an operand
{
    unsigned index;             // - 0 == reference, 1 == class, 2 == other

    if( TypeReference( type ) ) {
        index = 0;
    } else if( StructType( type ) ) {
        index = 1;
    } else {
        index = 2;
    }
    return index;
}


static void colonFun(           // SET UP SCALAR FOR COLON OVERLOADING
    OLINF* olinf,               // - overload information
    unsigned curr,              // - function index
    TYPE type )                 // - overloading type
{
    SYMBOL fun;                 // - function in scalar-overload list
    arg_list *alist;            // - arguments for function

    fun = ovfuns[ curr ];
    alist = SymFuncArgList( fun );
    alist->type_list[0] = type;
    alist->type_list[1] = type;
    RingAppend( &olinf->scalars, fun );
}


static void overloadColon(      // OVERLOAD COLON OPERATOR
    OLINF* olinf,               // - overload information
    unsigned curr )             // - current index
{
    TYPE type1;                 // - NodeType( operand[1] )
    TYPE type2;                 // - NodeType( operand[2] )
    uint_8 mask;                // - mask for overloading type

    type1 = olinf->left.node_type;
    type2 = olinf->right.node_type;
    mask = colonTable[ colonIndex( type1 ) ][ colonIndex( type2 ) ];
    if( mask & COLON_OP1 ) {
        colonFun( olinf, curr, type1 );
    }
    ++curr;
    if( mask & COLON_OP2 ) {
        colonFun( olinf, curr, type2 );
    } else if( mask & COLON_NOTSAME2 ) {
        if( ! TypesIdentical( type1, type2 ) ) {
            colonFun( olinf, curr, type2 );
        }
    } else if( mask & COLON_NOTREF1 ) {
        if( ! TypesIdentical( TypeReferenced( type1 ), type2 ) ) {
            colonFun( olinf, curr, type2 );
        }
    } else if( mask & COLON_NOTREF2 ) {
        if( ! TypesIdentical( type1, TypeReferenced( type2 ) ) ) {
            colonFun( olinf, curr, type2 );
        }
    }
}


static void scalarOperators(    // FIND SYMBOLS FOR SCALAR OPERATORS
    OLINF* olinf )              // - overload information
{
    unsigned curr;              // - current item
    PTREE right;                // - NULL or right node if used in overloading

    olinf->scalars = NULL;
    olinf->result_mem = NULL;
    olinf->result_nonmem = NULL;
    olinf->result_nonmem_namespace = NULL;
    right = NULL;
    if( olinf->flags & PTO_BINARY ) {
        if( !( olinf->mask & OPM_LT ) ) {
            right = olinf->expr->u.subtree[1];
        }
    }
    setupOVOP( olinf, right, &olinf->right );
    if( olinf->scalar_overloadable ) {
        if( olinf->mask & OPM_RR ) {
            if( olinf->have_class_type ) {
                for( curr = 0; curr < MAX_FUN_PROTOS; ++ curr ) {
                    OP_MASK fun_mask;
                    fun_mask = opfun_mask[ curr ];
                    if( fun_mask & OPM_RR ) {
                        overloadColon( olinf, curr );
                    } else if( olinf->mask & fun_mask ) {
                        RingAppend( &olinf->scalars, ovfuns[ curr ] );
                    }
                }
            }
        } else {
            if( olinf->have_user_type ) {
                boolean complex_assign = ( olinf->mask & OPM_ASSIGN )
                                       &&( olinf->left.class_type != NULL );
                if( !complex_assign ||
                   ( complex_assign && (olinf->mask & OPM_REF_MASK ) ) ) {
                    for( curr = 0; curr < MAX_FUN_PROTOS; ++ curr ) {
                        OP_MASK fun_mask;
                        fun_mask = opfun_mask[ curr ];
                        if( olinf->mask & fun_mask ) {
                            if( ( olinf->mask & fun_mask ) != OPM_ASSIGN ) {
                            // not just assign matching
                                RingAppend( &olinf->scalars, ovfuns[ curr ] );
                            }
                        }
                    }
                }
            }
        }
    }
}


static CNV_DIAG diag_transform =// diagnosis for transformation
{   ERR_CALL_WATCOM
,   ERR_CALL_WATCOM
,   ERR_CALL_WATCOM
,   ERR_CALL_WATCOM
,   ERR_CALL_WATCOM
};


static CNV_RETN transform_operand(// TRANSFORM AN OPERAND (TO SCALAR)
    PTREE *a_operand,           // - addr( operand )
    TYPE type,                  // - target type
    OP_MASK mask )              // - operator mask
{
    TYPE nd_type;               // - node type
    CNV_RETN cnv_status;        // - conversion status

    nd_type = (*a_operand)->type;
    if( ( NULL != PointerTypeEquivalent( type ) || MemberPtrType( type ) )
      &&( 0 == ( mask & OPM_RR ) ) ) {
        type = UdcFindType( nd_type, type );
    }
    if( ( type != NULL ) && ( NULL == EnumType( nd_type ) ) ) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?