/*============================================================================= 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-2012 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 #include // 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 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 inline bool handle_identifier(boost::wave::token_id prev, boost::wave::token_id before, StringT const &value) { using namespace boost::wave; switch (static_cast(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(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(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(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(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(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(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(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(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(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 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(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(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(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(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(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)