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