/*- * Copyright (c) 1998, 2002-2008 Kiyoshi Matsui * All rights reserved. * * Some parts of this code are derived from the public domain software * DECUS cpp (1984,1985) written by Martin Minow. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * E V A L . C * E x p r e s s i o n E v a l u a t i o n * * The routines to evaluate #if expression are placed here. * Some routines are used also to evaluate the value of numerical tokens. */ #if PREPROCESSED #include "mcpp.H" #else #include "system.H" #include "internal.H" #endif typedef struct optab { char op; /* Operator */ char prec; /* Its precedence */ char skip; /* Short-circuit: non-0 to skip */ } OPTAB; static int eval_lex( void); /* Get type and value of token */ static int chk_ops( void); /* Check identifier-like ops */ static VAL_SIGN * eval_char( char * const token); /* Evaluate character constant */ static expr_t eval_one( char ** seq_pp, int wide, int mbits, int * ucn8); /* Evaluate a character */ static VAL_SIGN * eval_eval( VAL_SIGN * valp, int op); /* Entry to #if arithmetic */ static expr_t eval_signed( VAL_SIGN ** valpp, expr_t v1, expr_t v2, int op); /* Do signed arithmetic of expr.*/ static expr_t eval_unsigned( VAL_SIGN ** valpp, uexpr_t v1u, uexpr_t v2u , int op); /* Do unsigned arithmetic */ static void overflow( const char * op_name, VAL_SIGN ** valpp , int ll_overflow); /* Diagnose overflow of expr. */ static int do_sizeof( void); /* Evaluate sizeof (type) */ static int look_type( int typecode); /* Look for type of the name */ static void dump_val( const char * msg, const VAL_SIGN * valp); /* Print value of an operand */ static void dump_stack( const OPTAB * opstack, const OPTAB * opp , const VAL_SIGN * value, const VAL_SIGN * valp); /* Print stacked operators */ /* For debug and error messages. */ static const char * const opname[ OP_END + 1] = { "end of expression", "val", "(", "unary +", "unary -", "~", "!", "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", ":", ")", "(none)" }; /* * opdope[] has the operator (and operand) precedence: * Bits * 7 Unused (so the value is always positive) * 6-2 Precedence (0000 .. 0174) * 1-0 Binary op. flags: * 10 The next binop flag (binop should/not follow). * 01 The binop flag (should be set/cleared when this op is seen). * Note: next binop * value 1 0 Value doesn't follow value. * Binop, ), END should follow value, value or unop doesn't. * ( 0 0 ( doesn't follow value. Value follows. * unary 0 0 Unop doesn't follow value. Value follows. * binary 0 1 Binary op follows value. Value follows. * ) 1 1 ) follows value. Binop, ), END follows. * END 0 1 END follows value, doesn't follow ops. */ static const char opdope[ OP_END + 1] = { 0001, /* End of expression */ 0002, 0170, /* VAL (constant), LPA */ /* Unary op's */ 0160, 0160, 0160, 0160, /* PLU, NEG, COM, NOT */ /* Binary op's */ 0151, 0151, 0151, /* MUL, DIV, MOD, */ 0141, 0141, 0131, 0131, /* ADD, SUB, SL, SR */ 0121, 0121, 0121, 0121, 0111, 0111, /* LT, LE, GT, GE, EQ, NE */ 0101, 0071, 0061, 0051, 0041, /* AND, XOR, OR, ANA, ORO */ 0031, 0031, /* QUE, COL */ /* Parens */ 0013, 0023 /* RPA, END */ }; /* * OP_QUE, OP_RPA and unary operators have alternate precedences: */ #define OP_RPA_PREC 0013 #define OP_QUE_PREC 0024 /* From right to left grouping */ #define OP_UNOP_PREC 0154 /* ditto */ /* * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that * #if FOO != 0 && 10 / FOO ... * doesn't generate an error message. They are stored in optab.skip. */ #define S_ANDOR 2 #define S_QUEST 1 static VAL_SIGN ev; /* Current value and signedness */ static int skip = 0; /* 3-way signal of skipping expr*/ static const char * const non_eval = " (in non-evaluated sub-expression)"; /* _W8_ */ #if HAVE_LONG_LONG && COMPILER == INDEPENDENT static int w_level = 1; /* warn_level at overflow of long */ #else static int w_level = 2; #endif /* * In KR and OLD_PREP modes. * Define bits for the basic types and their adjectives. */ #define T_CHAR 1 #define T_INT 2 #define T_FLOAT 4 #define T_DOUBLE 8 #define T_LONGDOUBLE 16 #define T_SHORT 32 #define T_LONG 64 #define T_LONGLONG 128 #define T_SIGNED 256 #define T_UNSIGNED 512 #define T_PTR 1024 /* Pointer to data objects */ #define T_FPTR 2048 /* Pointer to functions */ /* * The SIZES structure is used to store the values for #if sizeof. */ typedef struct sizes { int bits; /* If this bit is set, */ int size; /* this is the datum size value */ int psize; /* this is the pointer size */ } SIZES; /* * S_CHAR, etc. define the sizeof the basic TARGET machine word types. * By default, sizes are set to the values for the HOST computer. If * this is inappropriate, see those tables for details on what to change. * Also, if you have a machine where sizeof (signed int) differs from * sizeof (unsigned int), you will have to edit those tables and code in * eval.c. * Note: sizeof in #if expression is disallowed by Standard. */ #define S_CHAR (sizeof (char)) #define S_SINT (sizeof (short int)) #define S_INT (sizeof (int)) #define S_LINT (sizeof (long int)) #define S_FLOAT (sizeof (float)) #define S_DOUBLE (sizeof (double)) #define S_PCHAR (sizeof (char *)) #define S_PSINT (sizeof (short int *)) #define S_PINT (sizeof (int *)) #define S_PLINT (sizeof (long int *)) #define S_PFLOAT (sizeof (float *)) #define S_PDOUBLE (sizeof (double *)) #define S_PFPTR (sizeof (int (*)())) #if HAVE_LONG_LONG #if (HOST_COMPILER == BORLANDC) \ || (HOST_COMPILER == MSC && defined(_MSC_VER) && (_MSC_VER < 1300)) #define S_LLINT (sizeof (__int64)) #define S_PLLINT (sizeof (__int64 *)) #else #define S_LLINT (sizeof (long long int)) #define S_PLLINT (sizeof (long long int *)) #endif #endif #define S_LDOUBLE (sizeof (long double)) #define S_PLDOUBLE (sizeof (long double *)) typedef struct types { int type; /* This is the bits for types */ char * token_name; /* this is the token word */ int excluded; /* but these aren't legal here. */ } TYPES; #define ANYSIGN (T_SIGNED | T_UNSIGNED) #define ANYFLOAT (T_FLOAT | T_DOUBLE | T_LONGDOUBLE) #if HAVE_LONG_LONG #define ANYINT (T_CHAR | T_SHORT | T_INT | T_LONG | T_LONGLONG) #else #define ANYINT (T_CHAR | T_SHORT | T_INT | T_LONG) #endif static const TYPES basic_types[] = { { T_CHAR, "char", ANYFLOAT | ANYINT }, { T_SHORT, "short", ANYFLOAT | ANYINT }, { T_INT, "int", ANYFLOAT | T_CHAR | T_INT }, { T_LONG, "long", ANYFLOAT | ANYINT }, #if HAVE_LONG_LONG #if HOST_COMPILER == BORLANDC { T_LONGLONG, "__int64", ANYFLOAT | ANYINT }, #else { T_LONGLONG, "long long", ANYFLOAT | ANYINT }, #endif #endif { T_FLOAT, "float", ANYFLOAT | ANYINT | ANYSIGN }, { T_DOUBLE, "double", ANYFLOAT | ANYINT | ANYSIGN }, { T_LONGDOUBLE, "long double", ANYFLOAT | ANYINT | ANYSIGN }, { T_SIGNED, "signed", ANYFLOAT | ANYINT | ANYSIGN }, { T_UNSIGNED, "unsigned", ANYFLOAT | ANYINT | ANYSIGN }, { 0, NULL, 0 } /* Signal end */ }; /* * In this table, T_FPTR (pointer to function) should be placed last. */ static const SIZES size_table[] = { { T_CHAR, S_CHAR, S_PCHAR }, /* char */ { T_SHORT, S_SINT, S_PSINT }, /* short int */ { T_INT, S_INT, S_PINT }, /* int */ { T_LONG, S_LINT, S_PLINT }, /* long */ #if HAVE_LONG_LONG { T_LONGLONG, S_LLINT, S_PLLINT }, /* long long */ #endif { T_FLOAT, S_FLOAT, S_PFLOAT }, /* float */ { T_DOUBLE, S_DOUBLE, S_PDOUBLE }, /* double */ { T_LONGDOUBLE, S_LDOUBLE, S_PLDOUBLE }, /* long double */ { T_FPTR, 0, S_PFPTR }, /* int (*()) */ { 0, 0, 0 } /* End of table */ }; #define is_binary(op) (FIRST_BINOP <= op && op <= LAST_BINOP) #define is_unary(op) (FIRST_UNOP <= op && op <= LAST_UNOP) #if MCPP_LIB void init_eval( void) { skip = 0; } #endif expr_t eval_if( void) /* * Evaluate a #if expression. Straight-forward operator precedence. * This is called from directive() on encountering an #if directive. * It calls the following routines: * eval_lex() Lexical analyser -- returns the type and value of * the next input token. * eval_eval() Evaluates the current operator, given the values on the * value stack. Returns a pointer to the (new) value stack. */ { VAL_SIGN value[ NEXP * 2 + 1]; /* Value stack */ OPTAB opstack[ NEXP * 3 + 1]; /* Operator stack */ int parens = 0; /* Nesting levels of (, ) */ int prec; /* Operator precedence */ int binop = 0; /* Set if binary op. needed */ int op1; /* Operator from stack */ int skip_cur; /* For short-circuit testing */ VAL_SIGN * valp = value; /* -> Value and signedness */ OPTAB * opp = opstack; /* -> Operator stack */ int op; /* Current operator */ opp->op = OP_END; /* Mark bottom of stack */ opp->prec = opdope[ OP_END]; /* And its precedence */ skip = skip_cur = opp->skip = 0; /* Not skipping now */ while (1) { if (mcpp_debug & EXPRESSION) mcpp_fprintf( DBG , "In eval loop skip = %d, binop = %d, line is: %s\n" , opp->skip, binop, infile->bptr); skip = opp->skip; op = eval_lex(); skip = 0; /* Reset to be ready to return */ switch (op) { case OP_SUB : if (binop == 0) op = OP_NEG; /* Unary minus */ break; case OP_ADD : if (binop == 0) op = OP_PLU; /* Unary plus */ break; case OP_FAIL: return 0L; /* Token error */ } if (mcpp_debug & EXPRESSION) mcpp_fprintf( DBG , "op = %s, opdope = %04o, binop = %d, skip = %d\n" , opname[ op], opdope[ op], binop, opp->skip); if (op == VAL) { /* Value? */ if (binop != 0) { /* Binop is needed */ cerror( "Misplaced constant \"%s\"" /* _E_ */ , work_buf, 0L, NULL); return 0L; } else if (& value[ NEXP * 2] <= valp) { cerror( "More than %.0s%ld constants stacked at %s" /* _E_ */ , NULL, (long) (NEXP * 2 - 1), work_buf); return 0L; } else { if (mcpp_debug & EXPRESSION) { dump_val( "pushing ", &ev); mcpp_fprintf( DBG, " onto value stack[%d]\n" , (int)(valp - value)); } valp->val = ev.val; (valp++)->sign = ev.sign; binop = 1; /* Binary operator or so should follow */ } continue; } /* Else operators */ prec = opdope[ op]; if (binop != (prec & 1)) { if (op == OP_EOE) cerror( "Unterminated expression" /* _E_ */ , NULL, 0L, NULL); else cerror( "Operator \"%s\" in incorrect context" /* _E_ */ , opname[ op], 0L, NULL); return 0L; } binop = (prec & 2) >> 1; /* Binop should follow? */ while (1) { if (mcpp_debug & EXPRESSION) mcpp_fprintf( DBG , "op %s, prec %d, stacked op %s, prec %d, skip %d\n" , opname[ op], prec, opname[ opp->op], opp->prec, opp->skip); /* Stack coming sub-expression of higher precedence. */ if (opp->prec < prec) { if (op == OP_LPA) { prec = OP_RPA_PREC; if (standard && (warn_level & 4) && ++parens == std_limits.exp_nest + 1) cwarn( "More than %.0s%ld nesting of parens" /* _W4_ */ , NULL, (long) std_limits.exp_nest, NULL); } else if (op == OP_QUE) { prec = OP_QUE_PREC; } else if (is_unary( op)) { prec = OP_UNOP_PREC; } op1 = opp->skip; /* Save skip for test */ /* * Push operator onto operator stack. */ opp++; if (& opstack[ NEXP * 3] <= opp) { cerror( "More than %.0s%ld operators and parens stacked at %s" /* _E_ */ , NULL, (long) (NEXP * 3 - 1), opname[ op]); return 0L; } opp->op = op; opp->prec = prec; if (&value[0] < valp) skip_cur = (valp[-1].val != 0L); /* Short-circuit tester */ /* * Do the short-circuit stuff here. Short-circuiting * stops automagically when operators are evaluated. */ if ((op == OP_ANA && ! skip_cur) || (op == OP_ORO && skip_cur)) { opp->skip = S_ANDOR; /* And/or skip starts */ if (skip_cur) /* Evaluate non-zero */ valp[-1].val = 1L; /* value to 1 */ } else if (op == OP_QUE) { /* Start of ?: operator */ opp->skip = (op1 & S_ANDOR) | (!skip_cur ? S_QUEST : 0); } else if (op == OP_COL) { /* : inverts S_QUEST */ opp->skip = (op1 & S_ANDOR) | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST); } else { /* Other operators leave*/ opp->skip = op1; /* skipping unchanged. */ } if (mcpp_debug & EXPRESSION) { mcpp_fprintf( DBG, "stacking %s, ", opname[ op]); if (&value[0] < valp) dump_val( "valp[-1].val == ", valp - 1); mcpp_fprintf( DBG, " at %s\n", infile->bptr); dump_stack( opstack, opp, value, valp); } break; } /* * Coming sub-expression is of lower precedence. * Evaluate stacked sub-expression. * Pop operator from operator stack and evaluate it. * End of stack and '(', ')' are specials. */ skip_cur = opp->skip; /* Remember skip value */ switch ((op1 = opp->op)) { /* Look at stacked op */ case OP_END: /* Stack end marker */ if (op == OP_RPA) { /* No corresponding ( */ cerror( "Excessive \")\"", NULL, 0L, NULL); /* _E_ */ return 0L; } if (op == OP_EOE) return valp[-1].val; /* Finished ok. */ break; case OP_LPA: /* ( on stack */ if (op != OP_RPA) { /* Matches ) on input? */ cerror( "Missing \")\"", NULL, 0L, NULL); /* _E_ */ return 0L; } opp--; /* Unstack it */ parens--; /* Count down nest level*/ break; case OP_QUE: /* Evaluate true expr. */ break; case OP_COL: /* : on stack */ opp--; /* Unstack : */ if (opp->op != OP_QUE) { /* Matches ? on stack? */ cerror( "Misplaced \":\", previous operator is \"%s\"" /* _E_ */ , opname[opp->op], 0L, NULL); return 0L; } /* Evaluate op1. Fall through */ default: /* Others: */ opp--; /* Unstack the operator */ if (mcpp_debug & EXPRESSION) { mcpp_fprintf( DBG, "Stack before evaluation of %s\n" , opname[ op1]); dump_stack( opstack, opp, value, valp); } if (op1 == OP_COL) skip = 0; else skip = skip_cur; valp = eval_eval( valp, op1); if (valp->sign == VAL_ERROR) return 0L; /* Out of range or divide by 0 */ valp++; skip = 0; if (mcpp_debug & EXPRESSION) { mcpp_fprintf( DBG, "Stack after evaluation\n"); dump_stack( opstack, opp, value, valp); } } /* op1 switch end */ if (op1 == OP_END || op1 == OP_LPA || op1 == OP_QUE) break; /* Read another op. */ } /* Stack unwind loop */ } return 0L; /* Never reach here */ } static int eval_lex( void) /* * Return next operator or constant to evaluate. Called from eval_if(). It * calls a special-purpose routines for character constants and numeric values: * eval_char() called to evaluate 'x' * eval_num() called to evaluate numbers * C++98 treats 11 identifier-like tokens as operators. * POST_STD forbids character constants in #if expression. */ { int c1; VAL_SIGN * valp; int warn = ! skip || (warn_level & 8); int token_type; int c; ev.sign = SIGNED; /* Default signedness */ ev.val = 0L; /* Default value (on error or 0 value) */ in_if = ! skip; /* Inform to expand_macro() that the macro is */ /* in #if line and not skipped expression. */ c = skip_ws(); if (c == '\n') { unget_ch(); return OP_EOE; /* End of expression */ } token_type = get_unexpandable( c, warn); if (standard && macro_line == MACRO_ERROR) return OP_FAIL; /* Unterminated macro call */ if (token_type == NO_TOKEN) return OP_EOE; /* Only macro(s) expanding to 0-token */ switch (token_type) { case NAM: if (standard && str_eq( identifier, "defined")) { /* defined name */ c1 = c = skip_ws(); if (c == '(') /* Allow defined (name) */ c = skip_ws(); if (scan_token( c, (workp = work_buf, &workp), work_end) == NAM) { DEFBUF * defp = look_id( identifier); if (warn) { ev.val = (defp != NULL); if ((mcpp_debug & MACRO_CALL) && ! skip && defp) /* Annotate if the macro is in non-skipped expr. */ mcpp_fprintf( OUT, "/*%s*/", defp->name); } if (c1 != '(' || skip_ws() == ')') /* Balanced ? */ return VAL; /* Parsed ok */ } cerror( "Bad defined syntax: %s" /* _E_ */ , infile->fp ? "" : infile->buffer, 0L, NULL); break; } else if (cplus_val) { if (str_eq( identifier, "true")) { ev.val = 1L; return VAL; } else if (str_eq( identifier, "false")) { ev.val = 0L; return VAL; } else if (mcpp_mode != POST_STD && (openum = id_operator( identifier)) != 0) { /* Identifier-like operator in C++98 */ strcpy( work_buf, identifier); return chk_ops(); } } else if (! standard && str_eq( identifier, "sizeof")) { /* sizeof hackery */ return do_sizeof(); /* Gets own routine */ } /* * The ANSI C Standard says that an undefined symbol * in an #if has the value zero. We are a bit pickier, * warning except where the programmer was careful to write * #if defined(foo) ? foo : 0 */ if ((! skip && (warn_level & 4)) || (skip && (warn_level & 8))) cwarn( "Undefined symbol \"%s\"%.0ld%s" /* _W4_ _W8_ */ , identifier, 0L, skip ? non_eval : ", evaluated to 0"); return VAL; case CHR: /* Character constant */ case WCHR: /* Wide char constant */ if (mcpp_mode == POST_STD) { cerror( "Can't use a character constant %s" /* _E_ */ , work_buf, 0L, NULL); break; } valp = eval_char( work_buf); /* 'valp' points 'ev' */ if (valp->sign == VAL_ERROR) break; if (mcpp_debug & EXPRESSION) { dump_val( "eval_char returns ", &ev); mcpp_fputc( '\n', DBG); } return VAL; /* Return a value */ case STR: /* String literal */ case WSTR: /* Wide string literal */ cerror( "Can't use a string literal %s", work_buf, 0L, NULL); /* _E_ */ break; case NUM: /* Numbers are harder */ valp = eval_num( work_buf); /* 'valp' points 'ev' */ if (valp->sign == VAL_ERROR) break; if (mcpp_debug & EXPRESSION) { dump_val( "eval_num returns ", &ev); mcpp_fputc( '\n', DBG); } return VAL; case OPE: /* Operator or punctuator */ return chk_ops(); default: /* Total nonsense */ cerror( "Can't use the character %.0s0x%02lx" /* _E_ */ , NULL, (long) c, NULL); break; } return OP_FAIL; /* Any errors */ } static int chk_ops( void) /* * Check the operator. * If it can't be used in #if expression return OP_FAIL * else return openum. */ { switch (openum) { case OP_STR: case OP_CAT: case OP_ELL: case OP_1: case OP_2: case OP_3: cerror( "Can't use the operator \"%s\"" /* _E_ */ , work_buf, 0L, NULL); return OP_FAIL; default: return openum; } } static int do_sizeof( void) /* * Process the sizeof (basic type) operation in an #if string. * Sets ev.val to the size and returns * VAL success * OP_FAIL bad parse or something. * This routine is never called in STD and POST_STD mode. */ { const char * const no_type = "sizeof: No type specified"; /* _E_ */ int warn = ! skip || (warn_level & 8); int type_end = FALSE; int typecode = 0; int token_type = NO_TOKEN; const SIZES * sizp = NULL; if (get_unexpandable( skip_ws(), warn) != OPE || openum != OP_LPA) goto no_good; /* Not '(' */ /* * Scan off the tokens. */ while (! type_end) { token_type = get_unexpandable( skip_ws(), warn); /* Get next token expanding macros */ switch (token_type) { case OPE: if (openum == OP_LPA) { /* thing (*)() func ptr */ if (get_unexpandable( skip_ws(), warn) == OPE && openum == OP_MUL && get_unexpandable( skip_ws(), warn) == OPE && openum == OP_RPA) { /* (*) */ if (get_unexpandable( skip_ws(), warn) != OPE || openum != OP_LPA || get_unexpandable( skip_ws(), warn) != OPE || openum != OP_RPA) /* Not () */ goto no_good; typecode |= T_FPTR; /* Function pointer */ } else { /* Junk is an error */ goto no_good; } } else { /* '*' or ')' */ type_end = TRUE; } break; case NAM: /* Look for type comb. */ if ((typecode = look_type( typecode)) == 0) return OP_FAIL; /* Illegal type or comb.*/ break; default: goto no_good; /* Illegal token */ } } /* End of while */ /* * We are at the end of the type scan. Chew off '*' if necessary. */ if (token_type == OPE) { if (openum == OP_MUL) { /* '*' */ typecode |= T_PTR; if (get_unexpandable( skip_ws(), warn) != OPE) goto no_good; } if (openum == OP_RPA) { /* ')' */ /* * Last syntax check * We assume that all function pointers are the same size: * sizeof (int (*)()) == sizeof (float (*)()) * We assume that signed and unsigned don't change the size: * sizeof (signed int) == sizeof (unsigned int) */ if ((typecode & T_FPTR) != 0) { /* Function pointer */ typecode = T_FPTR | T_PTR; } else { /* Var or var * datum */ typecode &= ~(T_SIGNED | T_UNSIGNED); #if HAVE_LONG_LONG if ((typecode & (T_SHORT | T_LONG | T_LONGLONG)) != 0) #else if ((typecode & (T_SHORT | T_LONG)) != 0) #endif typecode &= ~T_INT; } if ((typecode & ~T_PTR) == 0) { cerror( no_type, NULL, 0L, NULL); return OP_FAIL; } else { /* * Exactly one bit (and possibly T_PTR) may be set. */ for (sizp = size_table; sizp->bits != 0; sizp++) { if ((typecode & ~T_PTR) == sizp->bits) { ev.val = ((typecode & T_PTR) != 0) ? sizp->psize : sizp->size; break; } } } } else { goto no_good; } } else { goto no_good; } if (mcpp_debug & EXPRESSION) { if (sizp) mcpp_fprintf( DBG, "sizp->bits:0x%x sizp->size:0x%x sizp->psize:0x%x ev.val:0x%lx\n" , sizp->bits, sizp->size, sizp->psize , (unsigned long) ev.val); } return VAL; no_good: unget_ch(); cerror( "sizeof: Syntax error", NULL, 0L, NULL); /* _E_ */ return OP_FAIL; } static int look_type( int typecode ) { const char * const unknown_type = "sizeof: Unknown type \"%s\"%.0ld%s"; /* _E_ _W8_ */ const char * const illeg_comb = "sizeof: Illegal type combination with \"%s\"%.0ld%s"; /* _E_ _W8_ */ int token_type; const TYPES * tp; if (str_eq( identifier, "long")) { if ((token_type = get_unexpandable( skip_ws(), !skip || (warn_level & 8))) == NO_TOKEN) return typecode; if (token_type == NAM) { #if HAVE_LONG_LONG if (str_eq( identifier, "long")) { strcpy( work_buf, "long long"); goto basic; } #endif if (str_eq( identifier, "double")) { strcpy( work_buf, "long double"); goto basic; } } unget_string( work_buf, NULL); /* Not long long */ strcpy( work_buf, "long"); /* nor long double */ } /* * Look for this unexpandable token in basic_types. */ basic: for (tp = basic_types; tp->token_name != NULL; tp++) { if (str_eq( work_buf, tp->token_name)) break; } if (tp->token_name == NULL) { if (! skip) { cerror( unknown_type, work_buf, 0L, NULL); return 0; } else if (warn_level & 8) { cwarn( unknown_type, work_buf, 0L, non_eval); } } if ((typecode & tp->excluded) != 0) { if (! skip) { cerror( illeg_comb, work_buf, 0L, NULL); return 0; } else if (warn_level & 8) { cwarn( illeg_comb, work_buf, 0L, non_eval); } } if (mcpp_debug & EXPRESSION) { if (tp->token_name) mcpp_fprintf( DBG, "sizeof -- typecode:0x%x tp->token_name:\"%s\" tp->type:0x%x\n" , typecode, tp->token_name, tp->type); } return typecode |= tp->type; /* Or in the type bit */ } VAL_SIGN * eval_num( const char * nump /* Preprocessing number */ ) /* * Evaluate number for #if lexical analysis. Note: eval_num recognizes * the unsigned suffix, but only returns a signed expr_t value, and stores * the signedness to ev.sign, which is set UNSIGNED (== unsigned) if the * value is not in the range of positive (signed) expr_t. */ { const char * const not_integer = "Not an integer \"%s\""; /* _E_ */ const char * const out_of_range = "Constant \"%s\"%.0ld%s is out of range"; /* _E_ _W1_ _W8_ */ expr_t value; uexpr_t v, v1; /* unsigned long long or unsigned long */ int uflag = FALSE; int lflag = FALSE; int erange = FALSE; int base; int c, c1; const char * cp = nump; #if HAVE_LONG_LONG const char * const out_of_range_long = "Constant \"%s\"%.0ld%s is out of range " /* _E_ _W1_ _W2_ _W8_ */ "of (unsigned) long"; const char * const ll_suffix = "LL suffix is used in other than C99 mode \"%s\"%.0ld%s"; /* _W1_ _W2_ _W8_ */ #if COMPILER == MSC || COMPILER == BORLANDC const char * const i64_suffix = "I64 suffix is used in other than C99 mode \"%s\"%.0ld%s"; /* _W2_ _W8_ */ #endif int llflag = FALSE; int erange_long = FALSE; #endif ev.sign = SIGNED; /* Default signedness */ ev.val = 0L; /* Default value */ if ((char_type[ c = *cp++ & UCHARMAX] & DIG) == 0) /* Dot */ goto num_err; if (c != '0') { /* Decimal */ base = 10; } else if ((c = *cp++ & UCHARMAX) == 'x' || c == 'X') { base = 16; /* Hexadecimal */ c = *cp++ & UCHARMAX; } else if (c == EOS) { /* 0 */ return & ev; } else { /* Octal or illegal */ base = 8; } v = v1 = 0L; for (;;) { c1 = c; if (isupper( c1)) c1 = tolower( c1); if (c1 >= 'a') c1 -= ('a' - 10); else c1 -= '0'; if (c1 < 0 || base <= c1) break; v1 *= base; v1 += c1; if (v1 / base < v) { /* Overflow */ if (! skip) goto range_err; else erange = TRUE; } #if HAVE_LONG_LONG if (! stdc3 && v1 > ULONGMAX) /* Overflow of long or unsigned long */ erange_long = TRUE; #endif v = v1; c = *cp++ & UCHARMAX; } value = v; while (c == 'u' || c == 'U' || c == 'l' || c == 'L') { if (c == 'u' || c == 'U') { if (uflag) goto num_err; uflag = TRUE; } else if (c == 'l' || c == 'L') { #if HAVE_LONG_LONG if (llflag) { goto num_err; } else if (lflag) { llflag = TRUE; if (! stdc3 && ((! skip && (warn_level & w_level)) || (skip && (warn_level & 8)))) cwarn( ll_suffix, nump, 0L, skip ? non_eval : NULL); } else { lflag = TRUE; } #else if (lflag) goto num_err; else lflag = TRUE; #endif } c = *cp++; } #if HAVE_LONG_LONG && (COMPILER == MSC || COMPILER == BORLANDC) if (tolower( c) == 'i') { c1 = atoi( cp); if (c1 == 64) { if (! stdc3 && ((! skip && (warn_level & w_level)) || (skip && (warn_level & 8)))) cwarn( i64_suffix, nump, 0L, skip ? non_eval : NULL); cp += 2; } else if (c1 == 32 || c1 == 16) { cp += 2; } else if (c1 == 8) { cp++; } c = *cp++; } #endif if (c != EOS) goto num_err; if (standard) { if (uflag) /* If 'U' suffixed, uexpr_t is treated as unsigned */ ev.sign = UNSIGNED; else ev.sign = (value >= 0L); #if HAVE_LONG_LONG } else { if (value > LONGMAX) erange_long = TRUE; #endif } ev.val = value; if (erange && (warn_level & 8)) cwarn( out_of_range, nump, 0L, non_eval); #if HAVE_LONG_LONG else if (erange_long && ((skip && (warn_level & 8)) || (! stdc3 && ! skip && (warn_level & w_level)))) cwarn( out_of_range_long, nump, 0L, skip ? non_eval : NULL); #endif return & ev; range_err: cerror( out_of_range, nump, 0L, NULL); ev.sign = VAL_ERROR; return & ev; num_err: cerror( not_integer, nump, 0L, NULL); ev.sign = VAL_ERROR; return & ev; } static VAL_SIGN * eval_char( char * const token ) /* * Evaluate a character constant. * This routine is never called in POST_STD mode. */ { const char * const w_out_of_range = "Wide character constant %s%.0ld%s is out of range"; /* _E_ _W8_ */ const char * const c_out_of_range = "Integer character constant %s%.0ld%s is out of range"; /* _E_ _W8_ */ uexpr_t value; uexpr_t tmp; expr_t cl; int erange = FALSE; int wide = (*token == 'L'); int ucn8; int i; int bits, mbits, u8bits, bits_save; char * cp = token + 1; /* Character content */ #if HAVE_LONG_LONG const char * const w_out_of_range_long = "Wide character constant %s%.0ld%s is " /* _E_ _W1_ _W2_ _W8_ */ "out of range of unsigned long"; const char * const c_out_of_range_long = "Integer character constant %s%.0ld%s is " /* _E_ _W1_ _W2_ _W8_ */ "out of range of unsigned long"; int erange_long = FALSE; #endif bits = CHARBIT; u8bits = CHARBIT * 4; if (mbchar & UTF8) mbits = CHARBIT * 4; else mbits = CHARBIT * 2; if (mcpp_mode == STD && wide) { /* Wide character constant */ cp++; /* Skip 'L' */ bits = mbits; } if (char_type[ *cp & UCHARMAX] & mbchk) { cl = mb_eval( &cp); bits = mbits; } else if ((cl = eval_one( &cp, wide, mbits, (ucn8 = FALSE, &ucn8))) == -1L) { ev.sign = VAL_ERROR; return & ev; } bits_save = bits; value = cl; for (i = 0; *cp != '\'' && *cp != EOS; i++) { if (char_type[ *cp & UCHARMAX] & mbchk) { cl = mb_eval( &cp); if (cl == 0) /* Shift-out sequence of multi-byte or wide character */ continue; bits = mbits; } else { cl = eval_one( &cp, wide, mbits, (ucn8 = FALSE, &ucn8)); if (cl == -1L) { ev.sign = VAL_ERROR; return & ev; } #if OK_UCN if (ucn8 == TRUE) bits = u8bits; else bits = bits_save; #endif } tmp = value; value = (value << bits) | cl; /* Multi-char or multi-byte char */ if ((value >> bits) < tmp) { /* Overflow */ if (! skip) goto range_err; else erange = TRUE; } #if HAVE_LONG_LONG if ((mcpp_mode == STD && (! stdc3 && value > ULONGMAX)) || (! standard && value > LONGMAX)) erange_long = TRUE; #endif } ev.sign = ((expr_t) value >= 0L); ev.val = value; if (erange && skip && (warn_level & 8)) { if (wide) cwarn( w_out_of_range, token, 0L, non_eval); else cwarn( c_out_of_range, token, 0L, non_eval); #if HAVE_LONG_LONG } else if (erange_long && ((skip && (warn_level & 8)) || (! stdc3 && ! skip && (warn_level & w_level)))) { if (wide) cwarn( w_out_of_range_long, token, 0L, skip ? non_eval : NULL); else cwarn( c_out_of_range_long, token, 0L, skip ? non_eval : NULL); #endif } if (i == 0) /* Constant of single (character or wide-character) */ return & ev; if ((! skip && (warn_level & 4)) || (skip && (warn_level & 8))) { if (mcpp_mode == STD && wide) cwarn( "Multi-character wide character constant %s%.0ld%s isn't portable" /* _W4_ _W8_ */ , token, 0L, skip ? non_eval : NULL); else cwarn( "Multi-character or multi-byte character constant %s%.0ld%s isn't portable" /* _W4_ _W8_ */ , token, 0L, skip ? non_eval : NULL); } return & ev; range_err: if (wide) cerror( w_out_of_range, token, 0L, NULL); else cerror( c_out_of_range, token, 0L, NULL); ev.sign = VAL_ERROR; return & ev; } static expr_t eval_one( char ** seq_pp, /* Address of pointer to sequence */ /* eval_one() advances the pointer to sequence */ int wide, /* Flag of wide-character */ int mbits, /* Number of bits of a wide-char */ int * ucn8 /* Flag of UCN-32 bits */ ) /* * Called from eval_char() above to get a single character, single multi- * byte character or wide character (with or without \ escapes). * Returns the value of the character or -1L on error. */ { #if OK_UCN const char * const ucn_malval = "UCN cannot specify the value %.0s\"%08lx\""; /* _E_ _W8_ */ #endif const char * const out_of_range = "%s%ld bits can't represent escape sequence '%s'"; /* _E_ _W8_ */ uexpr_t value; int erange = FALSE; char * seq = *seq_pp; /* Initial seq_pp for diagnostic*/ const char * cp; const char * digits; unsigned uc; unsigned uc1; int count; int bits; size_t wchar_max; uc = *(*seq_pp)++ & UCHARMAX; if (uc != '\\') /* Other than escape sequence */ return (expr_t) uc; /* escape sequence */ uc1 = uc = *(*seq_pp)++ & UCHARMAX; switch (uc) { case 'a': return '\a'; case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; case 'v': return '\v'; #if OK_UCN case 'u': case 'U': if (! stdc2) goto undefined; /* Else Universal character name */ /* Fall through */ #endif case 'x': /* '\xFF' */ if (! standard) goto undefined; digits = "0123456789abcdef"; bits = 4; uc = *(*seq_pp)++ & UCHARMAX; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': digits = "01234567"; bits = 3; break; case '\'': case '"': case '?': case '\\': return (expr_t) uc; default: goto undefined; } wchar_max = (UCHARMAX << CHARBIT) | UCHARMAX; if (mbits == CHARBIT * 4) { if (mcpp_mode == STD) wchar_max = (wchar_max << CHARBIT * 2) | wchar_max; else wchar_max = LONGMAX; } value = 0L; for (count = 0; ; ++count) { if (isupper( uc)) uc = tolower( uc); if ((cp = strchr( digits, uc)) == NULL) break; if (count >= 3 && bits == 3) break; /* Octal escape sequence at most 3 digits */ #if OK_UCN if ((count >= 4 && uc1 == 'u') || (count >= 8 && uc1 == 'U')) break; #endif value = (value << bits) | (cp - digits); #if OK_UCN if (wchar_max < value && uc1 != 'u' && uc1 != 'U') #else if (wchar_max < value) #endif { if (! skip) goto range_err; else erange = TRUE; } uc = *(*seq_pp)++ & UCHARMAX; } (*seq_pp)--; if (erange) { value &= wchar_max; goto range_err; } if (count == 0 && bits == 4) /* '\xnonsense' */ goto undefined; #if OK_UCN if (uc1 == 'u' || uc1 == 'U') { if ((count < 4 && uc1 == 'u') || (count < 8 && uc1 == 'U')) goto undefined; if ((value >= 0L && value <= 0x9FL && value != 0x24L && value != 0x40L && value != 0x60L) || (!stdc3 && value >= 0xD800L && value <= 0xDFFFL)) { if (!skip) cerror( ucn_malval, NULL, (long) value, NULL); else if (warn_level & 8) cwarn( ucn_malval, NULL, (long) value, NULL); } if (count >= 8 && uc1 == 'U') *ucn8 = TRUE; return (expr_t) value; } #endif /* OK_UCN */ if (! wide && (UCHARMAX < value)) { value &= UCHARMAX; goto range_err; } return (expr_t) value; undefined: uc1 = **seq_pp; **seq_pp = EOS; /* For diagnostic */ if ((! skip && (warn_level & 1)) || (skip && (warn_level & 8))) cwarn( "Undefined escape sequence%s %.0ld'%s'" /* _W1_ _W8_ */ , skip ? non_eval : NULL, 0L, seq); **seq_pp = uc1; *seq_pp = seq + 1; return (expr_t) '\\'; /* Returns the escape char */ range_err: uc1 = **seq_pp; **seq_pp = EOS; /* For diagnostic */ if (wide) { if (! skip) cerror( out_of_range, NULL, (long) mbits, seq); else if (warn_level & 8) cwarn( out_of_range, non_eval, (long) mbits, seq); } else { if (! skip) cerror( out_of_range, NULL, (long) CHARBIT, seq); else if (warn_level & 8) cwarn( out_of_range, non_eval, (long) CHARBIT, seq); } **seq_pp = uc1; if (! skip) return -1L; else return (expr_t) value; } static VAL_SIGN * eval_eval( VAL_SIGN * valp, int op ) /* * One or two values are popped from the value stack and do arithmetic. * The result is pushed onto the value stack. * eval_eval() returns the new pointer to the top of the value stack. */ { const char * const zero_div = "%sDivision by zero%.0ld%s"; /* _E_ _W8_ */ #if HAVE_LONG_LONG const char * const neg_format = "Negative value \"%" LL_FORM "d\" is converted to positive \"%" /* _W1_ _W8_*/ LL_FORM "u\"%%s"; #else const char * const neg_format = "Negative value \"%ld\" is converted to positive \"%lu\"%%s"; /* _W1_ _W8_*/ #endif expr_t v1, v2; int sign1, sign2; if (is_binary( op)) { v2 = (--valp)->val; sign2 = valp->sign; } else { v2 = 0L; /* Dummy */ sign2 = SIGNED; /* Dummy */ } v1 = (--valp)->val; sign1 = valp->sign; if (mcpp_debug & EXPRESSION) { mcpp_fprintf( DBG, "%s op %s", (is_binary( op)) ? "binary" : "unary" , opname[ op]); dump_val( ", v1 = ", valp); if (is_binary( op)) dump_val( ", v2 = ", valp + 1); mcpp_fputc( '\n', DBG); } if (standard && (sign1 == UNSIGNED || sign2 == UNSIGNED) && is_binary( op) && op != OP_ANA && op != OP_ORO && op != OP_SR && op != OP_SL) { if (((sign1 == SIGNED && v1 < 0L) || (sign2 == SIGNED && v2 < 0L) ) && ((! skip && (warn_level & 1)) || (skip && (warn_level & 8)))) { char negate[(((sizeof (expr_t) * 8) / 3) + 1) * 2 + 50]; expr_t v3; v3 = (sign1 == SIGNED ? v1 : v2); sprintf( negate, neg_format, v3, v3); cwarn( negate, skip ? non_eval : NULL, 0L, NULL); } valp->sign = sign1 = sign2 = UNSIGNED; } if ((op == OP_SL || op == OP_SR) && ((! skip && (warn_level & 1)) || (skip && (warn_level & 8)))) { if (v2 < 0L || v2 >= sizeof (expr_t) * CHARBIT) cwarn( "Illegal shift count %.0s\"%ld\"%s" /* _W1_ _W8_ */ , NULL, (long) v2, skip ? non_eval : NULL); #if HAVE_LONG_LONG else if (! stdc3 && v2 >= sizeof (long) * CHARBIT && ((! skip && (warn_level & w_level)) || (skip && (warn_level & 8)))) cwarn( "Shift count %.0s\"%ld\" is larger than bit count of long%s" /* _W1_ _W8_*/ , NULL, (long) v2, skip ? non_eval : NULL); #endif } if ((op == OP_DIV || op == OP_MOD) && v2 == 0L) { if (! skip) { cerror( zero_div, NULL, 0L, NULL); valp->sign = VAL_ERROR; return valp; } else { if (warn_level & 8) cwarn( zero_div, NULL, 0L, non_eval); valp->sign = sign1; valp->val = (expr_t) EXPR_MAX; return valp; } } if (! standard || sign1 == SIGNED) v1 = eval_signed( & valp, v1, v2, op); else v1 = eval_unsigned( & valp, (uexpr_t) v1, (uexpr_t) v2, op); if (valp->sign == VAL_ERROR) /* Out of range */ return valp; switch (op) { case OP_NOT: case OP_EQ: case OP_NE: case OP_LT: case OP_LE: case OP_GT: case OP_GE: case OP_ANA: case OP_ORO: valp->sign = SIGNED; break; default: valp->sign = sign1; break; } valp->val = v1; return valp; } static expr_t eval_signed( VAL_SIGN ** valpp, expr_t v1, expr_t v2, int op ) /* * Apply the argument operator to the signed data. * OP_COL is a special case. */ { const char * const illeg_op = "Bug: Illegal operator \"%s\" in eval_signed()"; /* _F_ */ const char * const not_portable = "\"%s\" of negative number isn't portable%.0ld%s"; /* _W1_ _W8_*/ const char * op_name = opname[ op]; VAL_SIGN * valp = *valpp; expr_t val; int chk; /* Flag of overflow in long long */ switch (op) { case OP_EOE: case OP_PLU: break; case OP_NEG: chk = v1 && v1 == -v1; if (chk #if HAVE_LONG_LONG || (! stdc3 && v1 && (long) v1 == (long) -v1) #endif ) overflow( op_name, valpp, chk); v1 = -v1; break; case OP_COM: v1 = ~v1; break; case OP_NOT: v1 = !v1; break; case OP_MUL: val = v1 * v2; chk = v1 && v2 && (val / v1 != v2 || val / v2 != v1); if (chk #if HAVE_LONG_LONG || (! stdc3 && v1 && v2 && ((long)val / (long)v1 != (long)v2 || (long)val / (long)v2 != (long)v1)) #endif ) overflow( op_name, valpp, chk); v1 = val; break; case OP_DIV: case OP_MOD: /* Division by 0 has been already diagnosed by eval_eval(). */ chk = -v1 == v1 && v2 == -1; if (chk /* LONG_MIN / -1 on two's complement */ #if HAVE_LONG_LONG || (! stdc3 && (long)-v1 == (long)v1 && (long)v2 == (long)-1) #endif ) overflow( op_name, valpp, chk); else if (! stdc3 && (v1 < 0L || v2 < 0L) && ((! skip && (warn_level & 1)) || (skip && (warn_level & 8)))) cwarn( not_portable, op_name, 0L, skip ? non_eval : NULL); if (op == OP_DIV) v1 /= v2; else v1 %= v2; break; case OP_ADD: val = v1 + v2; chk = (v2 > 0L && v1 > val) || (v2 < 0L && v1 < val); if (chk #if HAVE_LONG_LONG || (! stdc3 && (((long)v2 > 0L && (long)v1 > (long)val) || ((long)v2 < 0L && (long)v1 < (long)val))) #endif ) overflow( op_name, valpp, chk); v1 = val; break; case OP_SUB: val = v1 - v2; chk = (v2 > 0L && val > v1) || (v2 < 0L && val < v1); if (chk #if HAVE_LONG_LONG || (! stdc3 && (((long)v2 > 0L && (long)val > (long)v1) || ((long)v2 < 0L && (long)val < (long)v1))) #endif ) overflow( op_name, valpp, chk); v1 = val; break; case OP_SL: v1 <<= v2; break; case OP_SR: if (v1 < 0L && ((!skip && (warn_level & 1)) || (skip && (warn_level & 8)))) cwarn( not_portable, op_name, 0L, skip ? non_eval : NULL); v1 >>= v2; break; case OP_LT: v1 = (v1 < v2); break; case OP_LE: v1 = (v1 <= v2); break; case OP_GT: v1 = (v1 > v2); break; case OP_GE: v1 = (v1 >= v2); break; case OP_EQ: v1 = (v1 == v2); break; case OP_NE: v1 = (v1 != v2); break; case OP_AND: v1 &= v2; break; case OP_XOR: v1 ^= v2; break; case OP_OR: v1 |= v2; break; case OP_ANA: v1 = (v1 && v2); break; case OP_ORO: v1 = (v1 || v2); break; case OP_COL: /* * If v1 has the "true" value, v2 has the "false" value. * The top of the value stack has the test. */ v1 = (--*valpp)->val ? v1 : v2; break; default: cfatal( illeg_op, op_name, 0L, NULL); } *valpp = valp; return v1; } static expr_t eval_unsigned( VAL_SIGN ** valpp, uexpr_t v1u, uexpr_t v2u, int op ) /* * Apply the argument operator to the unsigned data. * Called from eval_eval() only in Standard mode. */ { const char * const illeg_op = "Bug: Illegal operator \"%s\" in eval_unsigned()"; /* _F_ */ const char * op_name = opname[ op]; VAL_SIGN * valp = *valpp; uexpr_t v1 = 0; int chk; /* Flag of overflow in unsigned long long */ int minus; /* Big integer converted from signed long */ minus = ! stdc3 && (v1u > ULONGMAX || v2u > ULONGMAX); switch (op) { case OP_EOE: case OP_PLU: v1 = v1u; break; case OP_NEG: v1 = -v1u; if (v1u) overflow( op_name, valpp, TRUE); break; case OP_COM: v1 = ~v1u; break; case OP_NOT: v1 = !v1u; break; case OP_MUL: v1 = v1u * v2u; chk = v1u && v2u && (v1 / v2u != v1u || v1 / v1u != v2u); if (chk #if HAVE_LONG_LONG || (! stdc3 && ! minus && v1 > ULONGMAX) #endif ) overflow( op_name, valpp, chk); break; case OP_DIV: /* Division by 0 has been already diagnosed by eval_eval(). */ v1 = v1u / v2u; break; case OP_MOD: v1 = v1u % v2u; break; case OP_ADD: v1 = v1u + v2u; chk = v1 < v1u; if (chk #if HAVE_LONG_LONG || (! stdc3 && ! minus && v1 > ULONGMAX) #endif ) overflow( op_name, valpp, chk); break; case OP_SUB: v1 = v1u - v2u; chk = v1 > v1u; if (chk #if HAVE_LONG_LONG || (! stdc3 && ! minus && v1 > ULONGMAX) #endif ) overflow( op_name, valpp, chk); break; case OP_SL: v1 = v1u << v2u; break; case OP_SR: v1 = v1u >> v2u; break; case OP_LT: v1 = (v1u < v2u); break; case OP_LE: v1 = (v1u <= v2u); break; case OP_GT: v1 = (v1u > v2u); break; case OP_GE: v1 = (v1u >= v2u); break; case OP_EQ: v1 = (v1u == v2u); break; case OP_NE: v1 = (v1u != v2u); break; case OP_AND: v1 = v1u & v2u; break; case OP_XOR: v1 = v1u ^ v2u; break; case OP_OR: v1 = v1u | v2u; break; case OP_ANA: v1 = (v1u && v2u); break; case OP_ORO: v1 = (v1u || v2u); break; case OP_COL: valp--; if (valp->val) v1 = v1u; else v1 = v2u; break; default: cfatal( illeg_op, op_name, 0L, NULL); } *valpp = valp; return v1; } static void overflow( const char * op_name, VAL_SIGN ** valpp, int ll_overflow /* Flag of overflow in long long */ ) { const char * const out_of_range = "Result of \"%s\" is out of range%.0ld%s"; /* _E_ _W1_ _W8_ */ #if HAVE_LONG_LONG if (standard && ! ll_overflow) { /* Overflow of long not in C99 mode */ if ((! skip && (warn_level & w_level)) || (skip && (warn_level & 8))) cwarn( out_of_range, op_name, 0L, " of (unsigned) long"); } else #endif if (skip) { if (warn_level & 8) cwarn( out_of_range, op_name, 0L, non_eval); /* Else don't warn */ } else if (standard && (*valpp)->sign == UNSIGNED) {/* Never overflow */ if (warn_level & 1) cwarn( out_of_range, op_name, 0L, NULL); } else { cerror( out_of_range, op_name, 0L, NULL); (*valpp)->sign = VAL_ERROR; } } static void dump_val( const char * msg, const VAL_SIGN * valp ) /* * Dump a value by internal representation. */ { #if HAVE_LONG_LONG const char * const format = "%s(%ssigned long long) 0x%016" LL_FORM "x"; #else const char * const format = "%s(%ssigned long) 0x%08lx"; #endif int sign = valp->sign; mcpp_fprintf( DBG, format, msg, sign ? "" : "un", valp->val); } static void dump_stack( const OPTAB * opstack, /* Operator stack */ const OPTAB * opp, /* Pointer into operator stack */ const VAL_SIGN * value, /* Value stack */ const VAL_SIGN * valp /* -> value vector */ ) /* * Dump stacked operators and values. */ { if (opstack < opp) mcpp_fprintf( DBG, "Index op prec skip name -- op stack at %s" , infile->bptr); while (opstack < opp) { mcpp_fprintf( DBG, " [%2d] %2d %04o %d %s\n", (int)(opp - opstack) , opp->op, opp->prec, opp->skip, opname[ opp->op]); opp--; } while (value <= --valp) { mcpp_fprintf( DBG, "value[%d].val = ", (int)(valp - value)); dump_val( "", valp); mcpp_fputc( '\n', DBG); } }