annotate DEPENDENCIES/generic/include/boost/wave/cpplexer/validate_universal_char.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 /*=============================================================================
Chris@16 2 Boost.Wave: A Standard compliant C++ preprocessor library
Chris@16 3
Chris@16 4 Grammar for universal character validation (see C++ standard: Annex E)
Chris@16 5
Chris@16 6 http://www.boost.org/
Chris@16 7
Chris@16 8 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
Chris@16 9 Software License, Version 1.0. (See accompanying file
Chris@16 10 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 11 =============================================================================*/
Chris@16 12 #if !defined(VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED)
Chris@16 13 #define VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED
Chris@16 14
Chris@16 15 #include <boost/assert.hpp>
Chris@16 16
Chris@16 17 #include <boost/wave/wave_config.hpp>
Chris@16 18 #include <boost/wave/util/file_position.hpp>
Chris@16 19 #include <boost/wave/cpplexer/cpplexer_exceptions.hpp>
Chris@16 20
Chris@16 21 // this must occur after all of the includes and before any code appears
Chris@16 22 #ifdef BOOST_HAS_ABI_HEADERS
Chris@16 23 #include BOOST_ABI_PREFIX
Chris@16 24 #endif
Chris@16 25
Chris@16 26 ///////////////////////////////////////////////////////////////////////////////
Chris@16 27 namespace boost {
Chris@16 28 namespace wave {
Chris@16 29 namespace cpplexer {
Chris@16 30 namespace impl {
Chris@16 31
Chris@16 32 enum universal_char_type {
Chris@16 33 universal_char_type_valid = 0,
Chris@16 34 universal_char_type_invalid = 1,
Chris@16 35 universal_char_type_base_charset = 2,
Chris@16 36 universal_char_type_not_allowed_for_identifiers = 3
Chris@16 37 };
Chris@16 38
Chris@16 39 ///////////////////////////////////////////////////////////////////////////
Chris@16 40 //
Chris@16 41 // is_range is a helper function for the classification by brute force
Chris@16 42 // below
Chris@16 43 //
Chris@16 44 ///////////////////////////////////////////////////////////////////////////
Chris@16 45 inline bool
Chris@16 46 in_range(unsigned long ch, unsigned long l, unsigned long u)
Chris@16 47 {
Chris@16 48 return (l <= ch && ch <= u);
Chris@16 49 }
Chris@16 50
Chris@16 51 ///////////////////////////////////////////////////////////////////////////////
Chris@16 52 //
Chris@16 53 // classify_universal_char
Chris@16 54 //
Chris@16 55 // This function classifies an universal character value into 4 subranges:
Chris@16 56 // universal_char_type_valid
Chris@16 57 // the universal character value is valid for identifiers
Chris@16 58 // universal_char_type_invalid
Chris@16 59 // the universal character value is not valid for its usage inside
Chris@16 60 // identifiers (see C++ Standard: 2.2.2 [lex.charset])
Chris@16 61 // universal_char_type_base_charset
Chris@16 62 // the universal character value designates a character from the base
Chris@16 63 // character set
Chris@16 64 // universal_char_type_not_allowed_for_identifiers
Chris@16 65 // the universal character value is not allowed in an identifier
Chris@16 66 //
Chris@16 67 // Implementation note:
Chris@16 68 // This classification isn't implemented very effectively here. This
Chris@16 69 // function should be rewritten with some range run matching algorithm.
Chris@16 70 //
Chris@16 71 ///////////////////////////////////////////////////////////////////////////////
Chris@16 72 inline universal_char_type
Chris@16 73 classify_universal_char (unsigned long ch)
Chris@16 74 {
Chris@16 75 // test for invalid characters
Chris@16 76 if (ch <= 0x0020 || in_range(ch, 0x007f, 0x009f))
Chris@16 77 return universal_char_type_invalid;
Chris@16 78
Chris@16 79 // test for characters in the range of the base character set
Chris@16 80 if (in_range(ch, 0x0021, 0x005f) || in_range(ch, 0x0061, 0x007e))
Chris@16 81 return universal_char_type_base_charset;
Chris@16 82
Chris@16 83 // test for additional valid character values (see C++ Standard: Annex E)
Chris@16 84 if (in_range(ch, 0x00c0, 0x00d6) || in_range(ch, 0x00d8, 0x00f6) ||
Chris@16 85 in_range(ch, 0x00f8, 0x01f5) || in_range(ch, 0x01fa, 0x0217) ||
Chris@16 86 in_range(ch, 0x0250, 0x02a8) || in_range(ch, 0x1e00, 0x1e9a) ||
Chris@16 87 in_range(ch, 0x1ea0, 0x1ef9))
Chris@16 88 {
Chris@16 89 return universal_char_type_valid; // Latin
Chris@16 90 }
Chris@16 91
Chris@16 92 if (0x0384 == ch || in_range(ch, 0x0388, 0x038a) ||
Chris@16 93 0x038c == ch || in_range(ch, 0x038e, 0x03a1) ||
Chris@16 94 in_range(ch, 0x03a3, 0x03ce) || in_range(ch, 0x03d0, 0x03d6) ||
Chris@16 95 0x03da == ch || 0x03dc == ch || 0x03de == ch || 0x03e0 == ch ||
Chris@16 96 in_range(ch, 0x03e2, 0x03f3) || in_range(ch, 0x1f00, 0x1f15) ||
Chris@16 97 in_range(ch, 0x1f18, 0x1f1d) || in_range(ch, 0x1f20, 0x1f45) ||
Chris@16 98 in_range(ch, 0x1f48, 0x1f4d) || in_range(ch, 0x1f50, 0x1f57) ||
Chris@16 99 0x1f59 == ch || 0x1f5b == ch || 0x1f5d == ch ||
Chris@16 100 in_range(ch, 0x1f5f, 0x1f7d) || in_range(ch, 0x1f80, 0x1fb4) ||
Chris@16 101 in_range(ch, 0x1fb6, 0x1fbc) || in_range(ch, 0x1fc2, 0x1fc4) ||
Chris@16 102 in_range(ch, 0x1fc6, 0x1fcc) || in_range(ch, 0x1fd0, 0x1fd3) ||
Chris@16 103 in_range(ch, 0x1fd6, 0x1fdb) || in_range(ch, 0x1fe0, 0x1fec) ||
Chris@16 104 in_range(ch, 0x1ff2, 0x1ff4) || in_range(ch, 0x1ff6, 0x1ffc))
Chris@16 105 {
Chris@16 106 return universal_char_type_valid; // Greek
Chris@16 107 }
Chris@16 108
Chris@16 109 if (in_range(ch, 0x0401, 0x040d) || in_range(ch, 0x040f, 0x044f) ||
Chris@16 110 in_range(ch, 0x0451, 0x045c) || in_range(ch, 0x045e, 0x0481) ||
Chris@16 111 in_range(ch, 0x0490, 0x04c4) || in_range(ch, 0x04c7, 0x04c8) ||
Chris@16 112 in_range(ch, 0x04cb, 0x04cc) || in_range(ch, 0x04d0, 0x04eb) ||
Chris@16 113 in_range(ch, 0x04ee, 0x04f5) || in_range(ch, 0x04f8, 0x04f9))
Chris@16 114 {
Chris@16 115 return universal_char_type_valid; // Cyrillic
Chris@16 116 }
Chris@16 117
Chris@16 118 if (in_range(ch, 0x0531, 0x0556) || in_range(ch, 0x0561, 0x0587))
Chris@16 119 return universal_char_type_valid; // Armenian
Chris@16 120
Chris@16 121 if (in_range(ch, 0x05d0, 0x05ea) || in_range(ch, 0x05f0, 0x05f4))
Chris@16 122 return universal_char_type_valid; // Hebrew
Chris@16 123
Chris@16 124 if (in_range(ch, 0x0621, 0x063a) || in_range(ch, 0x0640, 0x0652) ||
Chris@16 125 in_range(ch, 0x0670, 0x06b7) || in_range(ch, 0x06ba, 0x06be) ||
Chris@16 126 in_range(ch, 0x06c0, 0x06ce) || in_range(ch, 0x06e5, 0x06e7))
Chris@16 127 {
Chris@16 128 return universal_char_type_valid; // Arabic
Chris@16 129 }
Chris@16 130
Chris@16 131 if (in_range(ch, 0x0905, 0x0939) || in_range(ch, 0x0958, 0x0962))
Chris@16 132 return universal_char_type_valid; // Devanagari
Chris@16 133
Chris@16 134 if (in_range(ch, 0x0985, 0x098c) || in_range(ch, 0x098f, 0x0990) ||
Chris@16 135 in_range(ch, 0x0993, 0x09a8) || in_range(ch, 0x09aa, 0x09b0) ||
Chris@16 136 0x09b2 == ch || in_range(ch, 0x09b6, 0x09b9) ||
Chris@16 137 in_range(ch, 0x09dc, 0x09dd) || in_range(ch, 0x09df, 0x09e1) ||
Chris@16 138 in_range(ch, 0x09f0, 0x09f1))
Chris@16 139 {
Chris@16 140 return universal_char_type_valid; // Bengali
Chris@16 141 }
Chris@16 142
Chris@16 143 if (in_range(ch, 0x0a05, 0x0a0a) || in_range(ch, 0x0a0f, 0x0a10) ||
Chris@16 144 in_range(ch, 0x0a13, 0x0a28) || in_range(ch, 0x0a2a, 0x0a30) ||
Chris@16 145 in_range(ch, 0x0a32, 0x0a33) || in_range(ch, 0x0a35, 0x0a36) ||
Chris@16 146 in_range(ch, 0x0a38, 0x0a39) || in_range(ch, 0x0a59, 0x0a5c) ||
Chris@16 147 0x0a5e == ch)
Chris@16 148 {
Chris@16 149 return universal_char_type_valid; // Gurmukhi
Chris@16 150 }
Chris@16 151
Chris@16 152 if (in_range(ch, 0x0a85, 0x0a8b) || 0x0a8d == ch ||
Chris@16 153 in_range(ch, 0x0a8f, 0x0a91) || in_range(ch, 0x0a93, 0x0aa8) ||
Chris@16 154 in_range(ch, 0x0aaa, 0x0ab0) || in_range(ch, 0x0ab2, 0x0ab3) ||
Chris@16 155 in_range(ch, 0x0ab5, 0x0ab9) || 0x0ae0 == ch)
Chris@16 156 {
Chris@16 157 return universal_char_type_valid; // Gujarati
Chris@16 158 }
Chris@16 159
Chris@16 160 if (in_range(ch, 0x0b05, 0x0b0c) || in_range(ch, 0x0b0f, 0x0b10) ||
Chris@16 161 in_range(ch, 0x0b13, 0x0b28) || in_range(ch, 0x0b2a, 0x0b30) ||
Chris@16 162 in_range(ch, 0x0b32, 0x0b33) || in_range(ch, 0x0b36, 0x0b39) ||
Chris@16 163 in_range(ch, 0x0b5c, 0x0b5d) || in_range(ch, 0x0b5f, 0x0b61))
Chris@16 164 {
Chris@16 165 return universal_char_type_valid; // Oriya
Chris@16 166 }
Chris@16 167
Chris@16 168 if (in_range(ch, 0x0b85, 0x0b8a) || in_range(ch, 0x0b8e, 0x0b90) ||
Chris@16 169 in_range(ch, 0x0b92, 0x0b95) || in_range(ch, 0x0b99, 0x0b9a) ||
Chris@16 170 0x0b9c == ch || in_range(ch, 0x0b9e, 0x0b9f) ||
Chris@16 171 in_range(ch, 0x0ba3, 0x0ba4) || in_range(ch, 0x0ba8, 0x0baa) ||
Chris@16 172 in_range(ch, 0x0bae, 0x0bb5) || in_range(ch, 0x0bb7, 0x0bb9))
Chris@16 173 {
Chris@16 174 return universal_char_type_valid; // Tamil
Chris@16 175 }
Chris@16 176
Chris@16 177 if (in_range(ch, 0x0c05, 0x0c0c) || in_range(ch, 0x0c0e, 0x0c10) ||
Chris@16 178 in_range(ch, 0x0c12, 0x0c28) || in_range(ch, 0x0c2a, 0x0c33) ||
Chris@16 179 in_range(ch, 0x0c35, 0x0c39) || in_range(ch, 0x0c60, 0x0c61))
Chris@16 180 {
Chris@16 181 return universal_char_type_valid; // Telugu
Chris@16 182 }
Chris@16 183
Chris@16 184 if (in_range(ch, 0x0c85, 0x0c8c) || in_range(ch, 0x0c8e, 0x0c90) ||
Chris@16 185 in_range(ch, 0x0c92, 0x0ca8) || in_range(ch, 0x0caa, 0x0cb3) ||
Chris@16 186 in_range(ch, 0x0cb5, 0x0cb9) || in_range(ch, 0x0ce0, 0x0ce1))
Chris@16 187 {
Chris@16 188 return universal_char_type_valid; // Kannada
Chris@16 189 }
Chris@16 190
Chris@16 191 if (in_range(ch, 0x0d05, 0x0d0c) || in_range(ch, 0x0d0e, 0x0d10) ||
Chris@16 192 in_range(ch, 0x0d12, 0x0d28) || in_range(ch, 0x0d2a, 0x0d39) ||
Chris@16 193 in_range(ch, 0x0d60, 0x0d61))
Chris@16 194 {
Chris@16 195 return universal_char_type_valid; // Malayalam
Chris@16 196 }
Chris@16 197
Chris@16 198 if (in_range(ch, 0x0e01, 0x0e30) || in_range(ch, 0x0e32, 0x0e33) ||
Chris@16 199 in_range(ch, 0x0e40, 0x0e46) || in_range(ch, 0x0e4f, 0x0e5b))
Chris@16 200 {
Chris@16 201 return universal_char_type_valid; // Thai
Chris@16 202 }
Chris@16 203
Chris@16 204 return universal_char_type_not_allowed_for_identifiers;
Chris@16 205 }
Chris@16 206
Chris@16 207 ///////////////////////////////////////////////////////////////////////////////
Chris@16 208 //
Chris@16 209 // validate_identifier_name
Chris@16 210 //
Chris@16 211 // The validate_identifier_name function tests a given identifier name for
Chris@16 212 // its validity with regard to eventually contained universal characters.
Chris@16 213 // These should be in valid ranges (see the function
Chris@16 214 // classify_universal_char above).
Chris@16 215 //
Chris@16 216 // If the identifier name contains invalid or not allowed universal
Chris@16 217 // characters a corresponding lexing_exception is thrown.
Chris@16 218 //
Chris@16 219 ///////////////////////////////////////////////////////////////////////////////
Chris@16 220 template <typename StringT>
Chris@16 221 inline void
Chris@16 222 validate_identifier_name (StringT const &name, std::size_t line,
Chris@16 223 std::size_t column, StringT const &file_name)
Chris@16 224 {
Chris@16 225 using namespace std; // some systems have strtoul in namespace std::
Chris@16 226
Chris@16 227 typename StringT::size_type pos = name.find_first_of('\\');
Chris@16 228
Chris@16 229 while (StringT::npos != pos) {
Chris@16 230 // the identifier name contains a backslash (must be universal char)
Chris@16 231 BOOST_ASSERT('u' == name[pos+1] || 'U' == name[pos+1]);
Chris@16 232
Chris@16 233 StringT uchar_val(name.substr(pos+2, ('u' == name[pos+1]) ? 4 : 8));
Chris@16 234 universal_char_type type =
Chris@16 235 classify_universal_char(strtoul(uchar_val.c_str(), 0, 16));
Chris@16 236
Chris@16 237 if (universal_char_type_valid != type) {
Chris@16 238 // an invalid char was found, so throw an exception
Chris@16 239 StringT error_uchar(name.substr(pos, ('u' == name[pos+1]) ? 6 : 10));
Chris@16 240
Chris@16 241 if (universal_char_type_invalid == type) {
Chris@16 242 BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_invalid,
Chris@16 243 error_uchar, line, column, file_name.c_str());
Chris@16 244 }
Chris@16 245 else if (universal_char_type_base_charset == type) {
Chris@16 246 BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_base_charset,
Chris@16 247 error_uchar, line, column, file_name.c_str());
Chris@16 248 }
Chris@16 249 else {
Chris@16 250 BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_not_allowed,
Chris@16 251 error_uchar, line, column, file_name.c_str());
Chris@16 252 }
Chris@16 253 }
Chris@16 254
Chris@16 255 // find next universal char (if appropriate)
Chris@16 256 pos = name.find_first_of('\\', pos+2);
Chris@16 257 }
Chris@16 258 }
Chris@16 259
Chris@16 260 ///////////////////////////////////////////////////////////////////////////////
Chris@16 261 //
Chris@16 262 // validate_literal
Chris@16 263 //
Chris@16 264 // The validate_literal function tests a given string or character literal
Chris@16 265 // for its validity with regard to eventually contained universal
Chris@16 266 // characters. These should be in valid ranges (see the function
Chris@16 267 // classify_universal_char above).
Chris@16 268 //
Chris@16 269 // If the string or character literal contains invalid or not allowed
Chris@16 270 // universal characters a corresponding lexing_exception is thrown.
Chris@16 271 //
Chris@16 272 ///////////////////////////////////////////////////////////////////////////////
Chris@16 273 template <typename StringT>
Chris@16 274 inline void
Chris@16 275 validate_literal (StringT const &name, std::size_t line, std::size_t column,
Chris@16 276 StringT const &file_name)
Chris@16 277 {
Chris@16 278 using namespace std; // some systems have strtoul in namespace std::
Chris@16 279
Chris@16 280 typename StringT::size_type pos = name.find_first_of('\\');
Chris@16 281
Chris@16 282 while (StringT::npos != pos) {
Chris@16 283 // the literal contains a backslash (may be universal char)
Chris@16 284 if ('u' == name[pos+1] || 'U' == name[pos+1]) {
Chris@16 285 StringT uchar_val(name.substr(pos+2, ('u' == name[pos+1]) ? 4 : 8));
Chris@16 286 universal_char_type type =
Chris@16 287 classify_universal_char(strtoul(uchar_val.c_str(), 0, 16));
Chris@16 288
Chris@16 289 if (universal_char_type_valid != type &&
Chris@16 290 universal_char_type_not_allowed_for_identifiers != type)
Chris@16 291 {
Chris@16 292 // an invalid char was found, so throw an exception
Chris@16 293 StringT error_uchar(name.substr(pos, ('u' == name[pos+1]) ? 6 : 10));
Chris@16 294
Chris@16 295 if (universal_char_type_invalid == type) {
Chris@16 296 BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_invalid,
Chris@16 297 error_uchar, line, column, file_name.c_str());
Chris@16 298 }
Chris@16 299 else {
Chris@16 300 BOOST_WAVE_LEXER_THROW(lexing_exception, universal_char_base_charset,
Chris@16 301 error_uchar, line, column, file_name.c_str());
Chris@16 302 }
Chris@16 303 }
Chris@16 304 }
Chris@16 305
Chris@16 306 // find next universal char (if appropriate)
Chris@16 307 pos = name.find_first_of('\\', pos+2);
Chris@16 308 }
Chris@16 309 }
Chris@16 310
Chris@16 311 ///////////////////////////////////////////////////////////////////////////////
Chris@16 312 } // namespace impl
Chris@16 313 } // namespace cpplexer
Chris@16 314 } // namespace wave
Chris@16 315 } // namespace boost
Chris@16 316
Chris@16 317 // the suffix header occurs after all of the code
Chris@16 318 #ifdef BOOST_HAS_ABI_HEADERS
Chris@16 319 #include BOOST_ABI_SUFFIX
Chris@16 320 #endif
Chris@16 321
Chris@16 322 #endif // !defined(VALIDATE_UNIVERSAL_CHAR_HPP_55F1B811_CD76_4C72_8344_CBC69CF3B339_INCLUDED)