ppexpn.c

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

C
999
字号
/****************************************************************************
*
*                            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:  Preprocessor expression evaluator for C++ compiler.
*
****************************************************************************/


#include "plusplus.h"

#include <limits.h>

#include "errdefns.h"
#include "preproc.h"
#include "fold.h"
#include "stack.h"
#include "initdefs.h"
#include "carve.h"

#define L       I64LO32
#define H       I64HI32

#define I64Zero( a ) ( (a).uval.u._32[L] == 0 && (a).uval.u._32[H] == 0 )
#define I64NonZero(a) ( ! I64Zero(a)  )
#define U64Zero( a ) ( (a).uval.u._32[L] == 0 && (a).uval.u._32[H] == 0 )
#define U64NonZero(a) ( ! U64Zero(a)  )
#define U64Low( a ) ( a.uval.u._32[L] )
#define U64High( a ) ( a.uval.u._32[H] )

#define U64LT( a, b ) ( U64Cmp( &((a).uval), &((b).uval) ) < 0 )
#define U64GT( a, b ) ( U64Cmp( &((a).uval), &((b).uval) ) > 0 )
#define U64LE( a, b ) ( U64Cmp( &((a).uval), &((b).uval) ) <= 0 )
#define U64GE( a, b ) ( U64Cmp( &((a).uval), &((b).uval) ) >= 0 )
#define U64EQ( a, b ) ( U64Cmp( &((a).uval), &((b).uval) ) == 0 )
#define U64NE( a, b ) ( U64Cmp( &((a).uval), &((b).uval) ) != 0 )

#define I64LT( a, b ) ( I64Cmp( &((a).sval), &((b).sval) ) < 0 )
#define I64GT( a, b ) ( I64Cmp( &((a).sval), &((b).sval) ) > 0 )
#define I64LE( a, b ) ( I64Cmp( &((a).sval), &((b).sval) ) <= 0 )
#define I64GE( a, b ) ( I64Cmp( &((a).sval), &((b).sval) ) >= 0 )
#define I64EQ( a, b ) ( I64Cmp( &((a).sval), &((b).sval) ) == 0 )
#define I64NE( a, b ) ( I64Cmp( &((a).sval), &((b).sval) ) != 0 )

#define U64AddEq(a,b) U64Add( &((a).uval), &((b).uval), &((a).uval) );
#define U64SubEq(a,b) U64Sub( &((a).uval), &((b).uval), &((a).uval) );
#define U64MulEq(a,b) U64Mul( &((a).uval), &((b).uval), &((a).uval) );
#define U64AndEq(a,b) U64And( &((a).uval), &((b).uval), &((a).uval) );
#define U64OrEq(a,b)  U64Or( &((a).uval), &((b).uval), &((a).uval) );
#define U64XOrEq(a,b) U64Xor( &((a).uval), &((b).uval), &((a).uval) );


#define I64SetZero( a ) ( I32ToI64( 0, &(a).sval) );
#define U64SetZero( a ) ( U32ToU64( 0, &(a).uval) );

#ifdef pick
#undef pick
#endif

