blob: bfa22aa8b83bfe4eef8c6b62160959b353dfc804 [file] [log] [blame]
/*=============================================================================
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)