You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
518 lines
15 KiB
518 lines
15 KiB
/*============================================================================= |
|
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)
|
|
|