/*============================================================================= | |
Boost.Wave: A Standard compliant C++ preprocessor library | |
Detect the need to insert a whitespace token into the output stream | |
http://www.boost.org/ | |
Copyright (c) 2001-2011 Hartmut Kaiser. Distributed under the Boost | |
Software License, Version 1.0. (See accompanying file | |
LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
=============================================================================*/ | |
#if !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED) | |
#define INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED | |
#include <boost/wave/wave_config.hpp> | |
#include <boost/wave/token_ids.hpp> | |
// this must occur after all of the includes and before any code appears | |
#ifdef BOOST_HAS_ABI_HEADERS | |
#include BOOST_ABI_PREFIX | |
#endif | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { | |
namespace wave { | |
namespace util { | |
namespace impl { | |
// T_IDENTIFIER | |
template <typename StringT> | |
inline bool | |
would_form_universal_char (StringT const &value) | |
{ | |
if ('u' != value[0] && 'U' != value[0]) | |
return false; | |
if ('u' == value[0] && value.size() < 5) | |
return false; | |
if ('U' == value[0] && value.size() < 9) | |
return false; | |
typename StringT::size_type pos = | |
value.find_first_not_of("0123456789abcdefABCDEF", 1); | |
if (StringT::npos == pos || | |
('u' == value[0] && pos > 5) || | |
('U' == value[0] && pos > 9)) | |
{ | |
return true; // would form an universal char | |
} | |
return false; | |
} | |
template <typename StringT> | |
inline bool | |
handle_identifier(boost::wave::token_id prev, | |
boost::wave::token_id before, StringT const &value) | |
{ | |
using namespace boost::wave; | |
switch (static_cast<unsigned int>(prev)) { | |
case T_IDENTIFIER: | |
case T_NONREPLACABLE_IDENTIFIER: | |
case T_COMPL_ALT: | |
case T_OR_ALT: | |
case T_AND_ALT: | |
case T_NOT_ALT: | |
case T_XOR_ALT: | |
case T_ANDASSIGN_ALT: | |
case T_ORASSIGN_ALT: | |
case T_XORASSIGN_ALT: | |
case T_NOTEQUAL_ALT: | |
case T_FIXEDPOINTLIT: | |
return true; | |
case T_FLOATLIT: | |
case T_INTLIT: | |
case T_PP_NUMBER: | |
return (value.size() > 1 || (value[0] != 'e' && value[0] != 'E')); | |
// avoid constructing universal characters (\u1234) | |
case TOKEN_FROM_ID('\\', UnknownTokenType): | |
return would_form_universal_char(value); | |
} | |
return false; | |
} | |
// T_INTLIT | |
inline bool | |
handle_intlit(boost::wave::token_id prev, boost::wave::token_id /*before*/) | |
{ | |
using namespace boost::wave; | |
switch (static_cast<unsigned int>(prev)) { | |
case T_IDENTIFIER: | |
case T_NONREPLACABLE_IDENTIFIER: | |
case T_INTLIT: | |
case T_FLOATLIT: | |
case T_FIXEDPOINTLIT: | |
case T_PP_NUMBER: | |
return true; | |
} | |
return false; | |
} | |
// T_FLOATLIT | |
inline bool | |
handle_floatlit(boost::wave::token_id prev, | |
boost::wave::token_id /*before*/) | |
{ | |
using namespace boost::wave; | |
switch (static_cast<unsigned int>(prev)) { | |
case T_IDENTIFIER: | |
case T_NONREPLACABLE_IDENTIFIER: | |
case T_INTLIT: | |
case T_FLOATLIT: | |
case T_FIXEDPOINTLIT: | |
case T_PP_NUMBER: | |
return true; | |
} | |
return false; | |
} | |
// <% T_LEFTBRACE | |
inline bool | |
handle_alt_leftbrace(boost::wave::token_id prev, | |
boost::wave::token_id /*before*/) | |
{ | |
using namespace boost::wave; | |
switch (static_cast<unsigned int>(prev)) { | |
case T_LESS: // <<% | |
case T_SHIFTLEFT: // <<<% | |
return true; | |
} | |
return false; | |
} | |
// <: T_LEFTBRACKET | |
inline bool | |
handle_alt_leftbracket(boost::wave::token_id prev, | |
boost::wave::token_id /*before*/) | |
{ | |
using namespace boost::wave; | |
switch (static_cast<unsigned int>(prev)) { | |
case T_LESS: // <<: | |
case T_SHIFTLEFT: // <<<: | |
return true; | |
} | |
return false; | |
} | |
// T_FIXEDPOINTLIT | |
inline bool | |
handle_fixedpointlit(boost::wave::token_id prev, | |
boost::wave::token_id /*before*/) | |
{ | |
using namespace boost::wave; | |
switch (static_cast<unsigned int>(prev)) { | |
case T_IDENTIFIER: | |
case T_NONREPLACABLE_IDENTIFIER: | |
case T_INTLIT: | |
case T_FLOATLIT: | |
case T_FIXEDPOINTLIT: | |
case T_PP_NUMBER: | |
return true; | |
} | |
return false; | |
} | |
// T_DOT | |
inline bool | |
handle_dot(boost::wave::token_id prev, boost::wave::token_id before) | |
{ | |
using namespace boost::wave; | |
switch (static_cast<unsigned int>(prev)) { | |
case T_DOT: | |
if (T_DOT == before) | |
return true; // ... | |
break; | |
} | |
return false; | |
} | |
// T_QUESTION_MARK | |
inline bool | |
handle_questionmark(boost::wave::token_id prev, | |
boost::wave::token_id /*before*/) | |
{ | |
using namespace boost::wave; | |
switch(static_cast<unsigned int>(prev)) { | |
case TOKEN_FROM_ID('\\', UnknownTokenType): // \? | |
case T_QUESTION_MARK: // ?? | |
return true; | |
} | |
return false; | |
} | |
// T_NEWLINE | |
inline bool | |
handle_newline(boost::wave::token_id prev, | |
boost::wave::token_id before) | |
{ | |
using namespace boost::wave; | |
switch(static_cast<unsigned int>(prev)) { | |
case TOKEN_FROM_ID('\\', UnknownTokenType): // \ \n | |
case T_DIVIDE: | |
if (T_QUESTION_MARK == before) | |
return true; // ?/\n // may be \\n | |
break; | |
} | |
return false; | |
} | |
inline bool | |
handle_parens(boost::wave::token_id prev) | |
{ | |
switch (static_cast<unsigned int>(prev)) { | |
case T_LEFTPAREN: | |
case T_RIGHTPAREN: | |
case T_LEFTBRACKET: | |
case T_RIGHTBRACKET: | |
case T_LEFTBRACE: | |
case T_RIGHTBRACE: | |
case T_SEMICOLON: | |
case T_COMMA: | |
case T_COLON: | |
// no insertion between parens/brackets/braces and operators | |
return false; | |
default: | |
break; | |
} | |
return true; | |
} | |
} // namespace impl | |
class insert_whitespace_detection | |
{ | |
public: | |
insert_whitespace_detection(bool insert_whitespace_ = true) | |
: insert_whitespace(insert_whitespace_), | |
prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF) | |
{} | |
template <typename StringT> | |
bool must_insert(boost::wave::token_id current, StringT const &value) | |
{ | |
if (!insert_whitespace) | |
return false; // skip whitespace insertion alltogether | |
using namespace boost::wave; | |
switch (static_cast<unsigned int>(current)) { | |
case T_NONREPLACABLE_IDENTIFIER: | |
case T_IDENTIFIER: | |
return impl::handle_identifier(prev, beforeprev, value); | |
case T_PP_NUMBER: | |
case T_INTLIT: | |
return impl::handle_intlit(prev, beforeprev); | |
case T_FLOATLIT: | |
return impl::handle_floatlit(prev, beforeprev); | |
case T_STRINGLIT: | |
if (TOKEN_FROM_ID('L', IdentifierTokenType) == prev) // 'L' | |
return true; | |
break; | |
case T_LEFTBRACE_ALT: | |
return impl::handle_alt_leftbrace(prev, beforeprev); | |
case T_LEFTBRACKET_ALT: | |
return impl::handle_alt_leftbracket(prev, beforeprev); | |
case T_FIXEDPOINTLIT: | |
return impl::handle_fixedpointlit(prev, beforeprev); | |
case T_DOT: | |
return impl::handle_dot(prev, beforeprev); | |
case T_QUESTION_MARK: | |
return impl::handle_questionmark(prev, beforeprev); | |
case T_NEWLINE: | |
return impl::handle_newline(prev, beforeprev); | |
case T_LEFTPAREN: | |
case T_RIGHTPAREN: | |
case T_LEFTBRACKET: | |
case T_RIGHTBRACKET: | |
case T_SEMICOLON: | |
case T_COMMA: | |
case T_COLON: | |
switch (static_cast<unsigned int>(prev)) { | |
case T_LEFTPAREN: | |
case T_RIGHTPAREN: | |
case T_LEFTBRACKET: | |
case T_RIGHTBRACKET: | |
case T_LEFTBRACE: | |
case T_RIGHTBRACE: | |
return false; // no insertion between parens/brackets/braces | |
default: | |
if (IS_CATEGORY(prev, OperatorTokenType)) | |
return false; | |
break; | |
} | |
break; | |
case T_LEFTBRACE: | |
case T_RIGHTBRACE: | |
switch (static_cast<unsigned int>(prev)) { | |
case T_LEFTPAREN: | |
case T_RIGHTPAREN: | |
case T_LEFTBRACKET: | |
case T_RIGHTBRACKET: | |
case T_LEFTBRACE: | |
case T_RIGHTBRACE: | |
case T_SEMICOLON: | |
case T_COMMA: | |
case T_COLON: | |
return false; // no insertion between parens/brackets/braces | |
case T_QUESTION_MARK: | |
if (T_QUESTION_MARK == beforeprev) | |
return true; | |
if (IS_CATEGORY(prev, OperatorTokenType)) | |
return false; | |
break; | |
default: | |
break; | |
} | |
break; | |
case T_MINUS: | |
case T_MINUSMINUS: | |
case T_MINUSASSIGN: | |
if (T_MINUS == prev || T_MINUSMINUS == prev) | |
return true; | |
if (!impl::handle_parens(prev)) | |
return false; | |
if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) | |
return true; | |
break; | |
case T_PLUS: | |
case T_PLUSPLUS: | |
case T_PLUSASSIGN: | |
if (T_PLUS == prev || T_PLUSPLUS == prev) | |
return true; | |
if (!impl::handle_parens(prev)) | |
return false; | |
if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) | |
return true; | |
break; | |
case T_DIVIDE: | |
case T_DIVIDEASSIGN: | |
if (T_DIVIDE == prev) | |
return true; | |
if (!impl::handle_parens(prev)) | |
return false; | |
if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) | |
return true; | |
break; | |
case T_EQUAL: | |
case T_ASSIGN: | |
switch (static_cast<unsigned int>(prev)) { | |
case T_PLUSASSIGN: | |
case T_MINUSASSIGN: | |
case T_DIVIDEASSIGN: | |
case T_STARASSIGN: | |
case T_SHIFTRIGHTASSIGN: | |
case T_SHIFTLEFTASSIGN: | |
case T_EQUAL: | |
case T_NOTEQUAL: | |
case T_LESSEQUAL: | |
case T_GREATEREQUAL: | |
case T_LESS: | |
case T_GREATER: | |
case T_PLUS: | |
case T_MINUS: | |
case T_STAR: | |
case T_DIVIDE: | |
case T_ORASSIGN: | |
case T_ANDASSIGN: | |
case T_XORASSIGN: | |
case T_OR: | |
case T_AND: | |
case T_XOR: | |
case T_OROR: | |
case T_ANDAND: | |
return true; | |
case T_QUESTION_MARK: | |
if (T_QUESTION_MARK == beforeprev) | |
return true; | |
break; | |
default: | |
if (!impl::handle_parens(prev)) | |
return false; | |
break; | |
} | |
break; | |
case T_GREATER: | |
if (T_MINUS == prev || T_GREATER == prev) | |
return true; // prevent -> or >> | |
if (!impl::handle_parens(prev)) | |
return false; | |
if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) | |
return true; | |
break; | |
case T_LESS: | |
if (T_LESS == prev) | |
return true; // prevent << | |
// fall through | |
case T_CHARLIT: | |
case T_NOT: | |
case T_NOTEQUAL: | |
if (!impl::handle_parens(prev)) | |
return false; | |
if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) | |
return true; | |
break; | |
case T_AND: | |
case T_ANDAND: | |
if (!impl::handle_parens(prev)) | |
return false; | |
if (T_AND == prev || T_ANDAND == prev) | |
return true; | |
break; | |
case T_OR: | |
if (!impl::handle_parens(prev)) | |
return false; | |
if (T_OR == prev) | |
return true; | |
break; | |
case T_XOR: | |
if (!impl::handle_parens(prev)) | |
return false; | |
if (T_XOR == prev) | |
return true; | |
break; | |
case T_COMPL_ALT: | |
case T_OR_ALT: | |
case T_AND_ALT: | |
case T_NOT_ALT: | |
case T_XOR_ALT: | |
case T_ANDASSIGN_ALT: | |
case T_ORASSIGN_ALT: | |
case T_XORASSIGN_ALT: | |
case T_NOTEQUAL_ALT: | |
switch (static_cast<unsigned int>(prev)) { | |
case T_LEFTPAREN: | |
case T_RIGHTPAREN: | |
case T_LEFTBRACKET: | |
case T_RIGHTBRACKET: | |
case T_LEFTBRACE: | |
case T_RIGHTBRACE: | |
case T_SEMICOLON: | |
case T_COMMA: | |
case T_COLON: | |
// no insertion between parens/brackets/braces and operators | |
return false; | |
case T_IDENTIFIER: | |
if (T_NONREPLACABLE_IDENTIFIER == prev || | |
IS_CATEGORY(prev, KeywordTokenType)) | |
{ | |
return true; | |
} | |
break; | |
default: | |
break; | |
} | |
break; | |
case T_STAR: | |
if (T_STAR == prev) | |
return false; // '*****' do not need to be separated | |
if (T_GREATER== prev && | |
(T_MINUS == beforeprev || T_MINUSMINUS == beforeprev) | |
) | |
{ | |
return true; // prevent ->* | |
} | |
break; | |
case T_POUND: | |
if (T_POUND == prev) | |
return true; | |
break; | |
} | |
// FIXME: else, handle operators separately (will catch to many cases) | |
// if (IS_CATEGORY(current, OperatorTokenType) && | |
// IS_CATEGORY(prev, OperatorTokenType)) | |
// { | |
// return true; // operators must be delimited always | |
// } | |
return false; | |
} | |
void shift_tokens (boost::wave::token_id next_id) | |
{ | |
if (insert_whitespace) { | |
beforeprev = prev; | |
prev = next_id; | |
} | |
} | |
private: | |
bool insert_whitespace; // enable this component | |
boost::wave::token_id prev; // the previous analyzed token | |
boost::wave::token_id beforeprev; // the token before the previous | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
} // namespace util | |
} // namespace wave | |
} // namespace boost | |
// the suffix header occurs after all of the code | |
#ifdef BOOST_HAS_ABI_HEADERS | |
#include BOOST_ABI_SUFFIX | |
#endif | |
#endif // !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED) |