/* include ctokens.h for the precedence values */
#define prec(value) value
#define pick(token,string,class)
#define no_keywords
static  int    Prec[] = {     // table of token precedences
#include "ctokens.h"
#undef no_keywords

#ifndef NDEBUG
#define prec(value)
#define pick(token,string,class) string
#define no_keywords
static char * TokenNames[] = {
#include "ctokens.h"
#undef no_keywords
#endif

#define NUM_PREC (sizeof(Prec) / sizeof(int))

#define IS_OPERAND( token ) ( ( token == T_ID ) || ( token == T_CONSTANT ) \
                           || ( ( token > T_BEFORE_KEYWORDS ) \
                             && ( token < T_AFTER_KEYWORDS ) ) )

typedef struct ppvalue {
    union {
        unsigned_64    uval;
        signed_64      sval;
    };
    unsigned            no_sign : 1;
} ppvalue;

typedef struct loc_info {
    int pos;                    // incremented when token read
    TOKEN_LOCN  locn;           // token location in source file
} loc_info;

typedef struct operand_stack PPEXPN_OPERAND_STACK; // stack to store operands
struct operand_stack {
    PPEXPN_OPERAND_STACK *next;
    ppvalue     value;
    loc_info    loc;
};
static PPEXPN_OPERAND_STACK *HeadOperand = NULL;


typedef struct token_stack PPEXPN_OPERATOR_STACK; // stack to store operators
struct token_stack {
    PPEXPN_OPERATOR_STACK *next;
    int token;
    loc_info loc;
    int prec;
};
static PPEXPN_OPERATOR_STACK *HeadOperator = NULL;

static carve_t carve_ppoperand_stack;    // carver: operand stack entries
static carve_t carve_pptoken_stack;      // carver: operator stack entries

static int Pos = 0;                     // position of CurToken in parsing

#ifdef NDEBUG
    #define DbgDumpOperatorStack()
    #define DbgDumpOperandStack()
#else

#include "pragdefn.h"

void DbgDumpOperatorStack( void )       // dump PPEXPN_OPERATOR_STACK
{
    PPEXPN_OPERATOR_STACK *cur;

    if( PragDbgToggle.ppexpn ) {
        Stack_forall( HeadOperator, cur ) {
            printf("Token: %d %s Pos %d\n", cur->token
                                          , TokenNames[cur->token]
                                          , cur->loc.pos );
        }
    }
}

void DbgDumpToken( int token )          // dump PPEXPN_OPERAND_STACK
{
    printf("Token: %s\n", TokenNames[token] );
}

void DbgDumpOperandStack( void )        // dump PPEXPN_OPERAND_STACK
{
    PPEXPN_OPERAND_STACK *cur;

    if( PragDbgToggle.ppexpn ) {
        Stack_forall( HeadOperand, cur ) {
            printf("uval: %d sval %d no_sign %d Pos %d\n", cur->value.uval,
                    cur->value.sval, cur->value.no_sign, cur->loc.pos );
        }
    }
}
#endif

static void PrecedenceParse( ppvalue * );
static boolean CStart( void );
static boolean CRightParen( void );
static boolean CLeftParen( void );
static boolean CConditional( void );
static boolean CLogicalOr( void );
static boolean CLogicalAnd(void );
static boolean COr( void );
static boolean CXOr( void );
static boolean CAnd( void );
static boolean CEquality( void );
static boolean CRelational( void );
static boolean CShift( void );
static boolean CAdditive( void );
static boolean CMultiplicative( void );
static boolean CUnary( void );

boolean ( *CExpr[] )(void) = { // table of functions to reduce expressions
    CStart,             /* Level 0 */
    CRightParen,        /* Level 1 */
    CLeftParen,         /* Level 2 */
    CConditional,       /* Level 3 */
    CConditional,       /* Level 4 */
    CLogicalOr,         /* Level 5 */
    CLogicalAnd,        /* Level 6 */
    COr,                /* Level 7 */
    CXOr,               /* Level 8 */
    CAnd,               /* Level 9 */
    CEquality,          /* Level 10 */
    CRelational,        /* Level 11 */
    CShift,             /* Level 12 */
    CAdditive,          /* Level 13 */
    CMultiplicative,    /* Level 14 */
    CUnary              /* Level 15 */
};
#define UNARY_PREC (14)

static void ppexpnInit(         // INITIALIZATION FOR MODULE
    INITFINI* defn )            // - definition
{
    defn = defn;

    carve_ppoperand_stack = CarveCreate( sizeof( PPEXPN_OPERAND_STACK ), 16 );
    HeadOperand = NULL;

    carve_pptoken_stack = CarveCreate( sizeof( PPEXPN_OPERATOR_STACK ), 16 );
    HeadOperator = NULL;
}

static void ppexpnFini( // COMPLETION FOR MODULE
    INITFINI* defn ) // - definition
{
    defn = defn;

    CarveDestroy( carve_ppoperand_stack );
    HeadOperand = NULL;

    CarveDestroy( carve_pptoken_stack );
    HeadOperator = NULL;
}

INITDEFN( ppexpn, ppexpnInit, ppexpnFini );


static void PushOperator( int token, loc_info *loc, int prec )
{
    PPEXPN_OPERATOR_STACK *stack_entry;

    stack_entry = CarveAlloc( carve_pptoken_stack );
    stack_entry->token = token;
    stack_entry->loc = *loc;
    stack_entry->prec = prec;
    StackPush( &HeadOperator, stack_entry );
}

static void PushCurToken( int prec )
{
    loc_info loc;

    SrcFileGetTokenLocn( &loc.locn );
    loc.pos = Pos;
    PushOperator( CurToken, &loc, prec );
}


static boolean PopOperator( int *token, loc_info *loc )
{
    PPEXPN_OPERATOR_STACK *stack_entry;

    stack_entry = StackPop( &HeadOperator );
    if( stack_entry != NULL ) {
        if( token != NULL ) {
            *token = stack_entry->token;
        }
        if( loc != NULL ) {
            *loc = stack_entry->loc;
        }
        CarveFree( carve_pptoken_stack, stack_entry );
        return( TRUE );
    }
    return( FALSE );
}

static boolean TopOperator( int *token, int *prec )
{
    PPEXPN_OPERATOR_STACK *stack_entry;

    stack_entry = StackPop( &HeadOperator );
    if( stack_entry != NULL ) {
        if( token != NULL ) {
            *token = stack_entry->token;
        }
        if( prec != NULL ) {
            *prec = stack_entry->prec;
        }
        StackPush( &HeadOperator, stack_entry );
        return( TRUE );
    }
    return( FALSE );
}

static void PushOperand( ppvalue p, loc_info *loc )
{
    PPEXPN_OPERAND_STACK *stack_entry;

    stack_entry = CarveAlloc( carve_ppoperand_stack );
    stack_entry->value = p;
    stack_entry->loc = *loc;
    StackPush( &HeadOperand, stack_entry );
}

static void PushOperandCurLocation( ppvalue p )
{
    loc_info loc;

    SrcFileGetTokenLocn( &loc.locn );
    loc.pos = Pos;
    PushOperand( p, &loc );
}

static boolean PopOperand( ppvalue *p, loc_info *loc )
{
    PPEXPN_OPERAND_STACK *stack_entry;

    stack_entry = StackPop( &HeadOperand );
    if( stack_entry != NULL ) {
        if( p != NULL ) {
            *p = stack_entry->value;
        }
        if( loc != NULL ) {
            *loc = stack_entry->loc;
        }
        CarveFree( carve_ppoperand_stack, stack_entry );
        return( TRUE );
    }
    return( FALSE );
}

static boolean CheckToken( int prev_token )
{
    if( IS_OPERAND( prev_token ) && IS_OPERAND( CurToken ) ) {
        CErr1( ERR_CONSECUTIVE_OPERANDS ); //  can't have 2 operands in a row
        return( TRUE );
    }
    if( ( CurToken == T_PLUS ) || ( CurToken == T_MINUS ) ) {
        if( ( prev_token != T_RIGHT_PAREN )
         && ( !IS_OPERAND( prev_token ) || prev_token == T_START ) ) {
            if( CurToken == T_PLUS ) {
                CurToken = T_UNARY_PLUS;
            } else {
                CurToken = T_UNARY_MINUS;
            }
        }
    }
    return( FALSE );
}


static boolean PpNextToken( void )  // scan the next token and check for errors
{
    static int prev_token;

    prev_token = CurToken;
    NextToken();
    Pos++;
    return( CheckToken( prev_token ) );
}

long int PpConstExpr( void )    // Entry into ppexpn module
{
    ppvalue val;

    PrecedenceParse( &val );
    return( I64NonZero( val ) );
}

static void unexpectedCurToken( void )
{
    CErr2p( ERR_UNEXPECTED_IN_CONSTANT_EXPRESSION, Tokens[CurToken] );
}

static int isMacroDefined( void )
{
    PPState = PPS_EOL;
    return MacroDependsDefined();
}

static boolean COperand( void )
{
    ppvalue p;
    loc_info loc;
    TOKEN_LOCN left_loc;
    boolean done;

    done = FALSE;
    switch( CurToken ) {
      case T_ID:
        SrcFileGetTokenLocn( &loc.locn ); // need this to store result
        loc.pos = Pos;
        Pos++;
        if( strcmp( "defined", Buffer ) == 0 ) {
            PPState = PPS_EOL | PPS_NO_EXPAND;
            NextToken(); // Don't error check: can have T_ID T_ID here
            if( CurToken == T_LEFT_PAREN ) {
                SrcFileGetTokenLocn( &left_loc );
                NextToken(); // no need to error check or advance Pos
                I32ToI64( isMacroDefined(), &(p.sval) );
                NextToken(); // no need to error check or advance Pos
                if( CurToken != T_RIGHT_PAREN ) {
                    SetErrLoc( &left_loc );
                    CErr1( ERR_UNMATCHED_LEFT_PAREN );
                    done = TRUE;
                }
            } else {
                I32ToI64( isMacroDefined(), &(p.sval) );
            }
        } else {
            CErr2p( WARN_UNDEFD_MACRO_IS_ZERO, Buffer );
            I64SetZero( p );
        }
        p.no_sign = 0;
        if( !done ) {
            PushOperand( p, &loc );
            done = PpNextToken();
        }
        break;
      case T_FALSE:
      case T_TRUE:
        I32ToI64( CurToken == T_TRUE, &(p.sval) );
        p.no_sign = 0;
        PushOperandCurLocation( p );
        done = PpNextToken();
        break;
      case T_CONSTANT:
        switch( ConstType ) {
          case TYP_FLOAT:
          case TYP_DOUBLE:
          case TYP_LONG_DOUBLE:
            CErr1( ERR_EXPR_MUST_BE_INTEGRAL );
            done = TRUE;
            I32ToI64( SafeAtof( Buffer ), &(p.sval) );
            // LMW add long double support if available
            p.no_sign = 0;
            break;
          case TYP_WCHAR:
          case TYP_UCHAR:
          case TYP_USHORT:
          case TYP_UINT:
          case TYP_ULONG:
          case TYP_ULONG64:
            p.uval = Constant64;
            p.no_sign = 1;
            break;
          default:
            p.sval = Constant64;
            p.no_sign = 0;
        }
        if (!done ) {
            PushOperandCurLocation( p );
            done = PpNextToken();
        }
        break;

      default:
        CErr2p( WARN_UNDEFD_MACRO_IS_ZERO, Buffer );
        I64SetZero( p );
        p.no_sign = 0;
        PushOperandCurLocation( p );
        done = PpNextToken();
    }
    return( done );
}

static void PrecedenceParse( ppvalue *p ) // main precedence parse algorithm
{
    int prec_token;
    int prec_operator;
    boolean done;
    int top;
    ppvalue empty;
    loc_info loc;
    error_state_t error_info;

    U32ToU64( 0, &(p->sval) ); //default value

    if( CurToken == T_NULL ) {
        unexpectedCurToken();
        return;
    }
    CErrCheckpoint( &error_info );
    Pos = 0;
    SrcFileGetTokenLocn( &loc.locn );
    loc.pos = Pos;
    PushOperator( T_START, &loc, Prec[T_START] ); // problem because T_START is not a ppvalue
    Pos++;
    CheckToken( T_START ); // check for initial unary + or -
    done = FALSE;
    while( !done ) {
        if( IS_OPERAND( CurToken ) ) {
            done = COperand(); // get operand and read next token
        } else if( CurToken == T_LEFT_PAREN ) {
            PushCurToken( Prec[T_LEFT_PAREN] ); // always push left paren

⌨️ 快捷键说明

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