1 /*============================================================================= 2 Boost.Wave: A Standard compliant C++ preprocessor library 3 4 Detect the need to insert a whitespace token into the output stream 5 6 http://www.boost.org/ 7 8 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost 9 Software License, Version 1.0. (See accompanying file 10 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 11 =============================================================================*/ 12 #if !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED) 13 #define INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED 14 15 #include <boost/wave/wave_config.hpp> 16 #include <boost/wave/token_ids.hpp> 17 18 // this must occur after all of the includes and before any code appears 19 #ifdef BOOST_HAS_ABI_HEADERS 20 #include BOOST_ABI_PREFIX 21 #endif 22 23 /////////////////////////////////////////////////////////////////////////////// 24 namespace boost { 25 namespace wave { 26 namespace util { 27 28 namespace impl { 29 30 // T_IDENTIFIER 31 template <typename StringT> 32 inline bool would_form_universal_char(StringT const & value)33 would_form_universal_char (StringT const &value) 34 { 35 if ('u' != value[0] && 'U' != value[0]) 36 return false; 37 if ('u' == value[0] && value.size() < 5) 38 return false; 39 if ('U' == value[0] && value.size() < 9) 40 return false; 41 42 typename StringT::size_type pos = 43 value.find_first_not_of("0123456789abcdefABCDEF", 1); 44 45 if (StringT::npos == pos || 46 ('u' == value[0] && pos > 5) || 47 ('U' == value[0] && pos > 9)) 48 { 49 return true; // would form an universal char 50 } 51 return false; 52 } 53 template <typename StringT> 54 inline bool handle_identifier(boost::wave::token_id prev,boost::wave::token_id before,StringT const & value)55 handle_identifier(boost::wave::token_id prev, 56 boost::wave::token_id before, StringT const &value) 57 { 58 using namespace boost::wave; 59 switch (prev) { 60 case T_IDENTIFIER: 61 case T_NONREPLACABLE_IDENTIFIER: 62 case T_COMPL_ALT: 63 case T_OR_ALT: 64 case T_AND_ALT: 65 case T_NOT_ALT: 66 case T_XOR_ALT: 67 case T_ANDASSIGN_ALT: 68 case T_ORASSIGN_ALT: 69 case T_XORASSIGN_ALT: 70 case T_NOTEQUAL_ALT: 71 case T_FIXEDPOINTLIT: 72 return true; 73 74 case T_FLOATLIT: 75 case T_INTLIT: 76 case T_PP_NUMBER: 77 return (value.size() > 1 || (value[0] != 'e' && value[0] != 'E')); 78 79 // avoid constructing universal characters (\u1234) 80 case T_UNKNOWN_UNIVERSALCHAR: 81 return would_form_universal_char(value); 82 83 default: 84 break; 85 } 86 return false; 87 } 88 // T_INTLIT 89 inline bool handle_intlit(boost::wave::token_id prev,boost::wave::token_id)90 handle_intlit(boost::wave::token_id prev, boost::wave::token_id /*before*/) 91 { 92 using namespace boost::wave; 93 switch (prev) { 94 case T_IDENTIFIER: 95 case T_NONREPLACABLE_IDENTIFIER: 96 case T_INTLIT: 97 case T_FLOATLIT: 98 case T_FIXEDPOINTLIT: 99 case T_PP_NUMBER: 100 return true; 101 102 default: 103 break; 104 } 105 return false; 106 } 107 // T_FLOATLIT 108 inline bool handle_floatlit(boost::wave::token_id prev,boost::wave::token_id)109 handle_floatlit(boost::wave::token_id prev, 110 boost::wave::token_id /*before*/) 111 { 112 using namespace boost::wave; 113 switch (prev) { 114 case T_IDENTIFIER: 115 case T_NONREPLACABLE_IDENTIFIER: 116 case T_INTLIT: 117 case T_FLOATLIT: 118 case T_FIXEDPOINTLIT: 119 case T_PP_NUMBER: 120 return true; 121 122 default: 123 break; 124 } 125 return false; 126 } 127 // <% T_LEFTBRACE 128 inline bool handle_alt_leftbrace(boost::wave::token_id prev,boost::wave::token_id)129 handle_alt_leftbrace(boost::wave::token_id prev, 130 boost::wave::token_id /*before*/) 131 { 132 using namespace boost::wave; 133 switch (prev) { 134 case T_LESS: // <<% 135 case T_SHIFTLEFT: // <<<% 136 return true; 137 138 default: 139 break; 140 } 141 return false; 142 } 143 // <: T_LEFTBRACKET 144 inline bool handle_alt_leftbracket(boost::wave::token_id prev,boost::wave::token_id)145 handle_alt_leftbracket(boost::wave::token_id prev, 146 boost::wave::token_id /*before*/) 147 { 148 using namespace boost::wave; 149 switch (prev) { 150 case T_LESS: // <<: 151 case T_SHIFTLEFT: // <<<: 152 return true; 153 154 default: 155 break; 156 } 157 return false; 158 } 159 // T_FIXEDPOINTLIT 160 inline bool handle_fixedpointlit(boost::wave::token_id prev,boost::wave::token_id)161 handle_fixedpointlit(boost::wave::token_id prev, 162 boost::wave::token_id /*before*/) 163 { 164 using namespace boost::wave; 165 switch (prev) { 166 case T_IDENTIFIER: 167 case T_NONREPLACABLE_IDENTIFIER: 168 case T_INTLIT: 169 case T_FLOATLIT: 170 case T_FIXEDPOINTLIT: 171 case T_PP_NUMBER: 172 return true; 173 174 default: 175 break; 176 } 177 return false; 178 } 179 // T_DOT 180 inline bool handle_dot(boost::wave::token_id prev,boost::wave::token_id before)181 handle_dot(boost::wave::token_id prev, boost::wave::token_id before) 182 { 183 using namespace boost::wave; 184 switch (prev) { 185 case T_DOT: 186 if (T_DOT == before) 187 return true; // ... 188 break; 189 190 default: 191 break; 192 } 193 return false; 194 } 195 // T_QUESTION_MARK 196 inline bool handle_questionmark(boost::wave::token_id prev,boost::wave::token_id)197 handle_questionmark(boost::wave::token_id prev, 198 boost::wave::token_id /*before*/) 199 { 200 using namespace boost::wave; 201 switch(prev) { 202 case T_UNKNOWN_UNIVERSALCHAR: // \? 203 case T_QUESTION_MARK: // ?? 204 return true; 205 206 default: 207 break; 208 } 209 return false; 210 } 211 // T_NEWLINE 212 inline bool handle_newline(boost::wave::token_id prev,boost::wave::token_id before)213 handle_newline(boost::wave::token_id prev, 214 boost::wave::token_id before) 215 { 216 using namespace boost::wave; 217 switch(prev) { 218 case TOKEN_FROM_ID('\\', UnknownTokenType): // \ \n 219 case T_DIVIDE: 220 if (T_QUESTION_MARK == before) 221 return true; // ?/\n // may be \\n 222 break; 223 224 default: 225 break; 226 } 227 return false; 228 } 229 230 inline bool handle_parens(boost::wave::token_id prev)231 handle_parens(boost::wave::token_id prev) 232 { 233 switch (prev) { 234 case T_LEFTPAREN: 235 case T_RIGHTPAREN: 236 case T_LEFTBRACKET: 237 case T_RIGHTBRACKET: 238 case T_LEFTBRACE: 239 case T_RIGHTBRACE: 240 case T_SEMICOLON: 241 case T_COMMA: 242 case T_COLON: 243 // no insertion between parens/brackets/braces and operators 244 return false; 245 246 default: 247 break; 248 } 249 return true; 250 } 251 252 } // namespace impl 253 254 class insert_whitespace_detection 255 { 256 public: insert_whitespace_detection(bool insert_whitespace_=true)257 insert_whitespace_detection(bool insert_whitespace_ = true) 258 : insert_whitespace(insert_whitespace_), 259 prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF) 260 {} 261 262 template <typename StringT> must_insert(boost::wave::token_id current,StringT const & value)263 bool must_insert(boost::wave::token_id current, StringT const &value) 264 { 265 if (!insert_whitespace) 266 return false; // skip whitespace insertion alltogether 267 268 using namespace boost::wave; 269 switch (current) { 270 case T_NONREPLACABLE_IDENTIFIER: 271 case T_IDENTIFIER: 272 return impl::handle_identifier(prev, beforeprev, value); 273 case T_PP_NUMBER: 274 case T_INTLIT: 275 return impl::handle_intlit(prev, beforeprev); 276 case T_FLOATLIT: 277 return impl::handle_floatlit(prev, beforeprev); 278 case T_STRINGLIT: 279 if (TOKEN_FROM_ID('L', IdentifierTokenType) == prev) // 'L' 280 return true; 281 break; 282 case T_LEFTBRACE_ALT: 283 return impl::handle_alt_leftbrace(prev, beforeprev); 284 case T_LEFTBRACKET_ALT: 285 return impl::handle_alt_leftbracket(prev, beforeprev); 286 case T_FIXEDPOINTLIT: 287 return impl::handle_fixedpointlit(prev, beforeprev); 288 case T_DOT: 289 return impl::handle_dot(prev, beforeprev); 290 case T_QUESTION_MARK: 291 return impl::handle_questionmark(prev, beforeprev); 292 case T_NEWLINE: 293 return impl::handle_newline(prev, beforeprev); 294 295 case T_LEFTPAREN: 296 case T_RIGHTPAREN: 297 case T_LEFTBRACKET: 298 case T_RIGHTBRACKET: 299 case T_SEMICOLON: 300 case T_COMMA: 301 case T_COLON: 302 switch (prev) { 303 case T_LEFTPAREN: 304 case T_RIGHTPAREN: 305 case T_LEFTBRACKET: 306 case T_RIGHTBRACKET: 307 case T_LEFTBRACE: 308 case T_RIGHTBRACE: 309 return false; // no insertion between parens/brackets/braces 310 311 default: 312 if (IS_CATEGORY(prev, OperatorTokenType)) 313 return false; 314 break; 315 } 316 break; 317 318 case T_LEFTBRACE: 319 case T_RIGHTBRACE: 320 switch (prev) { 321 case T_LEFTPAREN: 322 case T_RIGHTPAREN: 323 case T_LEFTBRACKET: 324 case T_RIGHTBRACKET: 325 case T_LEFTBRACE: 326 case T_RIGHTBRACE: 327 case T_SEMICOLON: 328 case T_COMMA: 329 case T_COLON: 330 return false; // no insertion between parens/brackets/braces 331 332 case T_QUESTION_MARK: 333 if (T_QUESTION_MARK == beforeprev) 334 return true; 335 if (IS_CATEGORY(prev, OperatorTokenType)) 336 return false; 337 break; 338 339 default: 340 break; 341 } 342 break; 343 344 case T_MINUS: 345 case T_MINUSMINUS: 346 case T_MINUSASSIGN: 347 if (T_MINUS == prev || T_MINUSMINUS == prev) 348 return true; 349 if (!impl::handle_parens(prev)) 350 return false; 351 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) 352 return true; 353 break; 354 355 case T_PLUS: 356 case T_PLUSPLUS: 357 case T_PLUSASSIGN: 358 if (T_PLUS == prev || T_PLUSPLUS == prev) 359 return true; 360 if (!impl::handle_parens(prev)) 361 return false; 362 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) 363 return true; 364 break; 365 366 case T_DIVIDE: 367 case T_DIVIDEASSIGN: 368 if (T_DIVIDE == prev) 369 return true; 370 if (!impl::handle_parens(prev)) 371 return false; 372 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) 373 return true; 374 break; 375 376 case T_EQUAL: 377 case T_ASSIGN: 378 switch (prev) { 379 case T_PLUSASSIGN: 380 case T_MINUSASSIGN: 381 case T_DIVIDEASSIGN: 382 case T_STARASSIGN: 383 case T_SHIFTRIGHTASSIGN: 384 case T_SHIFTLEFTASSIGN: 385 case T_EQUAL: 386 case T_NOTEQUAL: 387 case T_LESSEQUAL: 388 case T_GREATEREQUAL: 389 case T_LESS: 390 case T_GREATER: 391 case T_PLUS: 392 case T_MINUS: 393 case T_STAR: 394 case T_DIVIDE: 395 case T_ORASSIGN: 396 case T_ANDASSIGN: 397 case T_XORASSIGN: 398 case T_OR: 399 case T_AND: 400 case T_XOR: 401 case T_OROR: 402 case T_ANDAND: 403 return true; 404 405 case T_QUESTION_MARK: 406 if (T_QUESTION_MARK == beforeprev) 407 return true; 408 break; 409 410 default: 411 if (!impl::handle_parens(prev)) 412 return false; 413 break; 414 } 415 break; 416 417 case T_GREATER: 418 if (T_MINUS == prev || T_GREATER == prev) 419 return true; // prevent -> or >> 420 if (!impl::handle_parens(prev)) 421 return false; 422 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) 423 return true; 424 break; 425 426 case T_LESS: 427 if (T_LESS == prev) 428 return true; // prevent << 429 // fall through 430 case T_CHARLIT: 431 case T_NOT: 432 case T_NOTEQUAL: 433 if (!impl::handle_parens(prev)) 434 return false; 435 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) 436 return true; 437 break; 438 439 case T_AND: 440 case T_ANDAND: 441 if (!impl::handle_parens(prev)) 442 return false; 443 if (T_AND == prev || T_ANDAND == prev) 444 return true; 445 break; 446 447 case T_OR: 448 if (!impl::handle_parens(prev)) 449 return false; 450 if (T_OR == prev) 451 return true; 452 break; 453 454 case T_XOR: 455 if (!impl::handle_parens(prev)) 456 return false; 457 if (T_XOR == prev) 458 return true; 459 break; 460 461 case T_COMPL_ALT: 462 case T_OR_ALT: 463 case T_AND_ALT: 464 case T_NOT_ALT: 465 case T_XOR_ALT: 466 case T_ANDASSIGN_ALT: 467 case T_ORASSIGN_ALT: 468 case T_XORASSIGN_ALT: 469 case T_NOTEQUAL_ALT: 470 switch (prev) { 471 case T_LEFTPAREN: 472 case T_RIGHTPAREN: 473 case T_LEFTBRACKET: 474 case T_RIGHTBRACKET: 475 case T_LEFTBRACE: 476 case T_RIGHTBRACE: 477 case T_SEMICOLON: 478 case T_COMMA: 479 case T_COLON: 480 // no insertion between parens/brackets/braces and operators 481 return false; 482 483 case T_IDENTIFIER: 484 if (T_NONREPLACABLE_IDENTIFIER == prev || 485 IS_CATEGORY(prev, KeywordTokenType)) 486 { 487 return true; 488 } 489 break; 490 491 default: 492 break; 493 } 494 break; 495 496 case T_STAR: 497 if (T_STAR == prev) 498 return false; // '*****' do not need to be separated 499 if (T_GREATER== prev && 500 (T_MINUS == beforeprev || T_MINUSMINUS == beforeprev) 501 ) 502 { 503 return true; // prevent ->* 504 } 505 break; 506 507 case T_POUND: 508 if (T_POUND == prev) 509 return true; 510 break; 511 512 default: 513 break; 514 } 515 516 // FIXME: else, handle operators separately (will catch to many cases) 517 // if (IS_CATEGORY(current, OperatorTokenType) && 518 // IS_CATEGORY(prev, OperatorTokenType)) 519 // { 520 // return true; // operators must be delimited always 521 // } 522 return false; 523 } shift_tokens(boost::wave::token_id next_id)524 void shift_tokens (boost::wave::token_id next_id) 525 { 526 if (insert_whitespace) { 527 beforeprev = prev; 528 prev = next_id; 529 } 530 } 531 532 private: 533 bool insert_whitespace; // enable this component 534 boost::wave::token_id prev; // the previous analyzed token 535 boost::wave::token_id beforeprev; // the token before the previous 536 }; 537 538 /////////////////////////////////////////////////////////////////////////////// 539 } // namespace util 540 } // namespace wave 541 } // namespace boost 542 543 // the suffix header occurs after all of the code 544 #ifdef BOOST_HAS_ABI_HEADERS 545 #include BOOST_ABI_SUFFIX 546 #endif 547 548 #endif // !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED) 549