cenum.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 352 行

C
352
字号
/****************************************************************************
*
*                            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:  enum statement processing
*
****************************************************************************/


#include "cvars.h"
#include "cgswitch.h"
#include <stddef.h>
#include <limits.h>
#include "i64.h"

void EnumInit( void )
{
    int i;

    for( i=0; i < ENUM_HASH_SIZE; i++ ) {
        EnumTable[i] = NULL;
    }
    EnumRecSize = 0;
}


local ENUM_HANDLE EnumLkAdd( TAGPTR tag )
{
    ENUMPTR     esym;
    int         len;

    VfyNewSym( HashValue, Buffer );
    len = sizeof(ENUMDEFN) + strlen(Buffer);
    if( len > EnumRecSize ) EnumRecSize = len;
    esym = (ENUMPTR) CPermAlloc( len );
    strcpy( esym->name, Buffer );
    esym->parent = tag;
    esym->hash = HashValue;
    esym->next_enum = EnumTable[ esym->hash ];
    ++EnumCount;
    if( tag->u.enum_list == NULL ) {
        tag->u.enum_list = esym;
    }
#if 0
    if( CompFlags.emit_browser_info ) {
        esym->xref = NewXref( NULL );
    }
#endif
    return( esym );
}
#if defined( WATCOM_BIG_ENDIAN )
#   define i64val(h,l) { h, l }
#else
#   define i64val(h,l) { l, h }
#endif
enum enum_rng {
    ENUM_UNDEF = -1,
    ENUM_S8,
    ENUM_U8,
    ENUM_S16,
#if TARGET_INT == 2
    ENUM_INT = ENUM_S16,
#endif
    ENUM_U16,
    ENUM_S32,
#if TARGET_INT == 4
    ENUM_INT = ENUM_S32,
#endif
    ENUM_U32,
    ENUM_S64,
    ENUM_U64,
    ENUM_SIZE,
};
enum low_high {
    LOW  =  0,
    HIGH =  1,
};
static uint64 const RangeTable[ENUM_SIZE][2] =
{ //  low                              high
    { i64val( 0xFFFFFFFF, 0xFFFFFF80 ),i64val( 0x00000000, 0x0000007F ) },//s8
    { i64val( 0x00000000, 0x00000000 ),i64val( 0x00000000, 0x000000FF ) },//u8
    { i64val( 0xFFFFFFFF, 0xFFFF8000 ),i64val( 0x00000000, 0x00007FFF ) },//s16
    { i64val( 0x00000000, 0x00000000 ),i64val( 0x00000000, 0x0000FFFF ) },//u16
    { i64val( 0xFFFFFFFF, 0x80000000 ),i64val( 0x00000000, 0x7FFFFFFF ) },//s32
    { i64val( 0x00000000, 0x00000000 ),i64val( 0x00000000, 0xFFFFFFFF ) },//u32
    { i64val( 0x80000000, 0x00000000 ),i64val( 0x7FFFFFFF, 0xFFFFFFFF ) },//s64
    { i64val( 0x00000000, 0x00000000 ),i64val( 0xFFFFFFFF, 0xFFFFFFFF ) },//u64
};

struct { DATA_TYPE decl_type; int size; } ItypeTable[ENUM_SIZE] =
{
    { TYPE_CHAR, TARGET_CHAR  },    //S8
    { TYPE_UCHAR,TARGET_CHAR  },    //U8
#if TARGET_INT == 2
    { TYPE_INT,  TARGET_INT  },     //S16
    { TYPE_UINT, TARGET_INT  },     //U16
#else
    { TYPE_SHORT, TARGET_SHORT },   //S16
    { TYPE_USHORT,TARGET_SHORT },   //U16
#endif
#if TARGET_INT == 4
    { TYPE_INT,   TARGET_INT  },    //S32
    { TYPE_UINT,  TARGET_INT  },    //U32
#else
    { TYPE_LONG,  TARGET_LONG },    //S32
    { TYPE_ULONG, TARGET_LONG },    //U32
#endif
    { TYPE_LONG64, TARGET_LONG64  },//S64
    { TYPE_ULONG64, TARGET_LONG64 },//U64
};

void get_msg_range( char *buff, enum enum_rng index )
{
    if( index & 1 ) {
        sprintf( buff, "%llu to %llu", RangeTable[index][LOW], RangeTable[index][HIGH] );
    } else {
        sprintf( buff, "%lld to %lld", RangeTable[index][LOW], RangeTable[index][HIGH] );
    }
}

TYPEPTR EnumDecl( int flags )
{
    TYPEPTR     typ;
    TAGPTR      tag;

    NextToken();
    if( CurToken == T_ID ) {
        /* could be: (1) "enum" <id> ";"
                     (2) "enum" <id> <variable_name> ";"
                     (3) "enum" <id> "{" <enum_const_decl> ... "}"
        */
        tag = TagLookup();
        NextToken();
        if( CurToken != T_LEFT_BRACE ) {
            typ = tag->sym_type;
            if( typ == NULL ) {
                CErr1( ERR_INCOMPLETE_ENUM_DECL );
                typ = TypeDefault();
            } else {
                if( typ->decl_type != TYPE_ENUM ) {         /* 18-jan-89 */
                    CErr2p( ERR_DUPLICATE_TAG, tag->name );
                }
                typ->u.tag = tag;
            }
            return( typ );
        }
        tag = VfyNewTag( tag, TYPE_ENUM );
    } else {
        tag = NullTag();
    }
    typ = TypeNode( TYPE_ENUM, GetType( TYPE_INT ) );
    typ->u.tag = tag;
    tag->sym_type = typ;
    tag->size = TARGET_INT;
    tag->u.enum_list = NULL;
    if( CurToken == T_LEFT_BRACE ) {
        const_val       val;
        enum enum_rng   index;
        enum enum_rng   const_index;
        enum enum_rng   start_index;
        enum enum_rng   step;
        enum enum_rng   error;
        uint64          n;
        uint64          Inc;
        bool            minus;
        bool            has_sign;
        ENUM_HANDLE     *prev_lnk;
        ENUM_HANDLE     esym;
        int             error_line;
        char            buff[50];

        if( CompFlags.make_enums_an_int ) {
            start_index = ENUM_INT;
        } else {
            start_index = ENUM_S8;
        }
        const_index = ENUM_UNDEF;
        NextToken();
        if( CurToken == T_RIGHT_BRACE ) {
            CErr1( ERR_EMPTY_ENUM_LIST );
        }
        U32ToU64( 1, &Inc );
        U64Clear( n );
        minus = FALSE;
        has_sign = FALSE;
        step = 1;
        prev_lnk = &esym;
        esym = NULL;
        while( CurToken == T_ID ) {
            esym = EnumLkAdd( tag );
            *prev_lnk = esym;
            prev_lnk = &esym->thread;
            error_line = TokenLine;
            NextToken();
            if( CurToken == T_EQUAL ) {
                NextToken();
                error_line = TokenLine;
                ConstExprAndType( &val );
                switch( val.type ){
                case TYPE_ULONG:
                case TYPE_UINT:
                case TYPE_ULONG64:
                    minus = FALSE;
                    break;
                default:
                    if( val.value.u.sign.v ) {
                        minus = TRUE;
                        step = 2;
                    } else {
                        minus = FALSE;
                    }
                    break;
                }
                n = val.value;
            } else if( has_sign ) {
                if( n.u.sign.v ) {
                    minus = TRUE;
                } else {
                    minus = FALSE;
                }
            }
            for( index = start_index; index < ENUM_SIZE; index += step ) {
                if( minus ) {
                    if( I64Cmp( &n, &( RangeTable[ index ][LOW] ) ) >= 0 ) break;
                } else {
                    if( U64Cmp( &n, &( RangeTable[ index ][HIGH]) ) <= 0 ) break;
                }
            }
            error = ENUM_UNDEF;
            if( !CompFlags.extensions_enabled && ( index > ENUM_INT )) {
                error = ENUM_INT;
            }
            if( index >= ENUM_SIZE ) {
                // overflow signed maximum range
                if( error == ENUM_UNDEF ) {
                    error = const_index;
                }
            } else if(( const_index == ENUM_SIZE - 1 ) && minus ) {
                // overflow unsigned maximum range by any negative signed value
                if( error == ENUM_UNDEF )
                    error = const_index;
                step = 1;
            } else {
                if( !has_sign && minus) {
                    has_sign = TRUE;
                    if( index < const_index ) {
                        // round up to signed
                        index = ( const_index + 1 ) & ~1;
                    }
                }
                if( index > const_index ) {
                    const_index = index;
                    typ->object = GetType( ItypeTable[const_index].decl_type );
                    tag->size   = ItypeTable[const_index].size;
                }
            }
            if( error != ENUM_UNDEF ) {
                TokenLine = error_line;
                get_msg_range( buff, error );
                CErr( ERR_ENUM_CONSTANT_OUT_OF_RANGE, buff );
            }
            esym->value = n;
            EnumTable[ esym->hash ] = esym;             /* 08-nov-94 */
            if( CurToken == T_RIGHT_BRACE )
                break;
            U64Add( &n, &Inc, &n );
            MustRecog( T_COMMA );
            if( !CompFlags.extensions_enabled
              && !CompFlags.c99_extensions
              && ( CurToken == T_RIGHT_BRACE )) {
                ExpectIdentifier();         /* 13-may-91 */
            }
        }
        MustRecog( T_RIGHT_BRACE );
    }
    return( typ );
}


int EnumLookup( int hash_value, char *name, struct enum_info *eip )
{
    ENUMPTR     esym;

    for( esym = EnumTable[hash_value]; esym; ) {
        if( strcmp( esym->name, name ) == 0 ) {
            eip->value = esym->value;
            eip->parent = esym->parent;
            eip->level = esym->parent->level;
            return( 1 );            /* indicate ENUM was found */
        }
        esym = esym->next_enum;
    }
    eip->level = -1;                /* indicate not found */
    return( 0 );                    /* indicate this was not an ENUM */
}


void FreeEnums( void )
{
    ENUMPTR     esym;
    int         i;

    for( i = 0; i < ENUM_HASH_SIZE; i++ ) {
        for( ; (esym = EnumTable[i]); ) {
            if( esym->parent->level != SymLevel ) break;
            EnumTable[i] = esym->next_enum;
        }
    }
}

#ifndef NDEBUG

void DumpEnumTable( void )
{
    ENUMPTR     esym;
    int         i;

    puts( "ENUM TABLE DUMP" );
    for( i=0; i < ENUM_HASH_SIZE; i++ ) {
        for( esym = EnumTable[i]; esym; ) {
            if( esym->parent->level == SymLevel ) {
                printf( "%s = %d\n", esym->name, esym->value );
            }
            esym = esym->next_enum;
        }
        printf( "---------%d----------\n", i );
    }
}
#endif

⌨️ 快捷键说明

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