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-2005 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 /////////////////////////////////////////////////////////////////////////////// 19 namespace boost { 20 namespace wave { 21 namespace util { 22 23 namespace impl { 24 25 // T_IDENTIFIER 26 template <typename StringT> 27 inline bool would_form_universal_char(StringT const & value)28 would_form_universal_char (StringT const &value) 29 { 30 if ('u' != value[0] && 'U' != value[0]) 31 return false; 32 if ('u' == value[0] && value.size() < 5) 33 return false; 34 if ('U' == value[0] && value.size() < 9) 35 return false; 36 37 typename StringT::size_type pos = 38 value.find_first_not_of("0123456789abcdefABCDEF", 1); 39 40 if (StringT::npos == pos || 41 ('u' == value[0] && pos > 5) || 42 ('U' == value[0] && pos > 9)) 43 { 44 return true; // would form an universal char 45 } 46 return false; 47 } 48 template <typename StringT> 49 inline bool handle_identifier(boost::wave::token_id prev,boost::wave::token_id before,StringT const & value)50 handle_identifier(boost::wave::token_id prev, 51 boost::wave::token_id before, StringT const &value) 52 { 53 using namespace boost::wave; 54 switch (static_cast<unsigned int>(prev)) { 55 case T_IDENTIFIER: 56 case T_NONREPLACABLE_IDENTIFIER: 57 case T_COMPL_ALT: 58 case T_OR_ALT: 59 case T_AND_ALT: 60 case T_NOT_ALT: 61 case T_XOR_ALT: 62 case T_ANDASSIGN_ALT: 63 case T_ORASSIGN_ALT: 64 case T_XORASSIGN_ALT: 65 case T_NOTEQUAL_ALT: 66 case T_FIXEDPOINTLIT: 67 return true; 68 69 case T_FLOATLIT: 70 case T_INTLIT: 71 return (value.size() > 1 || (value[0] != 'e' && value[0] != 'E')); 72 73 // avoid constructing universal characters (\u1234) 74 case TOKEN_FROM_ID('\\', UnknownTokenType): 75 return would_form_universal_char(value); 76 } 77 return false; 78 } 79 // T_INTLIT 80 inline bool handle_intlit(boost::wave::token_id prev,boost::wave::token_id before)81 handle_intlit(boost::wave::token_id prev, boost::wave::token_id before) 82 { 83 using namespace boost::wave; 84 switch (static_cast<unsigned int>(prev)) { 85 case T_IDENTIFIER: 86 case T_NONREPLACABLE_IDENTIFIER: 87 case T_INTLIT: 88 case T_FLOATLIT: 89 case T_FIXEDPOINTLIT: 90 return true; 91 } 92 return false; 93 } 94 // T_FLOATLIT 95 inline bool handle_floatlit(boost::wave::token_id prev,boost::wave::token_id before)96 handle_floatlit(boost::wave::token_id prev, 97 boost::wave::token_id before) 98 { 99 using namespace boost::wave; 100 switch (static_cast<unsigned int>(prev)) { 101 case T_IDENTIFIER: 102 case T_NONREPLACABLE_IDENTIFIER: 103 case T_INTLIT: 104 case T_FLOATLIT: 105 case T_FIXEDPOINTLIT: 106 return true; 107 } 108 return false; 109 } 110 // <% T_LEFTBRACE 111 inline bool handle_alt_leftbrace(boost::wave::token_id prev,boost::wave::token_id before)112 handle_alt_leftbrace(boost::wave::token_id prev, 113 boost::wave::token_id before) 114 { 115 using namespace boost::wave; 116 switch (static_cast<unsigned int>(prev)) { 117 case T_LESS: // <<% 118 case T_SHIFTLEFT: // <<<% 119 return true; 120 } 121 return false; 122 } 123 // <: T_LEFTBRACKET 124 inline bool handle_alt_leftbracket(boost::wave::token_id prev,boost::wave::token_id before)125 handle_alt_leftbracket(boost::wave::token_id prev, 126 boost::wave::token_id before) 127 { 128 using namespace boost::wave; 129 switch (static_cast<unsigned int>(prev)) { 130 case T_LESS: // <<: 131 case T_SHIFTLEFT: // <<<: 132 return true; 133 } 134 return false; 135 } 136 // T_FIXEDPOINTLIT 137 inline bool handle_fixedpointlit(boost::wave::token_id prev,boost::wave::token_id before)138 handle_fixedpointlit(boost::wave::token_id prev, 139 boost::wave::token_id before) 140 { 141 using namespace boost::wave; 142 switch (static_cast<unsigned int>(prev)) { 143 case T_IDENTIFIER: 144 case T_NONREPLACABLE_IDENTIFIER: 145 case T_INTLIT: 146 case T_FLOATLIT: 147 case T_FIXEDPOINTLIT: 148 return true; 149 } 150 return false; 151 } 152 // T_DOT 153 inline bool handle_dot(boost::wave::token_id prev,boost::wave::token_id before)154 handle_dot(boost::wave::token_id prev, boost::wave::token_id before) 155 { 156 using namespace boost::wave; 157 switch (static_cast<unsigned int>(prev)) { 158 case T_DOT: 159 if (T_DOT == before) 160 return true; // ... 161 break; 162 } 163 return false; 164 } 165 // T_QUESTION_MARK 166 inline bool handle_questionmark(boost::wave::token_id prev,boost::wave::token_id before)167 handle_questionmark(boost::wave::token_id prev, 168 boost::wave::token_id before) 169 { 170 using namespace boost::wave; 171 switch(static_cast<unsigned int>(prev)) { 172 case TOKEN_FROM_ID('\\', UnknownTokenType): // \? 173 case T_QUESTION_MARK: // ?? 174 return true; 175 } 176 return false; 177 } 178 // T_NEWLINE 179 inline bool handle_newline(boost::wave::token_id prev,boost::wave::token_id before)180 handle_newline(boost::wave::token_id prev, 181 boost::wave::token_id before) 182 { 183 using namespace boost::wave; 184 switch(static_cast<unsigned int>(prev)) { 185 case TOKEN_FROM_ID('\\', UnknownTokenType): // \ \n 186 case T_DIVIDE: 187 if (T_QUESTION_MARK == before) 188 return true; // ?/\n // may be \\n 189 break; 190 } 191 return false; 192 } 193 194 } // namespace impl 195 196 class insert_whitespace_detection 197 { 198 public: insert_whitespace_detection()199 insert_whitespace_detection() 200 : prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF) 201 {} 202 203 template <typename StringT> must_insert(boost::wave::token_id current,StringT const & value)204 bool must_insert(boost::wave::token_id current, StringT const &value) 205 { 206 using namespace boost::wave; 207 switch (current) { 208 case T_NONREPLACABLE_IDENTIFIER: 209 case T_IDENTIFIER: 210 return impl::handle_identifier(prev, beforeprev, value); 211 case T_INTLIT: 212 return impl::handle_intlit(prev, beforeprev); 213 case T_FLOATLIT: 214 return impl::handle_floatlit(prev, beforeprev); 215 case T_STRINGLIT: 216 if (TOKEN_FROM_ID('L', UnknownTokenType) == prev) // 'L' 217 return true; 218 break; 219 case T_LEFTBRACE_ALT: 220 return impl::handle_alt_leftbrace(prev, beforeprev); 221 case T_LEFTBRACKET_ALT: 222 return impl::handle_alt_leftbracket(prev, beforeprev); 223 case T_FIXEDPOINTLIT: 224 return impl::handle_fixedpointlit(prev, beforeprev); 225 case T_DOT: 226 return impl::handle_dot(prev, beforeprev); 227 case T_QUESTION_MARK: 228 return impl::handle_questionmark(prev, beforeprev); 229 case T_NEWLINE: 230 return impl::handle_newline(prev, beforeprev); 231 232 case T_LEFTPAREN: 233 case T_RIGHTPAREN: 234 case T_LEFTBRACKET: 235 case T_RIGHTBRACKET: 236 case T_SEMICOLON: 237 case T_COMMA: 238 case T_COLON: 239 switch (static_cast<unsigned int>(prev)) { 240 case T_LEFTPAREN: 241 case T_RIGHTPAREN: 242 case T_LEFTBRACKET: 243 case T_RIGHTBRACKET: 244 case T_LEFTBRACE: 245 case T_RIGHTBRACE: 246 return false; // no insertion between parens/brackets/braces 247 248 default: 249 break; 250 } 251 break; 252 253 case T_LEFTBRACE: 254 case T_RIGHTBRACE: 255 switch (static_cast<unsigned int>(prev)) { 256 case T_LEFTPAREN: 257 case T_RIGHTPAREN: 258 case T_LEFTBRACKET: 259 case T_RIGHTBRACKET: 260 case T_LEFTBRACE: 261 case T_RIGHTBRACE: 262 case T_SEMICOLON: 263 case T_COMMA: 264 case T_COLON: 265 return false; // no insertion between parens/brackets/braces 266 267 case T_QUESTION_MARK: 268 if (T_QUESTION_MARK == beforeprev) 269 return true; 270 break; 271 272 default: 273 break; 274 } 275 break; 276 277 case T_MINUS: 278 case T_MINUSMINUS: 279 case T_LESS: 280 case T_EQUAL: 281 case T_ASSIGN: 282 case T_GREATER: 283 case T_DIVIDE: 284 case T_CHARLIT: 285 case T_NOT: 286 case T_NOTEQUAL: 287 case T_DIVIDEASSIGN: 288 case T_MINUSASSIGN: 289 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) 290 return true; // ??{op} 291 break; 292 293 case T_COMPL_ALT: 294 case T_OR_ALT: 295 case T_AND_ALT: 296 case T_NOT_ALT: 297 case T_XOR_ALT: 298 case T_ANDASSIGN_ALT: 299 case T_ORASSIGN_ALT: 300 case T_XORASSIGN_ALT: 301 case T_NOTEQUAL_ALT: 302 if (T_IDENTIFIER == prev || T_NONREPLACABLE_IDENTIFIER == prev || 303 IS_CATEGORY(prev, KeywordTokenType)) 304 return true; 305 break; 306 } 307 308 // else, handle operators separately 309 if (IS_CATEGORY(current, OperatorTokenType) && 310 IS_CATEGORY(prev, OperatorTokenType)) 311 { 312 return true; // operators must be delimited always 313 } 314 return false; 315 } shift_tokens(boost::wave::token_id next_id)316 void shift_tokens (boost::wave::token_id next_id) 317 { 318 beforeprev = prev; 319 prev = next_id; 320 } 321 322 private: 323 boost::wave::token_id prev; // the previous analyzed token 324 boost::wave::token_id beforeprev; // the token before the previous 325 }; 326 327 /////////////////////////////////////////////////////////////////////////////// 328 } // namespace util 329 } // namespace wave 330 } // namespace boost 331 332 #endif // !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED) 333