| /*============================================================================= |
| 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-2010 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) |