/* Parse C expressions for cpplib. Copyright (C) 1987-2026 Free Software Foundation, Inc. Contributed by Per Bothner, 1994. This program is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 3, or (at your option) anylater version. This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details. You should have received a copy of the GNU General Public Licensealong with this program; see the file COPYING3. If not see<http://www.gnu.org/licenses/>. */ #include "config.h"#include "system.h"#include "cpplib.h"#include "internal.h" #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. */ location_t loc; /* The location of this value. */ enum cpp_ttype op;}; /* 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, location_t);static cpp_num num_lshift (cpp_reader *, 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 *, location_t);static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype);static unsigned int interpret_float_suffix (cpp_reader *, const uchar *, size_t);static unsigned int interpret_int_suffix (cpp_reader *, 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 ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1))#define CPP_UMINUS ((enum cpp_ttype) (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, CPP_DL_ERROR, msgid); goto syntax_error; } while(0)#define SYNTAX_ERROR2(msgid, arg) \ do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \ while(0)#define SYNTAX_ERROR_AT(loc, msgid) \ do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid); goto syntax_error; } \ while(0)#define SYNTAX_ERROR2_AT(loc, msgid, arg) \ do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, 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 (of CPP_N_* bits) describing the suffix. */static unsigned intinterpret_float_suffix (cpp_reader *pfile, const uchar *s, size_t len){ size_t orig_len = len; const uchar *orig_s = s; size_t flags; size_t f, d, l, w, q, i, fn, fnx, fn_bits, bf16; flags = 0; f = d = l = w = q = i = fn = fnx = fn_bits = bf16 = 0; /* The following decimal float suffixes, from TR 24732:2009, TS 18661-2:2015 and C23, are supported: df, DF, d32, D32 - _Decimal32. dd, DD, d64, D64 - _Decimal64. dl, DL, d128, D128 - _Decimal128. d64x, D64x - _Decimal64x. Fixed-point suffixes, from TR 18037:2008, are supported. They consist of three parts, in order: (i) An optional u or U, for unsigned types. (ii) An optional h or H, for short types, or l or L, for long types, or ll or LL, for long long types. Use of ll or LL is a GNU extension. (iii) r or R, for _Fract types, or k or K, for _Accum types. Otherwise the suffix is for a binary or standard floating-point type. Such a suffix, or the absence of a suffix, may be preceded or followed by i, I, j or J, to indicate an imaginary number with the corresponding complex type. The following suffixes for binary or standard floating-point types are supported: f, F - float (ISO C and C++). l, L - long double (ISO C and C++). d, D - double, even with the FLOAT_CONST_DECIMAL64 pragma in operation (from TR 24732:2009; the pragma and the suffix are not included in TS 18661-2:2015). w, W - machine-specific type such as __float80 (GNU extension). q, Q - machine-specific type such as __float128 (GNU extension). fN, FN - _FloatN (TS 18661-3:2015). fNx, FNx - _FloatNx (TS 18661-3:2015). bf16, BF16 - std::bfloat16_t (ISO C++23). */ /* Process decimal float suffixes, which are two letters starting with d or D. Order and case are significant. */ if (len == 2 && (*s == 'd' || *s == 'D')) { bool uppercase = (*s == 'D'); switch (s[1]) { case 'f': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break; case 'F': return (uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break; case 'd': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break; case 'D': return (uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break; case 'l': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break; case 'L': return (uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break; default: /* Additional two-character suffixes beginning with D are not for decimal float constants. */ break; } } if (CPP_OPTION (pfile, ext_numeric_literals)) { /* Recognize a fixed-point suffix. */ if (len != 0) switch (s[len-1]) { case 'k': case 'K': flags = CPP_N_ACCUM; break; case 'r': case 'R': flags = CPP_N_FRACT; break; default: break; } /* Continue processing a fixed-point suffix. The suffix is case insensitive except for ll or LL. Order is significant. */ if (flags) { if (len == 1) return flags; len--; if (*s == 'u' || *s == 'U') { flags |= CPP_N_UNSIGNED; if (len == 1) return flags; len--; s++; } switch (*s) { case 'h': case 'H': if (len == 1) return flags |= CPP_N_SMALL; break; case 'l': if (len == 1) return flags |= CPP_N_MEDIUM; if (len == 2 && s[1] == 'l') return flags |= CPP_N_LARGE; break; case 'L': if (len == 1) return flags |= CPP_N_MEDIUM; if (len == 2 && s[1] == 'L') return flags |= CPP_N_LARGE; break; default: break; } /* Anything left at this point is invalid. */ return 0; } } /* In any remaining valid suffix, the case and order don't matter. */ while (len--) { switch (s[0]) { case 'f': case 'F': f++; if (len > 0 && s[1] >= '1' && s[1] <= '9' && fn_bits == 0) { f--; while (len > 0 && s[1] >= '0' && s[1] <= '9' && fn_bits < CPP_FLOATN_MAX) { fn_bits = fn_bits * 10 + (s[1] - '0'); len--; s++; } if (len > 0 && s[1] == 'x') { fnx++; len--; s++; } else fn++; } break; case 'b': case 'B': if (len > 2 /* Except for bf16 / BF16 where case is significant. */ && s[1] == (s[0] == 'b' ? 'f' : 'F') && s[2] == '1' && s[3] == '6') { bf16++; len -= 3; s += 3; break; } return 0; case 'd': case 'D': if (!CPP_OPTION (pfile, cplusplus) && orig_s == s && len > 1) { if (s[1] == '3' && s[2] == '2' && len == 2) return CPP_N_DFLOAT | CPP_N_SMALL; if (s[1] == '6' && s[2] == '4') { if (len == 2) return CPP_N_DFLOAT | CPP_N_MEDIUM; if (len == 3 && s[3] == 'x') return CPP_N_DFLOAT | CPP_N_FLOATNX; } if (s[1] == '1' && s[2] == '2' && len == 3 && s[3] == '8') return CPP_N_DFLOAT | CPP_N_LARGE; } d++; break; case 'l': case 'L': l++; break; case 'w': case 'W': w++; break; case 'q': case 'Q': q++; break; case 'i': case 'I': case 'j': case 'J': i++; break; default: return 0; } s++; } /* Reject any case of multiple suffixes specifying types, multiple suffixes specifying an imaginary constant, _FloatN or _FloatNx suffixes for invalid values of N, and _FloatN suffixes for values of N larger than can be represented in the return value. The caller is responsible for rejecting _FloatN suffixes where _FloatN is not supported on the chosen target. */ if (f + d + l + w + q + fn + fnx + bf16 > 1 || i > 1) return 0; if (fn_bits > CPP_FLOATN_MAX) return 0; if (fnx && fn_bits != 32 && fn_bits != 64 && fn_bits != 128) return 0; if (fn && fn_bits != 16 && fn_bits % 32 != 0) return 0; if (fn && fn_bits == 96) return 0; if (i) { if (!CPP_OPTION (pfile, ext_numeric_literals)) return 0; /* In C++14 and up these suffixes are in the standard library, so treat them as user-defined literals. */ if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, lang) > CLK_CXX11 && orig_s[0] == 'i' && (orig_len == 1 || (orig_len == 2 && (orig_s[1] == 'f' || orig_s[1] == 'l')))) return 0; } if ((w || q) && !CPP_OPTION (pfile, ext_numeric_literals)) return 0; return ((i ? CPP_N_IMAGINARY : 0) | (f ? CPP_N_SMALL : d ? CPP_N_MEDIUM : l ? CPP_N_LARGE : w ? CPP_N_MD_W : q ? CPP_N_MD_Q : fn ? CPP_N_FLOATN | (fn_bits << CPP_FLOATN_SHIFT) : fnx ? CPP_N_FLOATNX | (fn_bits << CPP_FLOATN_SHIFT) : bf16 ? CPP_N_BFLOAT16 : CPP_N_DEFAULT));} /* Return the classification flags for a float suffix. */unsigned intcpp_interpret_float_suffix (cpp_reader *pfile, const char *s, size_t len){ return interpret_float_suffix (pfile, (const unsigned char *)s, len);} /* 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 intinterpret_int_suffix (cpp_reader *pfile, const uchar *s, size_t len){ size_t orig_len = len; size_t u, l, i, z, wb; u = l = i = z = wb = 0; while (len--) switch (s[len]) { case 'z': case 'Z': z++; break; 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; case 'b': if (len == 0 || s[len - 1] != 'w') return 0; wb++; len--; break; case 'B': if (len == 0 || s[len - 1] != 'W') return 0; wb++; len--; break; default: return 0; } if (l > 2 || u > 1 || i > 1 || z > 1 || wb > 1) return 0; if (z) { if (l > 0 || i > 0) return 0; if (!CPP_OPTION (pfile, cplusplus)) return 0; } if (wb) { if (CPP_OPTION (pfile, cplusplus)) return 0; if (l > 0 || i > 0 || z > 0) return 0; } if (i) { if (!CPP_OPTION (pfile, ext_numeric_literals)) return 0; /* In C++14 and up these suffixes are in the standard library, so treat them as user-defined literals. */ if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, lang) > CLK_CXX11 && s[0] == 'i' && (orig_len == 1 || (orig_len == 2 && s[1] == 'l'))) 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) | (z ? CPP_N_SIZE_T : 0) | (wb ? CPP_N_BITINT : 0));} /* Return the classification flags for an int suffix. */unsigned intcpp_interpret_int_suffix (cpp_reader *pfile, const char *s, size_t len){ return interpret_int_suffix (pfile, (const unsigned char *)s, len);} /* Return the string type corresponding to the the input user-defined string literal type. If the input type is not a user-defined string literal type return the input type. */enum cpp_ttypecpp_userdef_string_remove_type (enum cpp_ttype type){ if (type == CPP_STRING_USERDEF) return CPP_STRING; else if (type == CPP_WSTRING_USERDEF) return CPP_WSTRING; else if (type == CPP_STRING16_USERDEF) return CPP_STRING16; else if (type == CPP_STRING32_USERDEF) return CPP_STRING32; else if (type == CPP_UTF8STRING_USERDEF) return CPP_UTF8STRING; else return type;} /* Return the user-defined string literal type corresponding to the input string type. If the input type is not a string type return the input type. */enum cpp_ttypecpp_userdef_string_add_type (enum cpp_ttype type){ if (type == CPP_STRING) return CPP_STRING_USERDEF; else if (type == CPP_WSTRING) return CPP_WSTRING_USERDEF; else if (type == CPP_STRING16) return CPP_STRING16_USERDEF; else if (type == CPP_STRING32) return CPP_STRING32_USERDEF; else if (type == CPP_UTF8STRING) return CPP_UTF8STRING_USERDEF; else return type;} /* Return the char type corresponding to the the input user-defined char literal type. If the input type is not a user-defined char literal type return the input type. */enum cpp_ttypecpp_userdef_char_remove_type (enum cpp_ttype type){ if (type == CPP_CHAR_USERDEF) return CPP_CHAR; else if (type == CPP_WCHAR_USERDEF) return CPP_WCHAR; else if (type == CPP_CHAR16_USERDEF) return CPP_CHAR16; else if (type == CPP_CHAR32_USERDEF) return CPP_CHAR32; else if (type == CPP_UTF8CHAR_USERDEF) return CPP_UTF8CHAR; else return type;} /* Return the user-defined char literal type corresponding to the input char type. If the input type is not a char type return the input type. */enum cpp_ttypecpp_userdef_char_add_type (enum cpp_ttype type){ if (type == CPP_CHAR) return CPP_CHAR_USERDEF; else if (type == CPP_WCHAR) return CPP_WCHAR_USERDEF; else if (type == CPP_CHAR16) return CPP_CHAR16_USERDEF; else if (type == CPP_CHAR32) return CPP_CHAR32_USERDEF; else if (type == CPP_UTF8CHAR) return CPP_UTF8CHAR_USERDEF; elseLines 1–500 of 2423. Load more
/* Parse C expressions for cpplib. Copyright (C) 1987-2026 Free Software Foundation, Inc. Contributed by Per Bothner, 1994. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" #include "system.h" #include "cpplib.h" #include "internal.h" #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. */ location_t loc; /* The location of this value. */ enum cpp_ttype op; }; /* 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, location_t); static cpp_num num_lshift (cpp_reader *, 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 *, location_t); static struct op *reduce (cpp_reader *, struct op *, enum cpp_ttype); static unsigned int interpret_float_suffix (cpp_reader *, const uchar *, size_t); static unsigned int interpret_int_suffix (cpp_reader *, 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 ((enum cpp_ttype) (CPP_LAST_CPP_OP + 1)) #define CPP_UMINUS ((enum cpp_ttype) (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, CPP_DL_ERROR, msgid); goto syntax_error; } while(0) #define SYNTAX_ERROR2(msgid, arg) \ do { cpp_error (pfile, CPP_DL_ERROR, msgid, arg); goto syntax_error; } \ while(0) #define SYNTAX_ERROR_AT(loc, msgid) \ do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, msgid); goto syntax_error; } \ while(0) #define SYNTAX_ERROR2_AT(loc, msgid, arg) \ do { cpp_error_with_line (pfile, CPP_DL_ERROR, (loc), 0, 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 (of CPP_N_* bits) describing the suffix. */ static unsigned int interpret_float_suffix (cpp_reader *pfile, const uchar *s, size_t len) { size_t orig_len = len; const uchar *orig_s = s; size_t flags; size_t f, d, l, w, q, i, fn, fnx, fn_bits, bf16; flags = 0; f = d = l = w = q = i = fn = fnx = fn_bits = bf16 = 0; /* The following decimal float suffixes, from TR 24732:2009, TS 18661-2:2015 and C23, are supported: df, DF, d32, D32 - _Decimal32. dd, DD, d64, D64 - _Decimal64. dl, DL, d128, D128 - _Decimal128. d64x, D64x - _Decimal64x. Fixed-point suffixes, from TR 18037:2008, are supported. They consist of three parts, in order: (i) An optional u or U, for unsigned types. (ii) An optional h or H, for short types, or l or L, for long types, or ll or LL, for long long types. Use of ll or LL is a GNU extension. (iii) r or R, for _Fract types, or k or K, for _Accum types. Otherwise the suffix is for a binary or standard floating-point type. Such a suffix, or the absence of a suffix, may be preceded or followed by i, I, j or J, to indicate an imaginary number with the corresponding complex type. The following suffixes for binary or standard floating-point types are supported: f, F - float (ISO C and C++). l, L - long double (ISO C and C++). d, D - double, even with the FLOAT_CONST_DECIMAL64 pragma in operation (from TR 24732:2009; the pragma and the suffix are not included in TS 18661-2:2015). w, W - machine-specific type such as __float80 (GNU extension). q, Q - machine-specific type such as __float128 (GNU extension). fN, FN - _FloatN (TS 18661-3:2015). fNx, FNx - _FloatNx (TS 18661-3:2015). bf16, BF16 - std::bfloat16_t (ISO C++23). */ /* Process decimal float suffixes, which are two letters starting with d or D. Order and case are significant. */ if (len == 2 && (*s == 'd' || *s == 'D')) { bool uppercase = (*s == 'D'); switch (s[1]) { case 'f': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break; case 'F': return (uppercase ? (CPP_N_DFLOAT | CPP_N_SMALL) : 0); break; case 'd': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break; case 'D': return (uppercase ? (CPP_N_DFLOAT | CPP_N_MEDIUM) : 0); break; case 'l': return (!uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break; case 'L': return (uppercase ? (CPP_N_DFLOAT | CPP_N_LARGE) : 0); break; default: /* Additional two-character suffixes beginning with D are not for decimal float constants. */ break; } } if (CPP_OPTION (pfile, ext_numeric_literals)) { /* Recognize a fixed-point suffix. */ if (len != 0) switch (s[len-1]) { case 'k': case 'K': flags = CPP_N_ACCUM; break; case 'r': case 'R': flags = CPP_N_FRACT; break; default: break; } /* Continue processing a fixed-point suffix. The suffix is case insensitive except for ll or LL. Order is significant. */ if (flags) { if (len == 1) return flags; len--; if (*s == 'u' || *s == 'U') { flags |= CPP_N_UNSIGNED; if (len == 1) return flags; len--; s++; } switch (*s) { case 'h': case 'H': if (len == 1) return flags |= CPP_N_SMALL; break; case 'l': if (len == 1) return flags |= CPP_N_MEDIUM; if (len == 2 && s[1] == 'l') return flags |= CPP_N_LARGE; break; case 'L': if (len == 1) return flags |= CPP_N_MEDIUM; if (len == 2 && s[1] == 'L') return flags |= CPP_N_LARGE; break; default: break; } /* Anything left at this point is invalid. */ return 0; } } /* In any remaining valid suffix, the case and order don't matter. */ while (len--) { switch (s[0]) { case 'f': case 'F': f++; if (len > 0 && s[1] >= '1' && s[1] <= '9' && fn_bits == 0) { f--; while (len > 0 && s[1] >= '0' && s[1] <= '9' && fn_bits < CPP_FLOATN_MAX) { fn_bits = fn_bits * 10 + (s[1] - '0'); len--; s++; } if (len > 0 && s[1] == 'x') { fnx++; len--; s++; } else fn++; } break; case 'b': case 'B': if (len > 2 /* Except for bf16 / BF16 where case is significant. */ && s[1] == (s[0] == 'b' ? 'f' : 'F') && s[2] == '1' && s[3] == '6') { bf16++; len -= 3; s += 3; break; } return 0; case 'd': case 'D': if (!CPP_OPTION (pfile, cplusplus) && orig_s == s && len > 1) { if (s[1] == '3' && s[2] == '2' && len == 2) return CPP_N_DFLOAT | CPP_N_SMALL; if (s[1] == '6' && s[2] == '4') { if (len == 2) return CPP_N_DFLOAT | CPP_N_MEDIUM; if (len == 3 && s[3] == 'x') return CPP_N_DFLOAT | CPP_N_FLOATNX; } if (s[1] == '1' && s[2] == '2' && len == 3 && s[3] == '8') return CPP_N_DFLOAT | CPP_N_LARGE; } d++; break; case 'l': case 'L': l++; break; case 'w': case 'W': w++; break; case 'q': case 'Q': q++; break; case 'i': case 'I': case 'j': case 'J': i++; break; default: return 0; } s++; } /* Reject any case of multiple suffixes specifying types, multiple suffixes specifying an imaginary constant, _FloatN or _FloatNx suffixes for invalid values of N, and _FloatN suffixes for values of N larger than can be represented in the return value. The caller is responsible for rejecting _FloatN suffixes where _FloatN is not supported on the chosen target. */ if (f + d + l + w + q + fn + fnx + bf16 > 1 || i > 1) return 0; if (fn_bits > CPP_FLOATN_MAX) return 0; if (fnx && fn_bits != 32 && fn_bits != 64 && fn_bits != 128) return 0; if (fn && fn_bits != 16 && fn_bits % 32 != 0) return 0; if (fn && fn_bits == 96) return 0; if (i) { if (!CPP_OPTION (pfile, ext_numeric_literals)) return 0; /* In C++14 and up these suffixes are in the standard library, so treat them as user-defined literals. */ if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, lang) > CLK_CXX11 && orig_s[0] == 'i' && (orig_len == 1 || (orig_len == 2 && (orig_s[1] == 'f' || orig_s[1] == 'l')))) return 0; } if ((w || q) && !CPP_OPTION (pfile, ext_numeric_literals)) return 0; return ((i ? CPP_N_IMAGINARY : 0) | (f ? CPP_N_SMALL : d ? CPP_N_MEDIUM : l ? CPP_N_LARGE : w ? CPP_N_MD_W : q ? CPP_N_MD_Q : fn ? CPP_N_FLOATN | (fn_bits << CPP_FLOATN_SHIFT) : fnx ? CPP_N_FLOATNX | (fn_bits << CPP_FLOATN_SHIFT) : bf16 ? CPP_N_BFLOAT16 : CPP_N_DEFAULT)); } /* Return the classification flags for a float suffix. */ unsigned int cpp_interpret_float_suffix (cpp_reader *pfile, const char *s, size_t len) { return interpret_float_suffix (pfile, (const unsigned char *)s, len); } /* 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 (cpp_reader *pfile, const uchar *s, size_t len) { size_t orig_len = len; size_t u, l, i, z, wb; u = l = i = z = wb = 0; while (len--) switch (s[len]) { case 'z': case 'Z': z++; break; 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; case 'b': if (len == 0 || s[len - 1] != 'w') return 0; wb++; len--; break; case 'B': if (len == 0 || s[len - 1] != 'W') return 0; wb++; len--; break; default: return 0; } if (l > 2 || u > 1 || i > 1 || z > 1 || wb > 1) return 0; if (z) { if (l > 0 || i > 0) return 0; if (!CPP_OPTION (pfile, cplusplus)) return 0; } if (wb) { if (CPP_OPTION (pfile, cplusplus)) return 0; if (l > 0 || i > 0 || z > 0) return 0; } if (i) { if (!CPP_OPTION (pfile, ext_numeric_literals)) return 0; /* In C++14 and up these suffixes are in the standard library, so treat them as user-defined literals. */ if (CPP_OPTION (pfile, cplusplus) && CPP_OPTION (pfile, lang) > CLK_CXX11 && s[0] == 'i' && (orig_len == 1 || (orig_len == 2 && s[1] == 'l'))) 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) | (z ? CPP_N_SIZE_T : 0) | (wb ? CPP_N_BITINT : 0)); } /* Return the classification flags for an int suffix. */ unsigned int cpp_interpret_int_suffix (cpp_reader *pfile, const char *s, size_t len) { return interpret_int_suffix (pfile, (const unsigned char *)s, len); } /* Return the string type corresponding to the the input user-defined string literal type. If the input type is not a user-defined string literal type return the input type. */ enum cpp_ttype cpp_userdef_string_remove_type (enum cpp_ttype type) { if (type == CPP_STRING_USERDEF) return CPP_STRING; else if (type == CPP_WSTRING_USERDEF) return CPP_WSTRING; else if (type == CPP_STRING16_USERDEF) return CPP_STRING16; else if (type == CPP_STRING32_USERDEF) return CPP_STRING32; else if (type == CPP_UTF8STRING_USERDEF) return CPP_UTF8STRING; else return type; } /* Return the user-defined string literal type corresponding to the input string type. If the input type is not a string type return the input type. */ enum cpp_ttype cpp_userdef_string_add_type (enum cpp_ttype type) { if (type == CPP_STRING) return CPP_STRING_USERDEF; else if (type == CPP_WSTRING) return CPP_WSTRING_USERDEF; else if (type == CPP_STRING16) return CPP_STRING16_USERDEF; else if (type == CPP_STRING32) return CPP_STRING32_USERDEF; else if (type == CPP_UTF8STRING) return CPP_UTF8STRING_USERDEF; else return type; } /* Return the char type corresponding to the the input user-defined char literal type. If the input type is not a user-defined char literal type return the input type. */ enum cpp_ttype cpp_userdef_char_remove_type (enum cpp_ttype type) { if (type == CPP_CHAR_USERDEF) return CPP_CHAR; else if (type == CPP_WCHAR_USERDEF) return CPP_WCHAR; else if (type == CPP_CHAR16_USERDEF) return CPP_CHAR16; else if (type == CPP_CHAR32_USERDEF) return CPP_CHAR32; else if (type == CPP_UTF8CHAR_USERDEF) return CPP_UTF8CHAR; else return type; } /* Return the user-defined char literal type corresponding to the input char type. If the input type is not a char type return the input type. */ enum cpp_ttype cpp_userdef_char_add_type (enum cpp_ttype type) { if (type == CPP_CHAR) return CPP_CHAR_USERDEF; else if (type == CPP_WCHAR) return CPP_WCHAR_USERDEF; else if (type == CPP_CHAR16) return CPP_CHAR16_USERDEF; else if (type == CPP_CHAR32) return CPP_CHAR32_USERDEF; else if (type == CPP_UTF8CHAR) return CPP_UTF8CHAR_USERDEF; else