From 7057e6452ba6b205085eede49eddf37c2feab29a Mon Sep 17 00:00:00 2001 From: Edward Smith-Rowland <3dw4rd@verizon.net> Date: Thu, 31 Oct 2013 14:01:23 +0000 Subject: Implement C++14 digit separators. libcpp: 2013-10-31 Edward Smith-Rowland <3dw4rd@verizon.net> Implement C++14 digit separators. * include/cpplib.h (cpp_options): Add digit_separators flag. * internal.h (DIGIT_SEP(c)): New macro. * expr.c (cpp_classify_number): Check improper placement of digit sep; (cpp_interpret_integer): Skip over digit separators. * init.c (lang_flags): Add digit_separators flag; (lang_defaults): Add digit separator flags per language; (cpp_set_lang): Set digit_separators * lex.c (lex_number): Add digits separator to allowable characters for C++14. gcc/c-family: 2013-10-31 Edward Smith-Rowland <3dw4rd@verizon.net> Implement C++14 digit separators. * c-lex.c (interpret_float): Remove digit separators from scratch string before building real literal. gcc/testsuite: 2013-10-31 Edward Smith-Rowland <3dw4rd@verizon.net> Implement C++14 digit separators. * g++.dg/cpp1y/digit-sep.C: New. * g++.dg/cpp1y/digit-sep-neg.C: New. * g++.dg/cpp1y/digit-sep-cxx11-neg.C: New. libstdc++-v3: 2013-10-31 Edward Smith-Rowland <3dw4rd@verizon.net> Implement C++14 digit separators. * include/include/bits/parse_numbers.h: Change struct _Digit<_Base, '`'> to struct _Digit<_Base, '\''>. From-SVN: r204260 --- libcpp/ChangeLog | 13 ++++++++++ libcpp/expr.c | 67 +++++++++++++++++++++++++++++++++++++++++-------- libcpp/include/cpplib.h | 3 +++ libcpp/init.c | 32 ++++++++++++----------- libcpp/internal.h | 2 ++ libcpp/lex.c | 3 ++- 6 files changed, 93 insertions(+), 27 deletions(-) (limited to 'libcpp') diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index b4de4f5..2e98e34 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,16 @@ +2013-10-31 Edward Smith-Rowland <3dw4rd@verizon.net> + + Implement C++14 digit separators. + * include/cpplib.h (cpp_options): Add digit_separators flag. + * internal.h (DIGIT_SEP(c)): New macro. + * expr.c (cpp_classify_number): Check improper placement of digit sep; + (cpp_interpret_integer): Skip over digit separators. + * init.c (lang_flags): Add digit_separators flag; (lang_defaults): Add + digit separator flags per language; (cpp_set_lang): Set + digit_separators + * lex.c (lex_number): Add digits separator to allowable characters for + C++14. + 2013-10-15 David Malcolm * Makefile.in (PICFLAG): New. diff --git a/libcpp/expr.c b/libcpp/expr.c index 0eb6c13..c009807 100644 --- a/libcpp/expr.c +++ b/libcpp/expr.c @@ -394,6 +394,7 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, unsigned int max_digit, result, radix; enum {NOT_FLOAT = 0, AFTER_POINT, AFTER_EXPON} float_flag; bool seen_digit; + bool seen_digit_sep; if (ud_suffix) *ud_suffix = NULL; @@ -408,6 +409,7 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, max_digit = 0; radix = 10; seen_digit = false; + seen_digit_sep = false; /* First, interpret the radix. */ if (*str == '0') @@ -416,16 +418,27 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, str++; /* Require at least one hex digit to classify it as hex. */ - if ((*str == 'x' || *str == 'X') - && (str[1] == '.' || ISXDIGIT (str[1]))) + if (*str == 'x' || *str == 'X') { - radix = 16; - str++; + if (str[1] == '.' || ISXDIGIT (str[1])) + { + radix = 16; + str++; + } + else if (DIGIT_SEP (str[1])) + SYNTAX_ERROR_AT (virtual_location, + "digit separator after base indicator"); } - else if ((*str == 'b' || *str == 'B') && (str[1] == '0' || str[1] == '1')) + else if (*str == 'b' || *str == 'B') { - radix = 2; - str++; + if (str[1] == '0' || str[1] == '1') + { + radix = 2; + str++; + } + else if (DIGIT_SEP (str[1])) + SYNTAX_ERROR_AT (virtual_location, + "digit separator after base indicator"); } } @@ -436,13 +449,24 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, if (ISDIGIT (c) || (ISXDIGIT (c) && radix == 16)) { + seen_digit_sep = false; seen_digit = true; c = hex_value (c); if (c > max_digit) max_digit = c; } + else if (DIGIT_SEP (c)) + { + if (seen_digit_sep) + SYNTAX_ERROR_AT (virtual_location, "adjacent digit separators"); + seen_digit_sep = true; + } else if (c == '.') { + if (seen_digit_sep || DIGIT_SEP (*str)) + SYNTAX_ERROR_AT (virtual_location, + "digit separator adjacent to decimal point"); + seen_digit_sep = false; if (float_flag == NOT_FLOAT) float_flag = AFTER_POINT; else @@ -452,6 +476,9 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, else if ((radix <= 10 && (c == 'e' || c == 'E')) || (radix == 16 && (c == 'p' || c == 'P'))) { + if (seen_digit_sep || DIGIT_SEP (*str)) + SYNTAX_ERROR_AT (virtual_location, + "digit separator adjacent to exponent"); float_flag = AFTER_EXPON; break; } @@ -463,6 +490,10 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, } } + if (seen_digit_sep && float_flag != AFTER_EXPON) + SYNTAX_ERROR_AT (virtual_location, + "digit separator outside digit sequence"); + /* The suffix may be for decimal fixed-point constants without exponent. */ if (radix != 16 && float_flag == NOT_FLOAT) { @@ -520,16 +551,28 @@ cpp_classify_number (cpp_reader *pfile, const cpp_token *token, /* Exponent is decimal, even if string is a hex float. */ if (!ISDIGIT (*str)) - SYNTAX_ERROR_AT (virtual_location, "exponent has no digits"); - + { + if (DIGIT_SEP (*str)) + SYNTAX_ERROR_AT (virtual_location, + "digit separator adjacent to exponent"); + else + SYNTAX_ERROR_AT (virtual_location, "exponent has no digits"); + } do - str++; - while (ISDIGIT (*str)); + { + seen_digit_sep = DIGIT_SEP (*str); + str++; + } + while (ISDIGIT (*str) || DIGIT_SEP (*str)); } else if (radix == 16) SYNTAX_ERROR_AT (virtual_location, "hexadecimal floating constants require an exponent"); + if (seen_digit_sep) + SYNTAX_ERROR_AT (virtual_location, + "digit separator outside digit sequence"); + result = interpret_float_suffix (pfile, str, limit - str); if (result == 0) { @@ -723,6 +766,8 @@ cpp_interpret_integer (cpp_reader *pfile, const cpp_token *token, if (ISDIGIT (c) || (base == 16 && ISXDIGIT (c))) c = hex_value (c); + else if (DIGIT_SEP (c)) + continue; else break; diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 6c4225c..34ad6c3 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -437,6 +437,9 @@ struct cpp_options /* Nonzero for C++ 2014 Standard binary constants. */ unsigned char binary_constants; + /* Nonzero for C++ 2014 Standard digit separators. */ + unsigned char digit_separators; + /* Holds the name of the target (execution) character set. */ const char *narrow_charset; diff --git a/libcpp/init.c b/libcpp/init.c index 9751000..97aa6cd 100644 --- a/libcpp/init.c +++ b/libcpp/init.c @@ -84,24 +84,25 @@ struct lang_flags char rliterals; char user_literals; char binary_constants; + char digit_separators; }; static const struct lang_flags lang_defaults[] = -{ /* c99 c++ xnum xid std // digr ulit rlit udlit bin_cst */ - /* GNUC89 */ { 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0 }, - /* GNUC99 */ { 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0 }, - /* GNUC11 */ { 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0 }, - /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, - /* STDC94 */ { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0 }, - /* STDC99 */ { 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 }, - /* STDC11 */ { 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0 }, - /* GNUCXX */ { 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0 }, - /* CXX98 */ { 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0 }, - /* GNUCXX11 */ { 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0 }, - /* CXX11 */ { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0 }, - /* GNUCXX1Y */ { 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1 }, - /* CXX1Y */ { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, - /* ASM */ { 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 } +{ /* c99 c++ xnum xid std // digr ulit rlit udlit bin_cst dig_sep */ + /* GNUC89 */ { 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, + /* GNUC99 */ { 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0 }, + /* GNUC11 */ { 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0 }, + /* STDC89 */ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, + /* STDC94 */ { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 }, + /* STDC99 */ { 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, + /* STDC11 */ { 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0 }, + /* GNUCXX */ { 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, + /* CXX98 */ { 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, + /* GNUCXX11 */ { 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0 }, + /* CXX11 */ { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 }, + /* GNUCXX1Y */ { 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1 }, + /* CXX1Y */ { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* ASM */ { 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 } /* xid should be 1 for GNUC99, STDC99, GNUCXX, CXX98, GNUCXX11, CXX11, GNUCXX1Y, and CXX1Y when no longer experimental (when all uses of identifiers in the compiler have been audited for correct handling @@ -128,6 +129,7 @@ cpp_set_lang (cpp_reader *pfile, enum c_lang lang) CPP_OPTION (pfile, rliterals) = l->rliterals; CPP_OPTION (pfile, user_literals) = l->user_literals; CPP_OPTION (pfile, binary_constants) = l->binary_constants; + CPP_OPTION (pfile, digit_separators) = l->digit_separators; } /* Initialize library global state. */ diff --git a/libcpp/internal.h b/libcpp/internal.h index 1226dbd..6de44ed 100644 --- a/libcpp/internal.h +++ b/libcpp/internal.h @@ -59,6 +59,8 @@ struct cset_converter || (((prevc) == 'p' || (prevc) == 'P') \ && CPP_OPTION (pfile, extended_numbers)))) +#define DIGIT_SEP(c) ((c) == '\'' && CPP_OPTION (pfile, digit_separators)) + #define CPP_OPTION(PFILE, OPTION) ((PFILE)->opts.OPTION) #define CPP_BUFFER(PFILE) ((PFILE)->buffer) #define CPP_BUF_COLUMN(BUF, CUR) ((CUR) - (BUF)->line_base) diff --git a/libcpp/lex.c b/libcpp/lex.c index ed794d5..95995ed 100644 --- a/libcpp/lex.c +++ b/libcpp/lex.c @@ -1274,7 +1274,8 @@ lex_number (cpp_reader *pfile, cpp_string *number, cur = pfile->buffer->cur; /* N.B. ISIDNUM does not include $. */ - while (ISIDNUM (*cur) || *cur == '.' || VALID_SIGN (*cur, cur[-1])) + while (ISIDNUM (*cur) || *cur == '.' || DIGIT_SEP (*cur) + || VALID_SIGN (*cur, cur[-1])) { cur++; NORMALIZE_STATE_UPDATE_IDNUM (nst); -- cgit v1.1