Chris@16: /*============================================================================= Chris@16: Boost.Wave: A Standard compliant C++ preprocessor library 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: Chris@16: #if !defined(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED) Chris@16: #define MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED Chris@16: Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include 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: // escape a string literal (insert '\\' before every '\"', '?' and '\\') Chris@16: template Chris@16: inline StringT Chris@16: escape_lit(StringT const &value) Chris@16: { Chris@16: StringT result; Chris@16: typename StringT::size_type pos = 0; Chris@16: typename StringT::size_type pos1 = value.find_first_of ("\"\\?", 0); Chris@16: if (StringT::npos != pos1) { Chris@16: do { Chris@16: result += value.substr(pos, pos1-pos) Chris@16: + StringT("\\") Chris@16: + StringT(1, value[pos1]); Chris@16: pos1 = value.find_first_of ("\"\\?", pos = pos1+1); Chris@16: } while (StringT::npos != pos1); Chris@16: result += value.substr(pos); Chris@16: } Chris@16: else { Chris@16: result = value; Chris@16: } Chris@16: return result; Chris@16: } Chris@16: Chris@16: // un-escape a string literal (remove '\\' just before '\\', '\"' or '?') Chris@16: template Chris@16: inline StringT Chris@16: unescape_lit(StringT const &value) Chris@16: { Chris@16: StringT result; Chris@16: typename StringT::size_type pos = 0; Chris@16: typename StringT::size_type pos1 = value.find_first_of ("\\", 0); Chris@16: if (StringT::npos != pos1) { Chris@16: do { Chris@16: switch (value[pos1+1]) { Chris@16: case '\\': Chris@16: case '\"': Chris@16: case '?': Chris@16: result = result + value.substr(pos, pos1-pos); Chris@16: pos1 = value.find_first_of ("\\", (pos = pos1+1)+1); Chris@16: break; Chris@16: Chris@16: case 'n': Chris@16: result = result + value.substr(pos, pos1-pos) + "\n"; Chris@16: pos1 = value.find_first_of ("\\", pos = pos1+1); Chris@16: ++pos; Chris@16: break; Chris@16: Chris@16: default: Chris@16: result = result + value.substr(pos, pos1-pos+1); Chris@16: pos1 = value.find_first_of ("\\", pos = pos1+1); Chris@16: } Chris@16: Chris@16: } while (pos1 != StringT::npos); Chris@16: result = result + value.substr(pos); Chris@16: } Chris@16: else { Chris@16: // the string doesn't contain any escaped character sequences Chris@16: result = value; Chris@16: } Chris@16: return result; Chris@16: } Chris@16: Chris@16: // return the string representation of a token sequence Chris@16: template Chris@16: inline typename ContainerT::value_type::string_type Chris@16: as_stringlit (ContainerT const &token_sequence, PositionT const &pos) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: typedef typename ContainerT::value_type::string_type string_type; Chris@16: Chris@16: string_type result("\""); Chris@16: bool was_whitespace = false; Chris@16: typename ContainerT::const_iterator end = token_sequence.end(); Chris@16: for (typename ContainerT::const_iterator it = token_sequence.begin(); Chris@16: it != end; ++it) Chris@16: { Chris@16: token_id id = token_id(*it); Chris@16: Chris@16: if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) { Chris@16: if (!was_whitespace) { Chris@16: // C++ standard 16.3.2.2 [cpp.stringize] Chris@16: // Each occurrence of white space between the argument's Chris@16: // preprocessing tokens becomes a single space character in the Chris@16: // character string literal. Chris@16: result += " "; Chris@16: was_whitespace = true; Chris@16: } Chris@16: } Chris@16: else if (T_STRINGLIT == id || T_CHARLIT == id) { Chris@16: // string literals and character literals have to be escaped Chris@16: result += impl::escape_lit((*it).get_value()); Chris@16: was_whitespace = false; Chris@16: } Chris@16: else Chris@16: #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 Chris@16: if (T_PLACEMARKER != id) Chris@16: #endif Chris@16: { Chris@16: // now append this token to the string Chris@16: result += (*it).get_value(); Chris@16: was_whitespace = false; Chris@16: } Chris@16: } Chris@16: result += "\""; Chris@16: Chris@16: // validate the resulting literal to contain no invalid universal character Chris@16: // value (throws if invalid chars found) Chris@16: boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(), Chris@16: pos.get_column(), pos.get_file()); Chris@16: return result; Chris@16: } Chris@16: Chris@16: #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 Chris@16: // return the string representation of a token sequence Chris@16: template Chris@16: inline typename ContainerT::value_type::string_type Chris@16: as_stringlit (std::vector const &arguments, Chris@16: typename std::vector::size_type i, PositionT const &pos) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: typedef typename ContainerT::value_type::string_type string_type; Chris@16: Chris@16: BOOST_ASSERT(i < arguments.size()); Chris@16: Chris@16: string_type result("\""); Chris@16: bool was_whitespace = false; Chris@16: Chris@16: for (/**/; i < arguments.size(); ++i) { Chris@16: // stringize all remaining arguments Chris@16: typename ContainerT::const_iterator end = arguments[i].end(); Chris@16: for (typename ContainerT::const_iterator it = arguments[i].begin(); Chris@16: it != end; ++it) Chris@16: { Chris@16: token_id id = token_id(*it); Chris@16: Chris@16: if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) { Chris@16: if (!was_whitespace) { Chris@16: // C++ standard 16.3.2.2 [cpp.stringize] Chris@16: // Each occurrence of white space between the argument's Chris@16: // preprocessing tokens becomes a single space character in the Chris@16: // character string literal. Chris@16: result += " "; Chris@16: was_whitespace = true; Chris@16: } Chris@16: } Chris@16: else if (T_STRINGLIT == id || T_CHARLIT == id) { Chris@16: // string literals and character literals have to be escaped Chris@16: result += impl::escape_lit((*it).get_value()); Chris@16: was_whitespace = false; Chris@16: } Chris@16: else if (T_PLACEMARKER != id) { Chris@16: // now append this token to the string Chris@16: result += (*it).get_value(); Chris@16: was_whitespace = false; Chris@16: } Chris@16: } Chris@16: Chris@16: // append comma, if not last argument Chris@16: if (i < arguments.size()-1) { Chris@16: result += ","; Chris@16: was_whitespace = false; Chris@16: } Chris@16: } Chris@16: result += "\""; Chris@16: Chris@16: // validate the resulting literal to contain no invalid universal character Chris@16: // value (throws if invalid chars found) Chris@16: boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(), Chris@16: pos.get_column(), pos.get_file()); Chris@16: return result; Chris@16: } Chris@16: #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 Chris@16: Chris@16: // return the string representation of a token sequence Chris@16: template Chris@16: inline StringT Chris@16: as_string(IteratorT it, IteratorT const& end) Chris@16: { Chris@16: StringT result; Chris@16: for (/**/; it != end; ++it) Chris@16: { Chris@16: result += (*it).get_value(); Chris@16: } Chris@16: return result; Chris@16: } Chris@16: Chris@16: // return the string representation of a token sequence Chris@16: template Chris@16: inline typename ContainerT::value_type::string_type Chris@16: as_string (ContainerT const &token_sequence) Chris@16: { Chris@16: typedef typename ContainerT::value_type::string_type string_type; Chris@16: return as_string(token_sequence.begin(), Chris@16: token_sequence.end()); Chris@16: } Chris@16: Chris@16: #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Chris@16: // Copies all arguments beginning with the given index to the output Chris@16: // sequence. The arguments are separated by commas. Chris@16: // Chris@16: template Chris@16: void replace_ellipsis (std::vector const &arguments, Chris@16: typename ContainerT::size_type index, Chris@16: ContainerT &expanded, PositionT const &pos) Chris@16: { Chris@16: using namespace cpplexer; Chris@16: typedef typename ContainerT::value_type token_type; Chris@16: Chris@16: token_type comma(T_COMMA, ",", pos); Chris@16: for (/**/; index < arguments.size(); ++index) { Chris@16: ContainerT const &arg = arguments[index]; Chris@16: Chris@16: std::copy(arg.begin(), arg.end(), Chris@16: std::inserter(expanded, expanded.end())); Chris@16: Chris@16: if (index < arguments.size()-1) Chris@16: expanded.push_back(comma); Chris@16: } Chris@16: } Chris@16: #endif Chris@16: Chris@16: // Skip all whitespace characters and queue the skipped characters into the Chris@16: // given container Chris@16: template Chris@16: inline boost::wave::token_id Chris@16: skip_whitespace(IteratorT &first, IteratorT const &last) Chris@16: { Chris@16: token_id id = util::impl::next_token::peek(first, last, false); Chris@16: if (IS_CATEGORY(id, WhiteSpaceTokenType)) { Chris@16: do { Chris@16: ++first; Chris@16: id = util::impl::next_token::peek(first, last, false); Chris@16: } while (IS_CATEGORY(id, WhiteSpaceTokenType)); Chris@16: } Chris@16: ++first; Chris@16: return id; Chris@16: } Chris@16: Chris@16: template Chris@16: inline boost::wave::token_id Chris@16: skip_whitespace(IteratorT &first, IteratorT const &last, ContainerT &queue) Chris@16: { Chris@16: queue.push_back (*first); // queue up the current token Chris@16: Chris@16: token_id id = util::impl::next_token::peek(first, last, false); Chris@16: if (IS_CATEGORY(id, WhiteSpaceTokenType)) { Chris@16: do { Chris@16: queue.push_back(*++first); // queue up the next whitespace Chris@16: id = util::impl::next_token::peek(first, last, false); Chris@16: } while (IS_CATEGORY(id, WhiteSpaceTokenType)); Chris@16: } Chris@16: ++first; Chris@16: return id; Chris@16: } Chris@16: Chris@16: } // namespace impl 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(MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED)