stk-code_catmod/lib/mcpp/eval.c
2020-01-03 12:46:35 +08:00

1674 lines
58 KiB
C

/*-
* Copyright (c) 1998, 2002-2008 Kiyoshi Matsui <kmatsui@t3.rim.or.jp>
* 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);
}
}