X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcppexp.c;h=202b2d01a597c042ed3b6f4e893a84772e96b003;hb=df034f844ad35169ff0b9bc32ec6968b1d7d39cb;hp=bea20a22ce5d46f2e31aa7bd6e7c59ad1f374e4a;hpb=3e74fd59a8fd56073501dffa82dc26f956e7de8b;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cppexp.c b/gcc/cppexp.c index bea20a22ce5..202b2d01a59 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -1,6 +1,6 @@ /* Parse C expressions for cpplib. - Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001 - Free Software Foundation. + Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2001, + 2002 Free Software Foundation. Contributed by Per Bothner, 1994. This program is free software; you can redistribute it and/or modify it @@ -18,1050 +18,1590 @@ along with this program; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* Parse a C expression from text in a string */ - #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "cpplib.h" #include "cpphash.h" -#ifndef MAX_CHAR_TYPE_SIZE -#define MAX_CHAR_TYPE_SIZE CHAR_TYPE_SIZE -#endif - -#ifndef MAX_INT_TYPE_SIZE -#define MAX_INT_TYPE_SIZE INT_TYPE_SIZE -#endif - -#ifndef MAX_LONG_TYPE_SIZE -#define MAX_LONG_TYPE_SIZE LONG_TYPE_SIZE -#endif - -#ifndef MAX_WCHAR_TYPE_SIZE -#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE -#endif - -#define MAX_CHAR_TYPE_MASK (MAX_CHAR_TYPE_SIZE < HOST_BITS_PER_WIDEST_INT \ - ? (~(~(HOST_WIDEST_INT) 0 << MAX_CHAR_TYPE_SIZE)) \ - : ~ (HOST_WIDEST_INT) 0) - -#define MAX_WCHAR_TYPE_MASK (MAX_WCHAR_TYPE_SIZE < HOST_BITS_PER_WIDEST_INT \ - ? ~(~(HOST_WIDEST_INT) 0 << MAX_WCHAR_TYPE_SIZE) \ - : ~ (HOST_WIDEST_INT) 0) - -/* Yield nonzero if adding two numbers with A's and B's signs can yield a - number with SUM's sign, where A, B, and SUM are all C integers. */ -#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0) - -static void integer_overflow PARAMS ((cpp_reader *)); -static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, - unsigned int, - unsigned HOST_WIDEST_INT)); -static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, - unsigned int, - unsigned HOST_WIDEST_INT)); -static struct op parse_number PARAMS ((cpp_reader *, const cpp_token *)); -static struct op parse_charconst PARAMS ((cpp_reader *, const cpp_token *)); -static struct op parse_defined PARAMS ((cpp_reader *)); -static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, const U_CHAR **, - const U_CHAR *, HOST_WIDEST_INT)); -static struct op lex PARAMS ((cpp_reader *, int, cpp_token *)); -static const unsigned char *op_as_text PARAMS ((cpp_reader *, enum cpp_ttype)); +#define PART_PRECISION (sizeof (cpp_num_part) * CHAR_BIT) +#define HALF_MASK (~(cpp_num_part) 0 >> (PART_PRECISION / 2)) +#define LOW_PART(num_part) (num_part & HALF_MASK) +#define HIGH_PART(num_part) (num_part >> (PART_PRECISION / 2)) struct op { + const cpp_token *token; /* The token forming op (for diagnostics). */ + cpp_num value; /* The value logically "right" of op. */ enum cpp_ttype op; - U_CHAR prio; /* Priority of op. */ - U_CHAR flags; - U_CHAR unsignedp; /* True if value should be treated as unsigned. */ - HOST_WIDEST_INT value; /* The value logically "right" of op. */ }; -/* There is no "error" token, but we can't get comments in #if, so we can - abuse that token type. */ -#define CPP_ERROR CPP_COMMENT +/* Some simple utility routines on double integers. */ +#define num_zerop(num) ((num.low | num.high) == 0) +#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high) +static bool num_positive PARAMS ((cpp_num, size_t)); +static bool num_greater_eq PARAMS ((cpp_num, cpp_num, size_t)); +static cpp_num num_trim PARAMS ((cpp_num, size_t)); +static cpp_num num_part_mul PARAMS ((cpp_num_part, cpp_num_part)); + +static cpp_num num_unary_op PARAMS ((cpp_reader *, cpp_num, enum cpp_ttype)); +static cpp_num num_binary_op PARAMS ((cpp_reader *, cpp_num, cpp_num, + enum cpp_ttype)); +static cpp_num num_negate PARAMS ((cpp_num, size_t)); +static cpp_num num_bitwise_op PARAMS ((cpp_reader *, cpp_num, cpp_num, + enum cpp_ttype)); +static cpp_num num_inequality_op PARAMS ((cpp_reader *, cpp_num, cpp_num, + enum cpp_ttype)); +static cpp_num num_equality_op PARAMS ((cpp_reader *, cpp_num, cpp_num, + enum cpp_ttype)); +static cpp_num num_mul PARAMS ((cpp_reader *, cpp_num, cpp_num)); +static cpp_num num_div_op PARAMS ((cpp_reader *, cpp_num, cpp_num, + enum cpp_ttype)); +static cpp_num num_lshift PARAMS ((cpp_num, size_t, size_t)); +static cpp_num num_rshift PARAMS ((cpp_num, size_t, size_t)); + +static cpp_num append_digit PARAMS ((cpp_num, int, int, size_t)); +static cpp_num parse_defined PARAMS ((cpp_reader *)); +static cpp_num eval_token PARAMS ((cpp_reader *, const cpp_token *)); +static struct op *reduce PARAMS ((cpp_reader *, struct op *, enum cpp_ttype)); +static unsigned int interpret_float_suffix PARAMS ((const uchar *, size_t)); +static unsigned int interpret_int_suffix PARAMS ((const uchar *, size_t)); +static void check_promotion PARAMS ((cpp_reader *, const struct op *)); + +/* Token type abuse to create unary plus and minus operators. */ +#define CPP_UPLUS (CPP_LAST_CPP_OP + 1) +#define CPP_UMINUS (CPP_LAST_CPP_OP + 2) /* With -O2, gcc appears to produce nice code, moving the error message load and subsequent jump completely out of the main path. */ -#define CPP_ICE(msgid) \ - do { cpp_ice (pfile, msgid); goto syntax_error; } while(0) #define SYNTAX_ERROR(msgid) \ - do { cpp_error (pfile, msgid); goto syntax_error; } while(0) + do { cpp_error (pfile, DL_ERROR, msgid); goto syntax_error; } while(0) #define SYNTAX_ERROR2(msgid, arg) \ - do { cpp_error (pfile, msgid, arg); goto syntax_error; } while(0) + do { cpp_error (pfile, DL_ERROR, msgid, arg); goto syntax_error; } while(0) + +/* Subroutine of cpp_classify_number. S points to a float suffix of + length LEN, possibly zero. Returns 0 for an invalid suffix, or a + flag vector describing the suffix. */ +static unsigned int +interpret_float_suffix (s, len) + const uchar *s; + size_t len; +{ + size_t f = 0, l = 0, i = 0; + + while (len--) + switch (s[len]) + { + case 'f': case 'F': f++; break; + case 'l': case 'L': l++; break; + case 'i': case 'I': + case 'j': case 'J': i++; break; + default: + return 0; + } -/* Parse and convert an integer for #if. Accepts decimal, hex, or octal - with or without size suffixes. */ -struct suffix + if (f + l > 1 || i > 1) + return 0; + + return ((i ? CPP_N_IMAGINARY : 0) + | (f ? CPP_N_SMALL : + l ? CPP_N_LARGE : CPP_N_MEDIUM)); +} + +/* Subroutine of cpp_classify_number. S points to an integer suffix + of length LEN, possibly zero. Returns 0 for an invalid suffix, or a + flag vector describing the suffix. */ +static unsigned int +interpret_int_suffix (s, len) + const uchar *s; + size_t len; { - unsigned char s[4]; - unsigned char u; - unsigned char l; -}; + size_t u, l, i; -const struct suffix vsuf_1[] = { - { "u", 1, 0 }, { "U", 1, 0 }, - { "l", 0, 1 }, { "L", 0, 1 } -}; + u = l = i = 0; -const struct suffix vsuf_2[] = { - { "ul", 1, 1 }, { "UL", 1, 1 }, { "uL", 1, 1 }, { "Ul", 1, 1 }, - { "lu", 1, 1 }, { "LU", 1, 1 }, { "Lu", 1, 1 }, { "lU", 1, 1 }, - { "ll", 0, 2 }, { "LL", 0, 2 } -}; + while (len--) + switch (s[len]) + { + case 'u': case 'U': u++; break; + case 'i': case 'I': + case 'j': case 'J': i++; break; + case 'l': case 'L': l++; + /* If there are two Ls, they must be adjacent and the same case. */ + if (l == 2 && s[len] != s[len + 1]) + return 0; + break; + default: + return 0; + } -const struct suffix vsuf_3[] = { - { "ull", 1, 2 }, { "ULL", 1, 2 }, { "uLL", 1, 2 }, { "Ull", 1, 2 }, - { "llu", 1, 2 }, { "LLU", 1, 2 }, { "LLu", 1, 2 }, { "llU", 1, 2 } -}; -#define Nsuff(tab) (sizeof tab / sizeof (struct suffix)) + if (l > 2 || u > 1 || i > 1) + return 0; -static struct op -parse_number (pfile, tok) + return ((i ? CPP_N_IMAGINARY : 0) + | (u ? CPP_N_UNSIGNED : 0) + | ((l == 0) ? CPP_N_SMALL + : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE)); +} + +/* Categorize numeric constants according to their field (integer, + floating point, or invalid), radix (decimal, octal, hexadecimal), + and type suffixes. */ +unsigned int +cpp_classify_number (pfile, token) cpp_reader *pfile; - const cpp_token *tok; + const cpp_token *token; { - struct op op; - const U_CHAR *start = tok->val.str.text; - const U_CHAR *end = start + tok->val.str.len; - const U_CHAR *p = start; - int c = 0, i, nsuff; - unsigned HOST_WIDEST_INT n = 0, nd, MAX_over_base; - int base = 10; - int overflow = 0; - int digit, largest_digit = 0; - const struct suffix *sufftab; - - op.unsignedp = 0; - - if (p[0] == '0') + const uchar *str = token->val.str.text; + const uchar *limit; + unsigned int max_digit, result, radix; + enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag; + + /* If the lexer has done its job, length one can only be a single + digit. Fast-path this very common case. */ + if (token->val.str.len == 1) + return CPP_N_INTEGER | CPP_N_SMALL | CPP_N_DECIMAL; + + limit = str + token->val.str.len; + float_flag = NOT_FLOAT; + max_digit = 0; + radix = 10; + + /* First, interpret the radix. */ + if (*str == '0') { - if (end - start >= 3 && (p[1] == 'x' || p[1] == 'X')) + radix = 8; + str++; + + /* Require at least one hex digit to classify it as hex. */ + if ((*str == 'x' || *str == 'X') && ISXDIGIT (str[1])) { - p += 2; - base = 16; + radix = 16; + str++; + } + } + + /* Now scan for a well-formed integer or float. */ + for (;;) + { + unsigned int c = *str++; + + if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16)) + { + c = hex_value (c); + if (c > max_digit) + max_digit = c; + } + else if (c == '.') + { + if (float_flag == NOT_FLOAT) + float_flag = AFTER_POINT; + else + SYNTAX_ERROR ("too many decimal points in number"); + } + else if ((radix <= 10 && (c == 'e' || c == 'E')) + || (radix == 16 && (c == 'p' || c == 'P'))) + { + float_flag = AFTER_EXPON; + break; } else { - p += 1; - base = 8; + /* Start of suffix. */ + str--; + break; } } - /* Some buggy compilers (e.g. MPW C) seem to need both casts. */ - MAX_over_base = (((unsigned HOST_WIDEST_INT) -1) - / ((unsigned HOST_WIDEST_INT) base)); + if (float_flag != NOT_FLOAT && radix == 8) + radix = 10; + + if (max_digit >= radix) + SYNTAX_ERROR2 ("invalid digit \"%c\" in octal constant", '0' + max_digit); - for(; p < end; p++) + if (float_flag != NOT_FLOAT) { - c = *p; - - if (c >= '0' && c <= '9') - digit = c - '0'; - /* We believe that in all live character sets, a-f are - consecutive, and so are A-F. */ - else if (base == 16 && c >= 'a' && c <= 'f') - digit = c - 'a' + 10; - else if (base == 16 && c >= 'A' && c <= 'F') - digit = c - 'A' + 10; - else - break; + if (radix == 16 && CPP_PEDANTIC (pfile) && !CPP_OPTION (pfile, c99)) + cpp_error (pfile, DL_PEDWARN, + "use of C99 hexadecimal floating constant"); - if (largest_digit < digit) - largest_digit = digit; - nd = n * base + digit; - overflow |= MAX_over_base < n || nd < n; - n = nd; - } + if (float_flag == AFTER_EXPON) + { + if (*str == '+' || *str == '-') + str++; - if (p < end) - { - /* Check for a floating point constant. Note that float constants - with an exponent or suffix but no decimal point are technically - invalid (C99 6.4.4.2) but accepted elsewhere. */ - if ((c == '.' || c == 'F' || c == 'f') - || (base == 10 && (c == 'E' || c == 'e') - && p+1 < end && (p[1] == '+' || p[1] == '-')) - || (base == 16 && (c == 'P' || c == 'p') - && p+1 < end && (p[1] == '+' || p[1] == '-'))) - SYNTAX_ERROR ("floating point numbers are not valid in #if"); - - /* Determine the suffix. l means long, and u means unsigned. - See the suffix tables, above. */ - switch (end - p) + /* Exponent is decimal, even if string is a hex float. */ + if (!ISDIGIT (*str)) + SYNTAX_ERROR ("exponent has no digits"); + + do + str++; + while (ISDIGIT (*str)); + } + else if (radix == 16) + SYNTAX_ERROR ("hexadecimal floating constants require an exponent"); + + result = interpret_float_suffix (str, limit - str); + if (result == 0) { - case 1: sufftab = vsuf_1; nsuff = Nsuff(vsuf_1); break; - case 2: sufftab = vsuf_2; nsuff = Nsuff(vsuf_2); break; - case 3: sufftab = vsuf_3; nsuff = Nsuff(vsuf_3); break; - default: goto invalid_suffix; + cpp_error (pfile, DL_ERROR, + "invalid suffix \"%.*s\" on floating constant", + (int) (limit - str), str); + return CPP_N_INVALID; } - for (i = 0; i < nsuff; i++) - if (memcmp (p, sufftab[i].s, end - p) == 0) - break; - if (i == nsuff) - goto invalid_suffix; - op.unsignedp = sufftab[i].u; - - if (CPP_WTRADITIONAL (pfile) && sufftab[i].u) - cpp_warning (pfile, "traditional C rejects the `U' suffix"); - if (sufftab[i].l == 2 && CPP_OPTION (pfile, pedantic) - && ! CPP_OPTION (pfile, c99)) - cpp_pedwarn (pfile, "too many 'l' suffixes in integer constant"); + /* Traditional C didn't accept any floating suffixes. */ + if (limit != str + && CPP_WTRADITIONAL (pfile) + && ! cpp_sys_macro_p (pfile)) + cpp_error (pfile, DL_WARNING, + "traditional C rejects the \"%.*s\" suffix", + (int) (limit - str), str); + + result |= CPP_N_FLOATING; } - - if (base <= largest_digit) - cpp_pedwarn (pfile, "integer constant contains digits beyond the radix"); + else + { + result = interpret_int_suffix (str, limit - str); + if (result == 0) + { + cpp_error (pfile, DL_ERROR, + "invalid suffix \"%.*s\" on integer constant", + (int) (limit - str), str); + return CPP_N_INVALID; + } + + /* Traditional C only accepted the 'L' suffix. + Suppress warning about 'LL' with -Wno-long-long. */ + if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile)) + { + int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY)); + int large = (result & CPP_N_WIDTH) == CPP_N_LARGE; + + if (u_or_i || (large && CPP_OPTION (pfile, warn_long_long))) + cpp_error (pfile, DL_WARNING, + "traditional C rejects the \"%.*s\" suffix", + (int) (limit - str), str); + } - if (overflow) - cpp_pedwarn (pfile, "integer constant out of range"); + if ((result & CPP_N_WIDTH) == CPP_N_LARGE + && ! CPP_OPTION (pfile, c99) + && CPP_OPTION (pfile, warn_long_long)) + cpp_error (pfile, DL_PEDWARN, "use of C99 long long integer constant"); - /* If too big to be signed, consider it unsigned. */ - else if ((HOST_WIDEST_INT) n < 0 && ! op.unsignedp) - { - if (base == 10) - cpp_warning (pfile, "integer constant is so large that it is unsigned"); - op.unsignedp = 1; + result |= CPP_N_INTEGER; } - op.value = n; - op.op = CPP_INT; - return op; + if ((result & CPP_N_IMAGINARY) && CPP_PEDANTIC (pfile)) + cpp_error (pfile, DL_PEDWARN, "imaginary constants are a GCC extension"); + + if (radix == 10) + result |= CPP_N_DECIMAL; + else if (radix == 16) + result |= CPP_N_HEX; + else + result |= CPP_N_OCTAL; + + return result; - invalid_suffix: - cpp_error (pfile, "invalid suffix '%.*s' on integer constant", - (int) (end - p), p); syntax_error: - op.op = CPP_ERROR; - return op; + return CPP_N_INVALID; } -/* Parse and convert a character constant for #if. Understands backslash - escapes (\n, \031) and multibyte characters (if so configured). */ -static struct op -parse_charconst (pfile, tok) +/* cpp_interpret_integer converts an integer constant into a cpp_num, + of precision options->precision. + + We do not provide any interface for decimal->float conversion, + because the preprocessor doesn't need it and the floating point + handling in GCC proper is too ugly to speak of. */ +cpp_num +cpp_interpret_integer (pfile, token, type) cpp_reader *pfile; - const cpp_token *tok; + const cpp_token *token; + unsigned int type; { - struct op op; - HOST_WIDEST_INT result = 0; - int num_chars = 0; - int num_bits; - unsigned int width = MAX_CHAR_TYPE_SIZE; - HOST_WIDEST_INT mask = MAX_CHAR_TYPE_MASK; - int max_chars; - const U_CHAR *ptr = tok->val.str.text; - const U_CHAR *end = ptr + tok->val.str.len; - - int c = -1; - - if (tok->type == CPP_WCHAR) - width = MAX_WCHAR_TYPE_SIZE, mask = MAX_WCHAR_TYPE_MASK; - max_chars = MAX_LONG_TYPE_SIZE / width; - - while (ptr < end) + const uchar *p, *end; + cpp_num result; + + result.low = 0; + result.high = 0; + result.unsignedp = !!(type & CPP_N_UNSIGNED); + result.overflow = false; + + p = token->val.str.text; + end = p + token->val.str.len; + + /* Common case of a single digit. */ + if (token->val.str.len == 1) + result.low = p[0] - '0'; + else { - c = *ptr++; - if (c == '\'') - CPP_ICE ("unescaped ' in character constant"); - else if (c == '\\') + cpp_num_part max; + size_t precision = CPP_OPTION (pfile, precision); + unsigned int base = 10, c = 0; + bool overflow = false; + + if ((type & CPP_N_RADIX) == CPP_N_OCTAL) { - c = parse_escape (pfile, &ptr, end, mask); - if (width < HOST_BITS_PER_INT - && (unsigned int) c >= (unsigned int)(1 << width)) - cpp_pedwarn (pfile, - "escape sequence out of range for character"); + base = 8; + p++; } - - /* Merge character into result; ignore excess chars. */ - if (++num_chars <= max_chars) + else if ((type & CPP_N_RADIX) == CPP_N_HEX) { - if (width < HOST_BITS_PER_INT) - result = (result << width) | (c & ((1 << width) - 1)); + base = 16; + p += 2; + } + + /* We can add a digit to numbers strictly less than this without + needing the precision and slowness of double integers. */ + max = ~(cpp_num_part) 0; + if (precision < PART_PRECISION) + max >>= PART_PRECISION - precision; + max = (max - base + 1) / base + 1; + + for (; p < end; p++) + { + c = *p; + + if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c))) + c = hex_value (c); else - result = c; + break; + + /* Strict inequality for when max is set to zero. */ + if (result.low < max) + result.low = result.low * base + c; + else + { + result = append_digit (result, c, base, precision); + overflow |= result.overflow; + max = 0; + } } - } - if (num_chars == 0) - SYNTAX_ERROR ("empty character constant"); - else if (num_chars > max_chars) - SYNTAX_ERROR ("character constant too long"); - else if (num_chars != 1) - cpp_warning (pfile, "multi-character character constant"); - - /* If char type is signed, sign-extend the constant. */ - num_bits = num_chars * width; - - if (pfile->spec_nodes.n__CHAR_UNSIGNED__->type == NT_MACRO - || ((result >> (num_bits - 1)) & 1) == 0) - op.value = result & ((unsigned HOST_WIDEST_INT) ~0 - >> (HOST_BITS_PER_WIDEST_INT - num_bits)); - else - op.value = result | ~((unsigned HOST_WIDEST_INT) ~0 - >> (HOST_BITS_PER_WIDEST_INT - num_bits)); + if (overflow) + cpp_error (pfile, DL_PEDWARN, + "integer constant is too large for its type"); + /* If too big to be signed, consider it unsigned. Only warn for + decimal numbers. Traditional numbers were always signed (but + we still honor an explicit U suffix); but we only have + traditional semantics in directives. */ + else if (!result.unsignedp + && !(CPP_OPTION (pfile, traditional) + && pfile->state.in_directive) + && !num_positive (result, precision)) + { + if (base == 10) + cpp_error (pfile, DL_WARNING, + "integer constant is so large that it is unsigned"); + result.unsignedp = true; + } + } - /* This is always a signed type. */ - op.unsignedp = 0; - op.op = CPP_INT; - return op; + return result; +} - syntax_error: - op.op = CPP_ERROR; - return op; +/* Append DIGIT to NUM, a number of PRECISION bits being read in base + BASE. */ +static cpp_num +append_digit (num, digit, base, precision) + cpp_num num; + int digit, base; + size_t precision; +{ + cpp_num result; + unsigned int shift = 3 + (base == 16); + bool overflow; + cpp_num_part add_high, add_low; + + /* Multiply by 8 or 16. Catching this overflow here means we don't + need to worry about add_high overflowing. */ + overflow = !!(num.high >> (PART_PRECISION - shift)); + result.high = num.high << shift; + result.low = num.low << shift; + result.high |= num.low >> (PART_PRECISION - shift); + + if (base == 10) + { + add_low = num.low << 1; + add_high = (num.high << 1) + (num.low >> (PART_PRECISION - 1)); + } + else + add_high = add_low = 0; + + if (add_low + digit < add_low) + add_high++; + add_low += digit; + + if (result.low + add_low < result.low) + add_high++; + if (result.high + add_high < result.high) + overflow = true; + + result.low += add_low; + result.high += add_high; + + /* The above code catches overflow of a cpp_num type. This catches + overflow of the (possibly shorter) target precision. */ + num.low = result.low; + num.high = result.high; + result = num_trim (result, precision); + if (!num_eq (result, num)) + overflow = true; + + result.unsignedp = num.unsignedp; + result.overflow = overflow; + return result; } -static struct op +/* Handle meeting "defined" in a preprocessor expression. */ +static cpp_num parse_defined (pfile) cpp_reader *pfile; { + cpp_num result; int paren = 0; cpp_hashnode *node = 0; - cpp_token token; - struct op op; + const cpp_token *token; + cpp_context *initial_context = pfile->context; /* Don't expand macros. */ pfile->state.prevent_expansion++; - cpp_get_token (pfile, &token); - if (token.type == CPP_OPEN_PAREN) + token = cpp_get_token (pfile); + if (token->type == CPP_OPEN_PAREN) { paren = 1; - cpp_get_token (pfile, &token); + token = cpp_get_token (pfile); } - if (token.type == CPP_NAME) + if (token->type == CPP_NAME) { - node = token.val.node; - if (paren) + node = token->val.node; + if (paren && cpp_get_token (pfile)->type != CPP_CLOSE_PAREN) { - cpp_get_token (pfile, &token); - if (token.type != CPP_CLOSE_PAREN) - { - cpp_error (pfile, "missing ')' after \"defined\""); - node = 0; - } + cpp_error (pfile, DL_ERROR, "missing ')' after \"defined\""); + node = 0; } } else { - cpp_error (pfile, "operator \"defined\" requires an identifier"); - if (token.flags & NAMED_OP) + cpp_error (pfile, DL_ERROR, + "operator \"defined\" requires an identifier"); + if (token->flags & NAMED_OP) { cpp_token op; op.flags = 0; - op.type = token.type; - cpp_error (pfile, + op.type = token->type; + cpp_error (pfile, DL_ERROR, "(\"%s\" is an alternative token for \"%s\" in C++)", - cpp_token_as_text (pfile, &token), + cpp_token_as_text (pfile, token), cpp_token_as_text (pfile, &op)); } } - if (!node) - op.op = CPP_ERROR; - else + if (node) { - op.value = node->type == NT_MACRO; - op.unsignedp = 0; - op.op = CPP_INT; + if (pfile->context != initial_context) + cpp_error (pfile, DL_WARNING, + "this use of \"defined\" may not be portable"); - /* No macros? At top of file? */ - if (pfile->mi_state == MI_OUTSIDE && pfile->mi_cmacro == 0 - && pfile->mi_if_not_defined == MI_IND_NOT && pfile->mi_lexed == 1) - { - cpp_start_lookahead (pfile); - cpp_get_token (pfile, &token); - if (token.type == CPP_EOF) - pfile->mi_ind_cmacro = node; - cpp_stop_lookahead (pfile, 0); - } + _cpp_mark_macro_used (node); + + /* A possible controlling macro of the form #if !defined (). + _cpp_parse_expr checks there was no other junk on the line. */ + pfile->mi_ind_cmacro = node; } pfile->state.prevent_expansion--; - return op; -} -/* Read one token. */ + result.unsignedp = false; + result.high = 0; + result.overflow = false; + result.low = node && node->type == NT_MACRO; + return result; +} -static struct op -lex (pfile, skip_evaluation, token) +/* Convert a token into a CPP_NUMBER (an interpreted preprocessing + number or character constant, or the result of the "defined" or "#" + operators). */ +static cpp_num +eval_token (pfile, token) cpp_reader *pfile; - int skip_evaluation; - cpp_token *token; + const cpp_token *token; { - struct op op; - - cpp_get_token (pfile, token); + cpp_num result; + unsigned int temp; + int unsignedp = 0; switch (token->type) { - case CPP_INT: case CPP_NUMBER: - return parse_number (pfile, token); - - case CPP_CHAR: - case CPP_WCHAR: - return parse_charconst (pfile, token); + temp = cpp_classify_number (pfile, token); + switch (temp & CPP_N_CATEGORY) + { + case CPP_N_FLOATING: + cpp_error (pfile, DL_ERROR, + "floating constant in preprocessor expression"); + break; + case CPP_N_INTEGER: + if (!(temp & CPP_N_IMAGINARY)) + return cpp_interpret_integer (pfile, token, temp); + cpp_error (pfile, DL_ERROR, + "imaginary number in preprocessor expression"); + break; - case CPP_STRING: - case CPP_WSTRING: - SYNTAX_ERROR ("string constants are not valid in #if"); + case CPP_N_INVALID: + /* Error already issued. */ + break; + } + result.high = result.low = 0; + break; - case CPP_FLOAT: - SYNTAX_ERROR ("floating point numbers are not valid in #if"); + case CPP_WCHAR: + case CPP_CHAR: + { + cppchar_t cc = cpp_interpret_charconst (pfile, token, + &temp, &unsignedp); - case CPP_OTHER: - if (ISGRAPH (token->val.c)) - SYNTAX_ERROR2 ("invalid character '%c' in #if", token->val.c); - else - SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", token->val.c); + result.high = 0; + result.low = cc; + /* Sign-extend the result if necessary. */ + if (!unsignedp && (cppchar_signed_t) cc < 0) + { + if (PART_PRECISION > BITS_PER_CPPCHAR_T) + result.low |= ~(~(cpp_num_part) 0 + >> (PART_PRECISION - BITS_PER_CPPCHAR_T)); + result.high = ~(cpp_num_part) 0; + result = num_trim (result, CPP_OPTION (pfile, precision)); + } + } + break; case CPP_NAME: if (token->val.node == pfile->spec_nodes.n_defined) + return parse_defined (pfile); + else if (CPP_OPTION (pfile, cplusplus) + && (token->val.node == pfile->spec_nodes.n_true + || token->val.node == pfile->spec_nodes.n_false)) { - if (pfile->context->prev && CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, "\"defined\" operator appears during macro expansion"); - - return parse_defined (pfile); + result.high = 0; + result.low = (token->val.node == pfile->spec_nodes.n_true); + + /* Warn about use of true or false in #if when pedantic + and stdbool.h has not been included. */ + if (CPP_PEDANTIC (pfile) + && ! cpp_defined (pfile, DSC("__bool_true_false_are_defined"))) + cpp_error (pfile, DL_PEDWARN, + "ISO C++ does not permit \"%s\" in #if", + NODE_NAME (token->val.node)); } - /* Controlling #if expressions cannot contain identifiers (they - could become macros in the future). */ - pfile->mi_state = MI_FAILED; + else + { + result.high = 0; + result.low = 0; + if (CPP_OPTION (pfile, warn_undef) && !pfile->state.skip_eval) + cpp_error (pfile, DL_WARNING, "\"%s\" is not defined", + NODE_NAME (token->val.node)); + } + break; - op.op = CPP_INT; - op.unsignedp = 0; - op.value = 0; + default: /* CPP_HASH */ + _cpp_test_assertion (pfile, &temp); + result.high = 0; + result.low = temp; + } - if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation) - cpp_warning (pfile, "\"%s\" is not defined", token->val.node->name); + result.unsignedp = !!unsignedp; + result.overflow = false; + return result; +} + +/* Operator precedence and flags table. - return op; +After an operator is returned from the lexer, if it has priority less +than the operator on the top of the stack, we reduce the stack by one +operator and repeat the test. Since equal priorities do not reduce, +this is naturally right-associative. - case CPP_HASH: - { - int temp; - - op.op = CPP_INT; - if (_cpp_test_assertion (pfile, &temp)) - op.op = CPP_ERROR; - op.unsignedp = 0; - op.value = temp; - return op; - } +We handle left-associative operators by decrementing the priority of +just-lexed operators by one, but retaining the priority of operators +already on the stack. + +The remaining cases are '(' and ')'. We handle '(' by skipping the +reduction phase completely. ')' is given lower priority than +everything else, including '(', effectively forcing a reduction of the +parenthesized expression. If there is a matching '(', the routine +reduce() exits immediately. If the normal exit route sees a ')', then +there cannot have been a matching '(' and an error message is output. + +The parser assumes all shifted operators require a left operand unless +the flag NO_L_OPERAND is set. These semantics are automatic; any +extra semantics need to be handled with operator-specific code. */ + +/* Flags. If CHECK_PROMOTION, we warn if the effective sign of an + operand changes because of integer promotions. */ +#define NO_L_OPERAND (1 << 0) +#define LEFT_ASSOC (1 << 1) +#define CHECK_PROMOTION (1 << 2) + +/* Operator to priority map. Must be in the same order as the first + N entries of enum cpp_ttype. */ +static const struct operator +{ + uchar prio; + uchar flags; +} optab[] = +{ + /* EQ */ {0, 0}, /* Shouldn't happen. */ + /* NOT */ {16, NO_L_OPERAND}, + /* GREATER */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* LESS */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* PLUS */ {14, LEFT_ASSOC | CHECK_PROMOTION}, + /* MINUS */ {14, LEFT_ASSOC | CHECK_PROMOTION}, + /* MULT */ {15, LEFT_ASSOC | CHECK_PROMOTION}, + /* DIV */ {15, LEFT_ASSOC | CHECK_PROMOTION}, + /* MOD */ {15, LEFT_ASSOC | CHECK_PROMOTION}, + /* AND */ {9, LEFT_ASSOC | CHECK_PROMOTION}, + /* OR */ {7, LEFT_ASSOC | CHECK_PROMOTION}, + /* XOR */ {8, LEFT_ASSOC | CHECK_PROMOTION}, + /* RSHIFT */ {13, LEFT_ASSOC}, + /* LSHIFT */ {13, LEFT_ASSOC}, + + /* MIN */ {10, LEFT_ASSOC | CHECK_PROMOTION}, + /* MAX */ {10, LEFT_ASSOC | CHECK_PROMOTION}, + + /* COMPL */ {16, NO_L_OPERAND}, + /* AND_AND */ {6, LEFT_ASSOC}, + /* OR_OR */ {5, LEFT_ASSOC}, + /* QUERY */ {3, 0}, + /* COLON */ {4, LEFT_ASSOC | CHECK_PROMOTION}, + /* COMMA */ {2, LEFT_ASSOC}, + /* OPEN_PAREN */ {1, NO_L_OPERAND}, + /* CLOSE_PAREN */ {0, 0}, + /* EOF */ {0, 0}, + /* EQ_EQ */ {11, LEFT_ASSOC}, + /* NOT_EQ */ {11, LEFT_ASSOC}, + /* GREATER_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* LESS_EQ */ {12, LEFT_ASSOC | CHECK_PROMOTION}, + /* UPLUS */ {16, NO_L_OPERAND}, + /* UMINUS */ {16, NO_L_OPERAND} +}; + +/* Parse and evaluate a C expression, reading from PFILE. + Returns the truth value of the expression. + + The implementation is an operator precedence parser, i.e. a + bottom-up parser, using a stack for not-yet-reduced tokens. + + The stack base is op_stack, and the current stack pointer is 'top'. + There is a stack element for each operator (only), and the most + recently pushed operator is 'top->op'. An operand (value) is + stored in the 'value' field of the stack element of the operator + that precedes it. */ +bool +_cpp_parse_expr (pfile) + cpp_reader *pfile; +{ + struct op *top = pfile->op_stack; + unsigned int lex_count; + bool saw_leading_not, want_value = true; + + pfile->state.skip_eval = 0; + + /* Set up detection of #if ! defined(). */ + pfile->mi_ind_cmacro = 0; + saw_leading_not = false; + lex_count = 0; + + /* Lowest priority operator prevents further reductions. */ + top->op = CPP_EOF; + + for (;;) + { + struct op op; + + lex_count++; + op.token = cpp_get_token (pfile); + op.op = op.token->type; + + switch (op.op) + { + /* These tokens convert into values. */ + case CPP_NUMBER: + case CPP_CHAR: + case CPP_WCHAR: + case CPP_NAME: + case CPP_HASH: + if (!want_value) + SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", + cpp_token_as_text (pfile, op.token)); + want_value = false; + top->value = eval_token (pfile, op.token); + continue; + + case CPP_NOT: + saw_leading_not = lex_count == 1; + break; + case CPP_PLUS: + if (want_value) + op.op = CPP_UPLUS; + break; + case CPP_MINUS: + if (want_value) + op.op = CPP_UMINUS; + break; + case CPP_OTHER: + if (ISGRAPH (op.token->val.c)) + SYNTAX_ERROR2 ("invalid character '%c' in #if", op.token->val.c); + else + SYNTAX_ERROR2 ("invalid character '\\%03o' in #if", + op.token->val.c); + + default: + if ((int) op.op <= (int) CPP_EQ || (int) op.op >= (int) CPP_PLUS_EQ) + SYNTAX_ERROR2 ("token \"%s\" is not valid in preprocessor expressions", + cpp_token_as_text (pfile, op.token)); + break; + } - case CPP_NOT: - /* We don't worry about its position here. */ - pfile->mi_if_not_defined = MI_IND_NOT; - /* Fall through. */ + /* Check we have a value or operator as appropriate. */ + if (optab[op.op].flags & NO_L_OPERAND) + { + if (!want_value) + SYNTAX_ERROR2 ("missing binary operator before token \"%s\"", + cpp_token_as_text (pfile, op.token)); + } + else if (want_value) + { + /* Ordering here is subtle and intended to favor the + missing parenthesis diagnostics over alternatives. */ + if (op.op == CPP_CLOSE_PAREN) + { + if (top->op == CPP_OPEN_PAREN) + SYNTAX_ERROR ("void expression between '(' and ')'"); + } + else if (top->op == CPP_EOF) + SYNTAX_ERROR ("#if with no expression"); + if (top->op != CPP_EOF && top->op != CPP_OPEN_PAREN) + SYNTAX_ERROR2 ("operator '%s' has no right operand", + cpp_token_as_text (pfile, top->token)); + } + + top = reduce (pfile, top, op.op); + if (!top) + goto syntax_error; + + if (op.op == CPP_EOF) + break; - default: - if ((token->type > CPP_EQ && token->type < CPP_PLUS_EQ) - || token->type == CPP_EOF) + switch (op.op) { - op.op = token->type; - return op; + case CPP_CLOSE_PAREN: + continue; + case CPP_OR_OR: + if (!num_zerop (top->value)) + pfile->state.skip_eval++; + break; + case CPP_AND_AND: + case CPP_QUERY: + if (num_zerop (top->value)) + pfile->state.skip_eval++; + break; + case CPP_COLON: + if (top->op != CPP_QUERY) + SYNTAX_ERROR (" ':' without preceding '?'"); + if (!num_zerop (top[-1].value)) /* Was '?' condition true? */ + pfile->state.skip_eval++; + else + pfile->state.skip_eval--; + default: + break; } - SYNTAX_ERROR2 ("\"%s\" is not valid in #if expressions", - cpp_token_as_text (pfile, token)); + want_value = true; + + /* Check for and handle stack overflow. */ + if (++top == pfile->op_limit) + top = _cpp_expand_op_stack (pfile); + + top->op = op.op; + top->token = op.token; } - syntax_error: - op.op = CPP_ERROR; - return op; -} + /* The controlling macro expression is only valid if we called lex 3 + times: and . push_conditional () + checks that we are at top-of-file. */ + if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3)) + pfile->mi_ind_cmacro = 0; -/* Parse a C escape sequence. STRING_PTR points to a variable - containing a pointer to the string to parse. That pointer - is updated past the characters we use. The value of the - escape sequence is returned. + if (top != pfile->op_stack) + { + cpp_error (pfile, DL_ICE, "unbalanced stack in #if"); + syntax_error: + return false; /* Return false on syntax error. */ + } - If \ is followed by 000, we return 0 and leave the string pointer - after the zeros. A value of 0 does not mean end of string. */ + return !num_zerop (top->value); +} -static HOST_WIDEST_INT -parse_escape (pfile, string_ptr, limit, result_mask) +/* Reduce the operator / value stack if possible, in preparation for + pushing operator OP. Returns NULL on error, otherwise the top of + the stack. */ +static struct op * +reduce (pfile, top, op) cpp_reader *pfile; - const U_CHAR **string_ptr; - const U_CHAR *limit; - HOST_WIDEST_INT result_mask; + struct op *top; + enum cpp_ttype op; { - const U_CHAR *ptr = *string_ptr; - /* We know we have at least one following character. */ - int c = *ptr++; - switch (c) + unsigned int prio; + + if (top->op <= CPP_EQ || top->op > CPP_LAST_CPP_OP + 2) { - case 'a': c = TARGET_BELL; break; - case 'b': c = TARGET_BS; break; - case 'f': c = TARGET_FF; break; - case 'n': c = TARGET_NEWLINE; break; - case 'r': c = TARGET_CR; break; - case 't': c = TARGET_TAB; break; - case 'v': c = TARGET_VT; break; - - case 'e': case 'E': - if (CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, "non-ISO-standard escape sequence, '\\%c'", c); - c = TARGET_ESC; - break; - - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - { - unsigned int i = c - '0'; - int count = 0; - while (++count < 3) - { - if (ptr >= limit) - break; - - c = *ptr; - if (c < '0' || c > '7') - break; - ptr++; - i = (i << 3) + c - '0'; - } - if (i != (i & result_mask)) - { - i &= result_mask; - cpp_pedwarn (pfile, "octal escape sequence out of range"); - } - c = i; - break; - } + bad_op: + cpp_error (pfile, DL_ICE, "impossible operator '%u'", top->op); + return 0; + } - case 'x': - { - unsigned int i = 0, overflow = 0; - int digits_found = 0, digit; - for (;;) - { - if (ptr >= limit) - break; - c = *ptr; - if (c >= '0' && c <= '9') - digit = c - '0'; - else if (c >= 'a' && c <= 'f') - digit = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - digit = c - 'A' + 10; - else - break; - ptr++; - overflow |= i ^ (i << 4 >> 4); - i = (i << 4) + digit; - digits_found = 1; - } - if (!digits_found) - cpp_error (pfile, "\\x used with no following hex digits"); - if (overflow | (i != (i & result_mask))) - { - i &= result_mask; - cpp_pedwarn (pfile, "hex escape sequence out of range"); - } - c = i; - break; - } + if (op == CPP_OPEN_PAREN) + return top; + + /* Decrement the priority of left-associative operators to force a + reduction with operators of otherwise equal priority. */ + prio = optab[op].prio - ((optab[op].flags & LEFT_ASSOC) != 0); + while (prio < optab[top->op].prio) + { + if (CPP_OPTION (pfile, warn_num_sign_change) + && optab[top->op].flags & CHECK_PROMOTION) + check_promotion (pfile, top); + + switch (top->op) + { + case CPP_UPLUS: + case CPP_UMINUS: + case CPP_NOT: + case CPP_COMPL: + top[-1].value = num_unary_op (pfile, top->value, top->op); + break; + + case CPP_PLUS: + case CPP_MINUS: + case CPP_RSHIFT: + case CPP_LSHIFT: + case CPP_MIN: + case CPP_MAX: + case CPP_COMMA: + top[-1].value = num_binary_op (pfile, top[-1].value, + top->value, top->op); + break; + + case CPP_GREATER: + case CPP_LESS: + case CPP_GREATER_EQ: + case CPP_LESS_EQ: + top[-1].value + = num_inequality_op (pfile, top[-1].value, top->value, top->op); + break; + + case CPP_EQ_EQ: + case CPP_NOT_EQ: + top[-1].value + = num_equality_op (pfile, top[-1].value, top->value, top->op); + break; + + case CPP_AND: + case CPP_OR: + case CPP_XOR: + top[-1].value + = num_bitwise_op (pfile, top[-1].value, top->value, top->op); + break; + + case CPP_MULT: + top[-1].value = num_mul (pfile, top[-1].value, top->value); + break; + + case CPP_DIV: + case CPP_MOD: + top[-1].value = num_div_op (pfile, top[-1].value, + top->value, top->op); + break; + + case CPP_OR_OR: + top--; + if (!num_zerop (top->value)) + pfile->state.skip_eval--; + top->value.low = (!num_zerop (top->value) + || !num_zerop (top[1].value)); + top->value.high = 0; + top->value.unsignedp = false; + top->value.overflow = false; + continue; + + case CPP_AND_AND: + top--; + if (num_zerop (top->value)) + pfile->state.skip_eval--; + top->value.low = (!num_zerop (top->value) + && !num_zerop (top[1].value)); + top->value.high = 0; + top->value.unsignedp = false; + top->value.overflow = false; + continue; + + case CPP_OPEN_PAREN: + if (op != CPP_CLOSE_PAREN) + { + cpp_error (pfile, DL_ERROR, "missing ')' in expression"); + return 0; + } + top--; + top->value = top[1].value; + return top; + + case CPP_COLON: + top -= 2; + if (!num_zerop (top->value)) + { + pfile->state.skip_eval--; + top->value = top[1].value; + } + else + top->value = top[2].value; + top->value.unsignedp = (top[1].value.unsignedp + || top[2].value.unsignedp); + continue; + + case CPP_QUERY: + cpp_error (pfile, DL_ERROR, "'?' without following ':'"); + return 0; + + default: + goto bad_op; + } + + top--; + if (top->value.overflow && !pfile->state.skip_eval) + cpp_error (pfile, DL_PEDWARN, + "integer overflow in preprocessor expression"); } - *string_ptr = ptr; - return c; + + if (op == CPP_CLOSE_PAREN) + { + cpp_error (pfile, DL_ERROR, "missing '(' in expression"); + return 0; + } + + return top; } -static void -integer_overflow (pfile) +/* Returns the position of the old top of stack after expansion. */ +struct op * +_cpp_expand_op_stack (pfile) cpp_reader *pfile; { - if (CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, "integer overflow in preprocessor expression"); + size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack); + size_t new_size = old_size * 2 + 20; + + pfile->op_stack = (struct op *) xrealloc (pfile->op_stack, + new_size * sizeof (struct op)); + pfile->op_limit = pfile->op_stack + new_size; + + return pfile->op_stack + old_size; } -static HOST_WIDEST_INT -left_shift (pfile, a, unsignedp, b) +/* Emits a warning if the effective sign of either operand of OP + changes because of integer promotions. */ +static void +check_promotion (pfile, op) cpp_reader *pfile; - HOST_WIDEST_INT a; - unsigned int unsignedp; - unsigned HOST_WIDEST_INT b; + const struct op *op; { - if (b >= HOST_BITS_PER_WIDEST_INT) + if (op->value.unsignedp == op[-1].value.unsignedp) + return; + + if (op->value.unsignedp) { - if (! unsignedp && a != 0) - integer_overflow (pfile); - return 0; + if (!num_positive (op[-1].value, CPP_OPTION (pfile, precision))) + cpp_error (pfile, DL_WARNING, + "the left operand of \"%s\" changes sign when promoted", + cpp_token_as_text (pfile, op->token)); + } + else if (!num_positive (op->value, CPP_OPTION (pfile, precision))) + cpp_error (pfile, DL_WARNING, + "the right operand of \"%s\" changes sign when promoted", + cpp_token_as_text (pfile, op->token)); +} + +/* Clears the unused high order bits of the number pointed to by PNUM. */ +static cpp_num +num_trim (num, precision) + cpp_num num; + size_t precision; +{ + if (precision > PART_PRECISION) + { + precision -= PART_PRECISION; + if (precision < PART_PRECISION) + num.high &= ((cpp_num_part) 1 << precision) - 1; } - else if (unsignedp) - return (unsigned HOST_WIDEST_INT) a << b; else { - HOST_WIDEST_INT l = a << b; - if (l >> b != a) - integer_overflow (pfile); - return l; + if (precision < PART_PRECISION) + num.low &= ((cpp_num_part) 1 << precision) - 1; + num.high = 0; } + + return num; } -static HOST_WIDEST_INT -right_shift (pfile, a, unsignedp, b) - cpp_reader *pfile ATTRIBUTE_UNUSED; - HOST_WIDEST_INT a; - unsigned int unsignedp; - unsigned HOST_WIDEST_INT b; +/* True iff A (presumed signed) >= 0. */ +static bool +num_positive (num, precision) + cpp_num num; + size_t precision; { - if (b >= HOST_BITS_PER_WIDEST_INT) - return unsignedp ? 0 : a >> (HOST_BITS_PER_WIDEST_INT - 1); - else if (unsignedp) - return (unsigned HOST_WIDEST_INT) a >> b; - else - return a >> b; + if (precision > PART_PRECISION) + { + precision -= PART_PRECISION; + return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0; + } + + return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0; } - -/* Operator precedence and flags table. -After an operator is returned from the lexer, if it has priority less -than or equal to the operator on the top of the stack, we reduce the -stack by one operator and repeat the test. Since equal priorities -reduce, this is naturally left-associative. - -We handle right-associative operators by clearing the lower bit of all -left-associative operators, and setting it for right-associative ones. -After the reduction phase of a new operator, just before it is pushed -onto the stack, its RIGHT_ASSOC bit is cleared. The effect is that -during the reduction phase, the current right-associative operator has -a priority one greater than any other operator of otherwise equal -precedence that has been pushed on the top of the stack. This avoids -a reduction pass, and effectively makes the logic right-associative. +/* Sign extend a number, with PRECISION significant bits and all + others assumed clear, to fill out a cpp_num structure. */ +cpp_num +cpp_num_sign_extend (num, precision) + cpp_num num; + size_t precision; +{ + if (!num.unsignedp) + { + if (precision > PART_PRECISION) + { + precision -= PART_PRECISION; + if (precision < PART_PRECISION + && (num.high & (cpp_num_part) 1 << (precision - 1))) + num.high |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision)); + } + else if (num.low & (cpp_num_part) 1 << (precision - 1)) + { + if (precision < PART_PRECISION) + num.low |= ~(~(cpp_num_part) 0 >> (PART_PRECISION - precision)); + num.high = ~(cpp_num_part) 0; + } + } -The remaining cases are '(' and ')'. We handle '(' by skipping the -reduction phase completely. ')' is given lower priority than -everything else, including '(', effectively forcing a reduction of the -parenthesised expression. If there is no matching '(', the stack will -be reduced all the way to the beginning, exiting the parser in the -same way as the ultra-low priority end-of-expression dummy operator. -The exit code checks to see if the operator that caused it is ')', and -if so outputs an appropriate error message. - -The parser assumes all shifted operators require a right operand -unless the flag NO_R_OPERAND is set, and similarly for NO_L_OPERAND. -These semantics are automatically checked, any extra semantics need to -be handled with operator-specific code. */ - -#define FLAG_BITS 8 -#define FLAG_MASK ((1 << FLAG_BITS) - 1) -#define PRIO_SHIFT (FLAG_BITS + 1) -#define EXTRACT_PRIO(cnst) (cnst >> FLAG_BITS) -#define EXTRACT_FLAGS(cnst) (cnst & FLAG_MASK) - -/* Flags. */ -#define HAVE_VALUE (1 << 0) -#define NO_L_OPERAND (1 << 1) -#define NO_R_OPERAND (1 << 2) -#define SHORT_CIRCUIT (1 << 3) - -/* Priority and flag combinations. */ -#define RIGHT_ASSOC (1 << FLAG_BITS) -#define FORCE_REDUCE_PRIO (0 << PRIO_SHIFT) -#define CLOSE_PAREN_PRIO (1 << PRIO_SHIFT) -#define OPEN_PAREN_PRIO ((2 << PRIO_SHIFT) | NO_L_OPERAND) -#define COMMA_PRIO (3 << PRIO_SHIFT) -#define COND_PRIO ((4 << PRIO_SHIFT) | RIGHT_ASSOC | SHORT_CIRCUIT) -#define COLON_PRIO ((5 << PRIO_SHIFT) | SHORT_CIRCUIT) -#define OROR_PRIO ((6 << PRIO_SHIFT) | SHORT_CIRCUIT) -#define ANDAND_PRIO ((7 << PRIO_SHIFT) | SHORT_CIRCUIT) -#define OR_PRIO (8 << PRIO_SHIFT) -#define XOR_PRIO (9 << PRIO_SHIFT) -#define AND_PRIO (10 << PRIO_SHIFT) -#define MINMAX_PRIO (11 << PRIO_SHIFT) -#define EQUAL_PRIO (12 << PRIO_SHIFT) -#define LESS_PRIO (13 << PRIO_SHIFT) -#define SHIFT_PRIO (14 << PRIO_SHIFT) -#define PLUS_PRIO (15 << PRIO_SHIFT) -#define MUL_PRIO (16 << PRIO_SHIFT) -#define UNARY_PRIO ((17 << PRIO_SHIFT) | RIGHT_ASSOC | NO_L_OPERAND) + return num; +} -/* Operator to priority map. Must be in the same order as the first - N entries of enum cpp_ttype. */ -static const short -op_to_prio[] = +/* Returns the negative of NUM. */ +static cpp_num +num_negate (num, precision) + cpp_num num; + size_t precision; { - /* EQ */ 0, /* dummy entry - can't happen */ - /* NOT */ UNARY_PRIO, - /* GREATER */ LESS_PRIO, - /* LESS */ LESS_PRIO, - /* PLUS */ UNARY_PRIO, /* note these two can be unary */ - /* MINUS */ UNARY_PRIO, /* or binary */ - /* MULT */ MUL_PRIO, - /* DIV */ MUL_PRIO, - /* MOD */ MUL_PRIO, - /* AND */ AND_PRIO, - /* OR */ OR_PRIO, - /* XOR */ XOR_PRIO, - /* RSHIFT */ SHIFT_PRIO, - /* LSHIFT */ SHIFT_PRIO, - /* MIN */ MINMAX_PRIO, /* C++ specific */ - /* MAX */ MINMAX_PRIO, /* extensions */ - - /* COMPL */ UNARY_PRIO, - /* AND_AND */ ANDAND_PRIO, - /* OR_OR */ OROR_PRIO, - /* QUERY */ COND_PRIO, - /* COLON */ COLON_PRIO, - /* COMMA */ COMMA_PRIO, - /* OPEN_PAREN */ OPEN_PAREN_PRIO, - /* CLOSE_PAREN */ CLOSE_PAREN_PRIO, - /* EQ_EQ */ EQUAL_PRIO, - /* NOT_EQ */ EQUAL_PRIO, - /* GREATER_EQ */ LESS_PRIO, - /* LESS_EQ */ LESS_PRIO -}; + cpp_num copy; -#define COMPARE(OP) \ - top->unsignedp = 0; \ - top->value = (unsigned1 | unsigned2) \ - ? (unsigned HOST_WIDEST_INT) v1 OP (unsigned HOST_WIDEST_INT) v2 \ - : (v1 OP v2) -#define EQUALITY(OP) \ - top->value = v1 OP v2; \ - top->unsignedp = 0; -#define BITWISE(OP) \ - top->value = v1 OP v2; \ - top->unsignedp = unsigned1 | unsigned2; -#define MINMAX(OP) \ - top->value = (v1 OP v2) ? v1 : v2; \ - top->unsignedp = unsigned1 | unsigned2; -#define UNARY(OP) \ - top->value = OP v2; \ - top->unsignedp = unsigned2; \ - top->flags |= HAVE_VALUE; -#define SHIFT(PSH, MSH) \ - if (skip_evaluation) \ - break; \ - top->unsignedp = unsigned1; \ - if (v2 < 0 && ! unsigned2) \ - top->value = MSH (pfile, v1, unsigned1, -v2); \ - else \ - top->value = PSH (pfile, v1, unsigned1, v2); + copy = num; + num.high = ~num.high; + num.low = ~num.low; + if (++num.low == 0) + num.high++; + num = num_trim (num, precision); + num.overflow = (!num.unsignedp && num_eq (num, copy) && !num_zerop (num)); -/* Parse and evaluate a C expression, reading from PFILE. - Returns the truth value of the expression. */ + return num; +} -int -_cpp_parse_expr (pfile) - cpp_reader *pfile; +/* Returns true if A >= B. */ +static bool +num_greater_eq (pa, pb, precision) + cpp_num pa, pb; + size_t precision; { - /* The implementation is an operator precedence parser, i.e. a - bottom-up parser, using a stack for not-yet-reduced tokens. - - The stack base is 'stack', and the current stack pointer is 'top'. - There is a stack element for each operator (only), - and the most recently pushed operator is 'top->op'. - An operand (value) is stored in the 'value' field of the stack - element of the operator that precedes it. - In that case the 'flags' field has the HAVE_VALUE flag set. */ - -#define INIT_STACK_SIZE 20 - struct op init_stack[INIT_STACK_SIZE]; - struct op *stack = init_stack; - struct op *limit = stack + INIT_STACK_SIZE; - cpp_token token; - register struct op *top = stack + 1; - int skip_evaluation = 0; - int result; + bool unsignedp; - /* Set up detection of #if ! defined(). */ - pfile->mi_lexed = 0; - pfile->mi_if_not_defined = MI_IND_NONE; + unsignedp = pa.unsignedp || pb.unsignedp; - /* We've finished when we try to reduce this. */ - top->op = CPP_EOF; - /* Nifty way to catch missing '('. */ - top->prio = EXTRACT_PRIO(CLOSE_PAREN_PRIO); - /* Avoid missing right operand checks. */ - top->flags = NO_R_OPERAND; + if (!unsignedp) + { + /* Both numbers have signed type. If they are of different + sign, the answer is the sign of A. */ + unsignedp = num_positive (pa, precision); - for (;;) + if (unsignedp != num_positive (pb, precision)) + return unsignedp; + + /* Otherwise we can do an unsigned comparison. */ + } + + return (pa.high > pb.high) || (pa.high == pb.high && pa.low >= pb.low); +} + +/* Returns LHS OP RHS, where OP is a bit-wise operation. */ +static cpp_num +num_bitwise_op (pfile, lhs, rhs, op) + cpp_reader *pfile ATTRIBUTE_UNUSED; + cpp_num lhs, rhs; + enum cpp_ttype op; +{ + lhs.overflow = false; + lhs.unsignedp = lhs.unsignedp || rhs.unsignedp; + + /* As excess precision is zeroed, there is no need to num_trim () as + these operations cannot introduce a set bit there. */ + if (op == CPP_AND) { - unsigned int prio; - unsigned int flags; - struct op op; + lhs.low &= rhs.low; + lhs.high &= rhs.high; + } + else if (op == CPP_OR) + { + lhs.low |= rhs.low; + lhs.high |= rhs.high; + } + else + { + lhs.low ^= rhs.low; + lhs.high ^= rhs.high; + } - /* Read a token */ - op = lex (pfile, skip_evaluation, &token); - pfile->mi_lexed++; + return lhs; +} - /* If the token is an operand, push its value and get next - token. If it is an operator, get its priority and flags, and - try to reduce the expression on the stack. */ - switch (op.op) - { - case CPP_ERROR: - goto syntax_error; - push_immediate: - case CPP_INT: - /* Push a value onto the stack. */ - if (top->flags & HAVE_VALUE) - SYNTAX_ERROR ("missing binary operator"); - top->value = op.value; - top->unsignedp = op.unsignedp; - top->flags |= HAVE_VALUE; - continue; +/* Returns LHS OP RHS, where OP is an inequality. */ +static cpp_num +num_inequality_op (pfile, lhs, rhs, op) + cpp_reader *pfile; + cpp_num lhs, rhs; + enum cpp_ttype op; +{ + bool gte = num_greater_eq (lhs, rhs, CPP_OPTION (pfile, precision)); + + if (op == CPP_GREATER_EQ) + lhs.low = gte; + else if (op == CPP_LESS) + lhs.low = !gte; + else if (op == CPP_GREATER) + lhs.low = gte && !num_eq (lhs, rhs); + else /* CPP_LESS_EQ. */ + lhs.low = !gte || num_eq (lhs, rhs); + + lhs.high = 0; + lhs.overflow = false; + lhs.unsignedp = false; + return lhs; +} - case CPP_EOF: prio = FORCE_REDUCE_PRIO; break; - case CPP_PLUS: - case CPP_MINUS: prio = PLUS_PRIO; if (top->flags & HAVE_VALUE) break; - /* else unary; fall through */ - default: prio = op_to_prio[op.op]; break; - } +/* Returns LHS OP RHS, where OP is == or !=. */ +static cpp_num +num_equality_op (pfile, lhs, rhs, op) + cpp_reader *pfile ATTRIBUTE_UNUSED; + cpp_num lhs, rhs; + enum cpp_ttype op; +{ + /* Work around a 3.0.4 bug; see PR 6950. */ + bool eq = num_eq (lhs, rhs); + if (op == CPP_NOT_EQ) + eq = !eq; + lhs.low = eq; + lhs.high = 0; + lhs.overflow = false; + lhs.unsignedp = false; + return lhs; +} - /* Separate the operator's code into priority and flags. */ - flags = EXTRACT_FLAGS(prio); - prio = EXTRACT_PRIO(prio); - if (prio == EXTRACT_PRIO(OPEN_PAREN_PRIO)) - goto skip_reduction; +/* Shift NUM, of width PRECISION, right by N bits. */ +static cpp_num +num_rshift (num, precision, n) + cpp_num num; + size_t precision, n; +{ + cpp_num_part sign_mask; - /* Check for reductions. Then push the operator. */ - while (prio <= top->prio) - { - HOST_WIDEST_INT v1, v2; - unsigned int unsigned1, unsigned2; - - /* Most operators that can appear on the stack require a - right operand. Check this before trying to reduce. */ - if ((top->flags & (HAVE_VALUE | NO_R_OPERAND)) == 0) - { - if (top->op == CPP_OPEN_PAREN) - SYNTAX_ERROR ("void expression between '(' and ')'"); - else - SYNTAX_ERROR2 ("operator '%s' has no right operand", - op_as_text (pfile, top->op)); - } + if (num.unsignedp || num_positive (num, precision)) + sign_mask = 0; + else + sign_mask = ~(cpp_num_part) 0; - unsigned2 = top->unsignedp, v2 = top->value; - top--; - unsigned1 = top->unsignedp, v1 = top->value; + if (n >= precision) + num.high = num.low = sign_mask; + else + { + /* Sign-extend. */ + if (precision < PART_PRECISION) + num.high = sign_mask, num.low |= sign_mask << precision; + else if (precision < 2 * PART_PRECISION) + num.high |= sign_mask << (precision - PART_PRECISION); - /* Now set top->value = (top[1].op)(v1, v2); */ - switch (top[1].op) - { - default: - cpp_ice (pfile, "impossible operator '%s'", - op_as_text (pfile, top[1].op)); - goto syntax_error; - - case CPP_NOT: UNARY(!); break; - case CPP_COMPL: UNARY(~); break; - case CPP_LESS: COMPARE(<); break; - case CPP_GREATER: COMPARE(>); break; - case CPP_LESS_EQ: COMPARE(<=); break; - case CPP_GREATER_EQ: COMPARE(>=); break; - case CPP_EQ_EQ: EQUALITY(==); break; - case CPP_NOT_EQ: EQUALITY(!=); break; - case CPP_AND: BITWISE(&); break; - case CPP_XOR: BITWISE(^); break; - case CPP_OR: BITWISE(|); break; - case CPP_LSHIFT: SHIFT(left_shift, right_shift); break; - case CPP_RSHIFT: SHIFT(right_shift, left_shift); break; - case CPP_MIN: MINMAX(<); break; - case CPP_MAX: MINMAX(>); break; - - case CPP_PLUS: - if (!(top->flags & HAVE_VALUE)) - { - /* Can't use UNARY(+) because K+R C did not have unary - plus. Can't use UNARY() because some compilers object - to the empty argument. */ - top->value = v2; - top->unsignedp = unsigned2; - top->flags |= HAVE_VALUE; - - if (CPP_WTRADITIONAL (pfile)) - cpp_warning (pfile, - "traditional C rejects the unary plus operator"); - } - else - { - top->value = v1 + v2; - top->unsignedp = unsigned1 | unsigned2; - if (! top->unsignedp && ! skip_evaluation - && ! possible_sum_sign (v1, v2, top->value)) - integer_overflow (pfile); - } - break; - case CPP_MINUS: - if (!(top->flags & HAVE_VALUE)) - { - UNARY(-); - if (!skip_evaluation && (top->value & v2) < 0 && !unsigned2) - integer_overflow (pfile); - } - else - { /* Binary '-' */ - top->value = v1 - v2; - top->unsignedp = unsigned1 | unsigned2; - if (! top->unsignedp && ! skip_evaluation - && ! possible_sum_sign (top->value, v2, v1)) - integer_overflow (pfile); - } - break; - case CPP_MULT: - top->unsignedp = unsigned1 | unsigned2; - if (top->unsignedp) - top->value = (unsigned HOST_WIDEST_INT) v1 * v2; - else if (!skip_evaluation) - { - top->value = v1 * v2; - if (v1 && (top->value / v1 != v2 - || (top->value & v1 & v2) < 0)) - integer_overflow (pfile); - } - break; - case CPP_DIV: - case CPP_MOD: - if (skip_evaluation) - break; - if (v2 == 0) - SYNTAX_ERROR ("division by zero in #if"); - top->unsignedp = unsigned1 | unsigned2; - if (top[1].op == CPP_DIV) - { - if (top->unsignedp) - top->value = (unsigned HOST_WIDEST_INT) v1 / v2; - else - { - top->value = v1 / v2; - if ((top->value & v1 & v2) < 0) - integer_overflow (pfile); - } - } - else - { - if (top->unsignedp) - top->value = (unsigned HOST_WIDEST_INT) v1 % v2; - else - top->value = v1 % v2; - } - break; - - case CPP_OR_OR: - top->value = v1 || v2; - top->unsignedp = 0; - if (v1) skip_evaluation--; - break; - case CPP_AND_AND: - top->value = v1 && v2; - top->unsignedp = 0; - if (!v1) skip_evaluation--; - break; - case CPP_COMMA: - if (CPP_PEDANTIC (pfile)) - cpp_pedwarn (pfile, "comma operator in operand of #if"); - top->value = v2; - top->unsignedp = unsigned2; - break; - case CPP_QUERY: - SYNTAX_ERROR ("syntax error '?' without following ':'"); - case CPP_COLON: - if (top[0].op != CPP_QUERY) - SYNTAX_ERROR ("syntax error ':' without preceding '?'"); - top--; - if (top->value) skip_evaluation--; - top->value = top->value ? v1 : v2; - top->unsignedp = unsigned1 | unsigned2; - break; - case CPP_OPEN_PAREN: - if (op.op != CPP_CLOSE_PAREN) - SYNTAX_ERROR ("missing ')' in expression"); - op.value = v2; - op.unsignedp = unsigned2; - goto push_immediate; - case CPP_EOF: - /* Reducing this dummy operator indicates we've finished. */ - if (op.op == CPP_CLOSE_PAREN) - SYNTAX_ERROR ("missing '(' in expression"); - goto done; - } + if (n >= PART_PRECISION) + { + n -= PART_PRECISION; + num.low = num.high; + num.high = sign_mask; } - /* Handle short-circuit evaluations. */ - if (flags & SHORT_CIRCUIT) - switch (op.op) - { - case CPP_OR_OR: if (top->value) skip_evaluation++; break; - case CPP_AND_AND: - case CPP_QUERY: if (!top->value) skip_evaluation++; break; - case CPP_COLON: - if (top[-1].value) /* Was '?' condition true? */ - skip_evaluation++; - else - skip_evaluation--; - default: - break; - } + if (n) + { + num.low = (num.low >> n) | (num.high << (PART_PRECISION - n)); + num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n)); + } + } + + num = num_trim (num, precision); + num.overflow = false; + return num; +} - skip_reduction: - /* Check we have a left operand iff we need one. */ - if (flags & NO_L_OPERAND) +/* Shift NUM, of width PRECISION, left by N bits. */ +static cpp_num +num_lshift (num, precision, n) + cpp_num num; + size_t precision, n; +{ + if (n >= precision) + { + num.overflow = !num.unsignedp && !num_zerop (num); + num.high = num.low = 0; + } + else + { + cpp_num orig, maybe_orig; + size_t m = n; + + orig = num; + if (m >= PART_PRECISION) + { + m -= PART_PRECISION; + num.high = num.low; + num.low = 0; + } + if (m) { - if (top->flags & HAVE_VALUE) - SYNTAX_ERROR2 ("missing binary operator before '%s'", - op_as_text (pfile, top->op)); + num.high = (num.high << m) | (num.low >> (PART_PRECISION - m)); + num.low <<= m; } + num = num_trim (num, precision); + + if (num.unsignedp) + num.overflow = false; else { - if (!(top->flags & HAVE_VALUE)) - SYNTAX_ERROR2 ("operator '%s' has no left operand", - op_as_text (pfile, top->op)); + maybe_orig = num_rshift (num, precision, n); + num.overflow = !num_eq (orig, maybe_orig); } + } - /* Check for and handle stack overflow. */ - top++; - if (top == limit) + return num; +} + +/* The four unary operators: +, -, ! and ~. */ +static cpp_num +num_unary_op (pfile, num, op) + cpp_reader *pfile; + cpp_num num; + enum cpp_ttype op; +{ + switch (op) + { + case CPP_UPLUS: + if (CPP_WTRADITIONAL (pfile) && !pfile->state.skip_eval) + cpp_error (pfile, DL_WARNING, + "traditional C rejects the unary plus operator"); + num.overflow = false; + break; + + case CPP_UMINUS: + num = num_negate (num, CPP_OPTION (pfile, precision)); + break; + + case CPP_COMPL: + num.high = ~num.high; + num.low = ~num.low; + num = num_trim (num, CPP_OPTION (pfile, precision)); + num.overflow = false; + break; + + default: /* case CPP_NOT: */ + num.low = num_zerop (num); + num.high = 0; + num.overflow = false; + num.unsignedp = false; + break; + } + + return num; +} + +/* The various binary operators. */ +static cpp_num +num_binary_op (pfile, lhs, rhs, op) + cpp_reader *pfile; + cpp_num lhs, rhs; + enum cpp_ttype op; +{ + cpp_num result; + size_t precision = CPP_OPTION (pfile, precision); + bool gte; + size_t n; + + switch (op) + { + /* Shifts. */ + case CPP_LSHIFT: + case CPP_RSHIFT: + if (!rhs.unsignedp && !num_positive (rhs, precision)) { - struct op *new_stack; - int old_size = (char *) limit - (char *) stack; - int new_size = 2 * old_size; - if (stack != init_stack) - new_stack = (struct op *) xrealloc (stack, new_size); + /* A negative shift is a positive shift the other way. */ + if (op == CPP_LSHIFT) + op = CPP_RSHIFT; else - { - new_stack = (struct op *) xmalloc (new_size); - memcpy (new_stack, stack, old_size); - } - stack = new_stack; - top = (struct op *) ((char *) new_stack + old_size); - limit = (struct op *) ((char *) new_stack + new_size); + op = CPP_LSHIFT; + rhs = num_negate (rhs, precision); } - - top->flags = flags; - top->prio = prio & ~EXTRACT_PRIO(RIGHT_ASSOC); - top->op = op.op; + if (rhs.high) + n = ~0; /* Maximal. */ + else + n = rhs.low; + if (op == CPP_LSHIFT) + lhs = num_lshift (lhs, precision, n); + else + lhs = num_rshift (lhs, precision, n); + break; + + /* Min / Max. */ + case CPP_MIN: + case CPP_MAX: + { + bool unsignedp = lhs.unsignedp || rhs.unsignedp; + + gte = num_greater_eq (lhs, rhs, precision); + if (op == CPP_MIN) + gte = !gte; + if (!gte) + lhs = rhs; + lhs.unsignedp = unsignedp; + } + break; + + /* Arithmetic. */ + case CPP_MINUS: + rhs = num_negate (rhs, precision); + case CPP_PLUS: + result.low = lhs.low + rhs.low; + result.high = lhs.high + rhs.high; + if (result.low < lhs.low) + result.high++; + + result = num_trim (result, precision); + result.unsignedp = lhs.unsignedp || rhs.unsignedp; + if (result.unsignedp) + result.overflow = false; + else + { + bool lhsp = num_positive (lhs, precision); + result.overflow = (lhsp == num_positive (rhs, precision) + && lhsp != num_positive (result, precision)); + } + return result; + + /* Comma. */ + default: /* case CPP_COMMA: */ + if (CPP_PEDANTIC (pfile) && !pfile->state.skip_eval) + cpp_error (pfile, DL_PEDWARN, + "comma operator in operand of #if"); + lhs = rhs; + break; } - done: - result = (top[1].value != 0); - if (top != stack) - CPP_ICE ("unbalanced stack in #if"); - else if (!(top[1].flags & HAVE_VALUE)) + return lhs; +} + +/* Multiplies two unsigned cpp_num_parts to give a cpp_num. This + cannot overflow. */ +static cpp_num +num_part_mul (lhs, rhs) + cpp_num_part lhs, rhs; +{ + cpp_num result; + cpp_num_part middle[2], temp; + + result.low = LOW_PART (lhs) * LOW_PART (rhs); + result.high = HIGH_PART (lhs) * HIGH_PART (rhs); + + middle[0] = LOW_PART (lhs) * HIGH_PART (rhs); + middle[1] = HIGH_PART (lhs) * LOW_PART (rhs); + + temp = result.low; + result.low += LOW_PART (middle[0]) << (PART_PRECISION / 2); + if (result.low < temp) + result.high++; + + temp = result.low; + result.low += LOW_PART (middle[1]) << (PART_PRECISION / 2); + if (result.low < temp) + result.high++; + + result.high += HIGH_PART (middle[0]); + result.high += HIGH_PART (middle[1]); + result.unsignedp = 1; + + return result; +} + +/* Multiply two preprocessing numbers. */ +static cpp_num +num_mul (pfile, lhs, rhs) + cpp_reader *pfile; + cpp_num lhs, rhs; +{ + cpp_num result, temp; + bool unsignedp = lhs.unsignedp || rhs.unsignedp; + bool overflow, negate = false; + size_t precision = CPP_OPTION (pfile, precision); + + /* Prepare for unsigned multiplication. */ + if (!unsignedp) { - SYNTAX_ERROR ("#if with no expression"); - syntax_error: - result = 0; /* Return 0 on syntax error. */ + if (!num_positive (lhs, precision)) + negate = !negate, lhs = num_negate (lhs, precision); + if (!num_positive (rhs, precision)) + negate = !negate, rhs = num_negate (rhs, precision); } - /* Free dynamic stack if we allocated one. */ - if (stack != init_stack) - free (stack); + overflow = lhs.high && rhs.high; + result = num_part_mul (lhs.low, rhs.low); + + temp = num_part_mul (lhs.high, rhs.low); + result.high += temp.low; + if (temp.high) + overflow = true; + + temp = num_part_mul (lhs.low, rhs.high); + result.high += temp.low; + if (temp.high) + overflow = true; + + temp.low = result.low, temp.high = result.high; + result = num_trim (result, precision); + if (!num_eq (result, temp)) + overflow = true; + + if (negate) + result = num_negate (result, precision); + + if (unsignedp) + result.overflow = false; + else + result.overflow = overflow || (num_positive (result, precision) ^ !negate + && !num_zerop (result)); + result.unsignedp = unsignedp; + return result; } -static const unsigned char * -op_as_text (pfile, op) +/* Divide two preprocessing numbers, returning the answer or the + remainder depending upon OP. */ +static cpp_num +num_div_op (pfile, lhs, rhs, op) cpp_reader *pfile; + cpp_num lhs, rhs; enum cpp_ttype op; { - cpp_token token; + cpp_num result, sub; + cpp_num_part mask; + bool unsignedp = lhs.unsignedp || rhs.unsignedp; + bool negate = false, lhs_neg = false; + size_t i, precision = CPP_OPTION (pfile, precision); + + /* Prepare for unsigned division. */ + if (!unsignedp) + { + if (!num_positive (lhs, precision)) + negate = !negate, lhs_neg = true, lhs = num_negate (lhs, precision); + if (!num_positive (rhs, precision)) + negate = !negate, rhs = num_negate (rhs, precision); + } + + /* Find the high bit. */ + if (rhs.high) + { + i = precision - 1; + mask = (cpp_num_part) 1 << (i - PART_PRECISION); + for (; ; i--, mask >>= 1) + if (rhs.high & mask) + break; + } + else if (rhs.low) + { + if (precision > PART_PRECISION) + i = precision - PART_PRECISION - 1; + else + i = precision - 1; + mask = (cpp_num_part) 1 << i; + for (; ; i--, mask >>= 1) + if (rhs.low & mask) + break; + } + else + { + if (!pfile->state.skip_eval) + cpp_error (pfile, DL_ERROR, "division by zero in #if"); + return lhs; + } + + /* First nonzero bit of RHS is bit I. Do naive division by + shifting the RHS fully left, and subtracting from LHS if LHS is + at least as big, and then repeating but with one less shift. + This is not very efficient, but is easy to understand. */ + + rhs.unsignedp = true; + lhs.unsignedp = true; + i = precision - i - 1; + sub = num_lshift (rhs, precision, i); + + result.high = result.low = 0; + for (;;) + { + if (num_greater_eq (lhs, sub, precision)) + { + lhs = num_binary_op (pfile, lhs, sub, CPP_MINUS); + if (i >= PART_PRECISION) + result.high |= (cpp_num_part) 1 << (i - PART_PRECISION); + else + result.low |= (cpp_num_part) 1 << i; + } + if (i-- == 0) + break; + sub.low = (sub.low >> 1) | (sub.high << (PART_PRECISION - 1)); + sub.high >>= 1; + } + + /* We divide so that the remainder has the sign of the LHS. */ + if (op == CPP_DIV) + { + result.unsignedp = unsignedp; + if (unsignedp) + result.overflow = false; + else + { + if (negate) + result = num_negate (result, precision); + result.overflow = num_positive (result, precision) ^ !negate; + } + + return result; + } + + /* CPP_MOD. */ + lhs.unsignedp = unsignedp; + lhs.overflow = false; + if (lhs_neg) + lhs = num_negate (lhs, precision); - token.type = op; - token.flags = 0; - return cpp_token_as_text (pfile, &token); + return lhs; }