1 /*=============================================================================
2 Boost.Wave: A Standard compliant C++ preprocessor library
4 Detect the need to insert a whitespace token into the output stream
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
15 #include <boost/wave/wave_config.hpp>
16 #include <boost/wave/token_ids.hpp>
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
23 ///////////////////////////////////////////////////////////////////////////////
31 template <typename StringT>
33 would_form_universal_char (StringT const &value)
35 if ('u' != value[0] && 'U' != value[0])
37 if ('u' == value[0] && value.size() < 5)
39 if ('U' == value[0] && value.size() < 9)
42 typename StringT::size_type pos =
43 value.find_first_not_of("0123456789abcdefABCDEF", 1);
45 if (StringT::npos == pos ||
46 ('u' == value[0] && pos > 5) ||
47 ('U' == value[0] && pos > 9))
49 return true; // would form an universal char
53 template <typename StringT>
55 handle_identifier(boost::wave::token_id prev,
56 boost::wave::token_id before, StringT const &value)
58 using namespace boost::wave;
59 switch (static_cast<unsigned int>(prev)) {
61 case T_NONREPLACABLE_IDENTIFIER:
77 return (value.size() > 1 || (value[0] != 'e' && value[0] != 'E'));
79 // avoid constructing universal characters (\u1234)
80 case TOKEN_FROM_ID('\\', UnknownTokenType):
81 return would_form_universal_char(value);
87 handle_intlit(boost::wave::token_id prev, boost::wave::token_id /*before*/)
89 using namespace boost::wave;
90 switch (static_cast<unsigned int>(prev)) {
92 case T_NONREPLACABLE_IDENTIFIER:
103 handle_floatlit(boost::wave::token_id prev,
104 boost::wave::token_id /*before*/)
106 using namespace boost::wave;
107 switch (static_cast<unsigned int>(prev)) {
109 case T_NONREPLACABLE_IDENTIFIER:
112 case T_FIXEDPOINTLIT:
120 handle_alt_leftbrace(boost::wave::token_id prev,
121 boost::wave::token_id /*before*/)
123 using namespace boost::wave;
124 switch (static_cast<unsigned int>(prev)) {
126 case T_SHIFTLEFT: // <<<%
133 handle_alt_leftbracket(boost::wave::token_id prev,
134 boost::wave::token_id /*before*/)
136 using namespace boost::wave;
137 switch (static_cast<unsigned int>(prev)) {
139 case T_SHIFTLEFT: // <<<:
146 handle_fixedpointlit(boost::wave::token_id prev,
147 boost::wave::token_id /*before*/)
149 using namespace boost::wave;
150 switch (static_cast<unsigned int>(prev)) {
152 case T_NONREPLACABLE_IDENTIFIER:
155 case T_FIXEDPOINTLIT:
163 handle_dot(boost::wave::token_id prev, boost::wave::token_id before)
165 using namespace boost::wave;
166 switch (static_cast<unsigned int>(prev)) {
176 handle_questionmark(boost::wave::token_id prev,
177 boost::wave::token_id /*before*/)
179 using namespace boost::wave;
180 switch(static_cast<unsigned int>(prev)) {
181 case TOKEN_FROM_ID('\\', UnknownTokenType): // \?
182 case T_QUESTION_MARK: // ??
189 handle_newline(boost::wave::token_id prev,
190 boost::wave::token_id before)
192 using namespace boost::wave;
193 switch(static_cast<unsigned int>(prev)) {
194 case TOKEN_FROM_ID('\\', UnknownTokenType): // \ \n
196 if (T_QUESTION_MARK == before)
197 return true; // ?/\n // may be \\n
204 handle_parens(boost::wave::token_id prev)
206 switch (static_cast<unsigned int>(prev)) {
216 // no insertion between parens/brackets/braces and operators
227 class insert_whitespace_detection
230 insert_whitespace_detection(bool insert_whitespace_ = true)
231 : insert_whitespace(insert_whitespace_),
232 prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF)
235 template <typename StringT>
236 bool must_insert(boost::wave::token_id current, StringT const &value)
238 if (!insert_whitespace)
239 return false; // skip whitespace insertion alltogether
241 using namespace boost::wave;
242 switch (static_cast<unsigned int>(current)) {
243 case T_NONREPLACABLE_IDENTIFIER:
245 return impl::handle_identifier(prev, beforeprev, value);
248 return impl::handle_intlit(prev, beforeprev);
250 return impl::handle_floatlit(prev, beforeprev);
252 if (TOKEN_FROM_ID('L', IdentifierTokenType) == prev) // 'L'
255 case T_LEFTBRACE_ALT:
256 return impl::handle_alt_leftbrace(prev, beforeprev);
257 case T_LEFTBRACKET_ALT:
258 return impl::handle_alt_leftbracket(prev, beforeprev);
259 case T_FIXEDPOINTLIT:
260 return impl::handle_fixedpointlit(prev, beforeprev);
262 return impl::handle_dot(prev, beforeprev);
263 case T_QUESTION_MARK:
264 return impl::handle_questionmark(prev, beforeprev);
266 return impl::handle_newline(prev, beforeprev);
275 switch (static_cast<unsigned int>(prev)) {
282 return false; // no insertion between parens/brackets/braces
285 if (IS_CATEGORY(prev, OperatorTokenType))
293 switch (static_cast<unsigned int>(prev)) {
303 return false; // no insertion between parens/brackets/braces
305 case T_QUESTION_MARK:
306 if (T_QUESTION_MARK == beforeprev)
308 if (IS_CATEGORY(prev, OperatorTokenType))
320 if (T_MINUS == prev || T_MINUSMINUS == prev)
322 if (!impl::handle_parens(prev))
324 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
331 if (T_PLUS == prev || T_PLUSPLUS == prev)
333 if (!impl::handle_parens(prev))
335 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
341 if (T_DIVIDE == prev)
343 if (!impl::handle_parens(prev))
345 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
351 switch (static_cast<unsigned int>(prev)) {
356 case T_SHIFTRIGHTASSIGN:
357 case T_SHIFTLEFTASSIGN:
378 case T_QUESTION_MARK:
379 if (T_QUESTION_MARK == beforeprev)
384 if (!impl::handle_parens(prev))
391 if (T_MINUS == prev || T_GREATER == prev)
392 return true; // prevent -> or >>
393 if (!impl::handle_parens(prev))
395 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
401 return true; // prevent <<
406 if (!impl::handle_parens(prev))
408 if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
414 if (!impl::handle_parens(prev))
416 if (T_AND == prev || T_ANDAND == prev)
421 if (!impl::handle_parens(prev))
428 if (!impl::handle_parens(prev))
439 case T_ANDASSIGN_ALT:
441 case T_XORASSIGN_ALT:
443 switch (static_cast<unsigned int>(prev)) {
453 // no insertion between parens/brackets/braces and operators
457 if (T_NONREPLACABLE_IDENTIFIER == prev ||
458 IS_CATEGORY(prev, KeywordTokenType))
471 return false; // '*****' do not need to be separated
472 if (T_GREATER== prev &&
473 (T_MINUS == beforeprev || T_MINUSMINUS == beforeprev)
476 return true; // prevent ->*
486 // FIXME: else, handle operators separately (will catch to many cases)
487 // if (IS_CATEGORY(current, OperatorTokenType) &&
488 // IS_CATEGORY(prev, OperatorTokenType))
490 // return true; // operators must be delimited always
494 void shift_tokens (boost::wave::token_id next_id)
496 if (insert_whitespace) {
503 bool insert_whitespace; // enable this component
504 boost::wave::token_id prev; // the previous analyzed token
505 boost::wave::token_id beforeprev; // the token before the previous
508 ///////////////////////////////////////////////////////////////////////////////
513 // the suffix header occurs after all of the code
514 #ifdef BOOST_HAS_ABI_HEADERS
515 #include BOOST_ABI_SUFFIX
518 #endif // !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED)