+/* 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 SYNTAX_ERROR(msgid) \
+ do { cpp_error (pfile, DL_ERROR, msgid); goto syntax_error; } while(0)
+#define SYNTAX_ERROR2(msgid, arg) \
+ 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;
+ }
+
+ 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;
+{
+ 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;