/*============================================================================= 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-2005 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 /////////////////////////////////////////////////////////////////////////////// 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: 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: 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: 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: 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; } } // namespace impl class insert_whitespace_detection { public: insert_whitespace_detection() : prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF) {} template bool must_insert(boost::wave::token_id current, StringT const &value) { using namespace boost::wave; switch (current) { case T_NONREPLACABLE_IDENTIFIER: case T_IDENTIFIER: return impl::handle_identifier(prev, beforeprev, value); 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', UnknownTokenType) == 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: 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; break; default: break; } break; case T_MINUS: case T_MINUSMINUS: case T_LESS: case T_EQUAL: case T_ASSIGN: case T_GREATER: case T_DIVIDE: case T_CHARLIT: case T_NOT: case T_NOTEQUAL: case T_DIVIDEASSIGN: case T_MINUSASSIGN: if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev) return true; // ??{op} 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: if (T_IDENTIFIER == prev || T_NONREPLACABLE_IDENTIFIER == prev || IS_CATEGORY(prev, KeywordTokenType)) return true; break; } // else, handle operators separately 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) { beforeprev = prev; prev = next_id; } private: 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 #endif // !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED)