/* 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
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 "cpplib.h"
#include "cpphash.h"
-#include "defaults.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 (cpp_num, size_t);
+static bool num_greater_eq (cpp_num, cpp_num, size_t);
+static cpp_num num_trim (cpp_num, size_t);
+static cpp_num num_part_mul (cpp_num_part, cpp_num_part);
+
+static cpp_num num_unary_op (cpp_reader *, cpp_num, enum cpp_ttype);
+static cpp_num num_binary_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_negate (cpp_num, size_t);
+static cpp_num num_bitwise_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_inequality_op (cpp_reader *, cpp_num, cpp_num,
+ enum cpp_ttype);
+static cpp_num num_equality_op (cpp_reader *, cpp_num, cpp_num,
+ enum cpp_ttype);
+static cpp_num num_mul (cpp_reader *, cpp_num, cpp_num);
+static cpp_num num_div_op (cpp_reader *, cpp_num, cpp_num, enum cpp_ttype);
+static cpp_num num_lshift (cpp_num, size_t, size_t);
+static cpp_num num_rshift (cpp_num, size_t, size_t);
+
+static cpp_num append_digit (cpp_num, int, int, size_t);
+static cpp_num parse_defined (cpp_reader *);
+static cpp_num eval_token (cpp_reader *, const cpp_token *);
+static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype);
+static unsigned int interpret_float_suffix (const uchar *, size_t);
+static unsigned int interpret_int_suffix (const uchar *, size_t);
+static void check_promotion (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)
-/* Parse and convert an integer for #if. Accepts decimal, hex, or octal
- with or without size suffixes. */
-struct suffix
+/* 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 (const uchar *s, size_t len)
{
- unsigned char s[4];
- unsigned char u;
- unsigned char l;
-};
+ size_t f = 0, l = 0, i = 0;
-const struct suffix vsuf_1[] = {
- { "u", 1, 0 }, { "U", 1, 0 },
- { "l", 0, 1 }, { "L", 0, 1 }
-};
+ 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;
+ }
-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 }
-};
+ if (f + l > 1 || i > 1)
+ 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))
+ 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 (const uchar *s, size_t len)
+{
+ size_t u, l, i;
+
+ u = l = i = 0;
+
+ 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;
+ }
+
+ if (l > 2 || u > 1 || i > 1)
+ return 0;
+
+ return ((i ? CPP_N_IMAGINARY : 0)
+ | (u ? CPP_N_UNSIGNED : 0)
+ | ((l == 0) ? CPP_N_SMALL
+ : (l == 1) ? CPP_N_MEDIUM : CPP_N_LARGE));
+}
-static struct op
-parse_number (pfile, tok)
- cpp_reader *pfile;
- const cpp_token *tok;
+/* Categorize numeric constants according to their field (integer,
+ floating point, or invalid), radix (decimal, octal, hexadecimal),
+ and type suffixes. */
+unsigned int
+cpp_classify_number (cpp_reader *pfile, 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')
+ && (str[1] == '.' || 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 (overflow)
- cpp_pedwarn (pfile, "integer constant out of range");
+ 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 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;
+ 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");
+
+ 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_reader *pfile;
- const cpp_token *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 we don't want to
+ drag in GCC's floating point emulator. */
+cpp_num
+cpp_interpret_integer (cpp_reader *pfile, 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)
+ {
+ base = 8;
+ p++;
+ }
+ else if ((type & CPP_N_RADIX) == CPP_N_HEX)
{
- 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 = 16;
+ p += 2;
}
-
- /* Merge character into result; ignore excess chars. */
- if (++num_chars <= max_chars)
+
+ /* 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++)
{
- if (width < HOST_BITS_PER_INT)
- result = (result << width) | (c & ((1 << width) - 1));
+ c = *p;
+
+ if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c)))
+ c = hex_value (c);
+ else
+ break;
+
+ /* Strict inequality for when max is set to zero. */
+ if (result.low < max)
+ result.low = result.low * base + c;
else
- result = c;
+ {
+ 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 (cpp_num num, int digit, int 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
-parse_defined (pfile)
- cpp_reader *pfile;
+/* Handle meeting "defined" in a preprocessor expression. */
+static cpp_num
+parse_defined (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, "\"defined\" without an identifier");
-
- if (!node)
- op.op = CPP_ERROR;
- else
{
- op.value = node->type == NT_MACRO;
- op.unsignedp = 0;
- op.op = CPP_INT;
-
- /* 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_error (pfile, DL_ERROR,
+ "operator \"defined\" requires an identifier");
+ if (token->flags & NAMED_OP)
{
- 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_token op;
+
+ op.flags = 0;
+ 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, &op));
}
}
+ if (node)
+ {
+ if (pfile->context != initial_context && CPP_PEDANTIC (pfile))
+ cpp_error (pfile, DL_WARNING,
+ "this use of \"defined\" may not be portable");
+
+ _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)
- cpp_reader *pfile;
- int skip_evaluation;
- cpp_token *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 (cpp_reader *pfile, 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);
}
- /* 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;
+ }
+
+ result.unsignedp = !!unsignedp;
+ result.overflow = false;
+ return result;
+}
+\f
+/* Operator precedence and flags table.
- if (CPP_OPTION (pfile, warn_undef) && !skip_evaluation)
- cpp_warning (pfile, "\"%s\" is not defined", token->val.node->name);
+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.
- 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.
- 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;
- }
+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 (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:
- /* We don't worry about its position here. */
- pfile->mi_if_not_defined = MI_IND_NOT;
- /* Fall through. */
+ 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;
+
+ 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;
+ }
+
+ /* 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));
+ }
- default:
- if ((token->type > CPP_EQ && token->type < CPP_PLUS_EQ)
- || token->type == CPP_EOF)
+ top = reduce (pfile, top, op.op);
+ if (!top)
+ goto syntax_error;
+
+ if (op.op == CPP_EOF)
+ break;
+
+ 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: <!> <defined expression> and <EOF>. 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)
- cpp_reader *pfile;
- const U_CHAR **string_ptr;
- const U_CHAR *limit;
- HOST_WIDEST_INT 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 (cpp_reader *pfile, 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;
}
+/* Returns the position of the old top of stack after expansion. */
+struct op *
+_cpp_expand_op_stack (cpp_reader *pfile)
+{
+ size_t old_size = (size_t) (pfile->op_limit - pfile->op_stack);
+ size_t new_size = old_size * 2 + 20;
+
+ pfile->op_stack = xrealloc (pfile->op_stack, new_size * sizeof (struct op));
+ pfile->op_limit = pfile->op_stack + new_size;
+
+ return pfile->op_stack + old_size;
+}
+
+/* Emits a warning if the effective sign of either operand of OP
+ changes because of integer promotions. */
static void
-integer_overflow (pfile)
- cpp_reader *pfile;
+check_promotion (cpp_reader *pfile, const struct op *op)
{
- if (CPP_PEDANTIC (pfile))
- cpp_pedwarn (pfile, "integer overflow in preprocessor expression");
+ if (op->value.unsignedp == op[-1].value.unsignedp)
+ return;
+
+ if (op->value.unsignedp)
+ {
+ 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));
}
-static HOST_WIDEST_INT
-left_shift (pfile, a, unsignedp, b)
- cpp_reader *pfile;
- HOST_WIDEST_INT a;
- unsigned int unsignedp;
- unsigned HOST_WIDEST_INT b;
+/* Clears the unused high order bits of the number pointed to by PNUM. */
+static cpp_num
+num_trim (cpp_num num, size_t precision)
{
- if (b >= HOST_BITS_PER_WIDEST_INT)
+ if (precision > PART_PRECISION)
{
- if (! unsignedp && a != 0)
- integer_overflow (pfile);
- return 0;
+ 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 (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;
}
-\f
-/* 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 (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 (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 (cpp_num pa, cpp_num 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 (cpp_reader *pfile ATTRIBUTE_UNUSED,
+ cpp_num lhs, cpp_num 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 (cpp_reader *pfile, cpp_num lhs, cpp_num 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 (cpp_reader *pfile ATTRIBUTE_UNUSED,
+ cpp_num lhs, cpp_num 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 (cpp_num num, size_t precision, size_t 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;
+}
+
+/* Shift NUM, of width PRECISION, left by N bits. */
+static cpp_num
+num_lshift (cpp_num num, size_t precision, size_t 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;
- skip_reduction:
- /* Check we have a left operand iff we need one. */
- if (flags & NO_L_OPERAND)
+ orig = num;
+ if (m >= PART_PRECISION)
{
- if (top->flags & HAVE_VALUE)
- SYNTAX_ERROR2 ("missing binary operator before '%s'",
- op_as_text (pfile, top->op));
+ m -= PART_PRECISION;
+ num.high = num.low;
+ num.low = 0;
}
+ if (m)
+ {
+ 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 (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 (cpp_reader *pfile, cpp_num lhs, cpp_num 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 (cpp_num_part lhs, cpp_num_part 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 (cpp_reader *pfile, cpp_num lhs, cpp_num 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)
- cpp_reader *pfile;
- enum cpp_ttype op;
+/* Divide two preprocessing numbers, returning the answer or the
+ remainder depending upon OP. */
+static cpp_num
+num_div_op (cpp_reader *pfile, cpp_num lhs, cpp_num 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;
}