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 + -
显示快捷键?