Chris@16: /*============================================================================= Chris@16: Boost.Wave: A Standard compliant C++ preprocessor library Chris@16: Whitespace eater Chris@16: Chris@16: http://www.boost.org/ Chris@16: Chris@16: Copyright (c) 2003 Paul Mensonides Chris@16: Copyright (c) 2001-2012 Hartmut Kaiser. Chris@16: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: =============================================================================*/ Chris@16: Chris@16: #if !defined(WHITESPACE_HANDLING_HPP_INCLUDED) Chris@16: #define WHITESPACE_HANDLING_HPP_INCLUDED Chris@16: 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 context_policies { Chris@16: Chris@16: namespace util { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // This function returns true if the given C style comment contains at Chris@16: // least one newline Chris@16: template Chris@16: bool ccomment_has_newline(TokenT const& token) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: if (T_CCOMMENT == token_id(token) && Chris@16: TokenT::string_type::npos != token.get_value().find_first_of("\n")) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // This function returns the number of newlines in the given C style Chris@16: // comment Chris@16: template Chris@16: int ccomment_count_newlines(TokenT const& token) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: int newlines = 0; Chris@16: if (T_CCOMMENT == token_id(token)) { Chris@16: typename TokenT::string_type const& value = token.get_value(); Chris@16: typename TokenT::string_type::size_type p = value.find_first_of("\n"); Chris@16: Chris@16: while (TokenT::string_type::npos != p) { Chris@16: ++newlines; Chris@16: p = value.find_first_of("\n", p+1); Chris@16: } Chris@16: } Chris@16: return newlines; Chris@16: } Chris@16: Chris@16: #if BOOST_WAVE_SUPPORT_CPP0X != 0 Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // This function returns the number of newlines in the given C++11 style Chris@16: // raw string Chris@16: template Chris@16: int rawstring_count_newlines(TokenT const& token) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: int newlines = 0; Chris@16: if (T_RAWSTRINGLIT == token_id(token)) { Chris@16: typename TokenT::string_type const& value = token.get_value(); Chris@16: typename TokenT::string_type::size_type p = value.find_first_of("\n"); Chris@16: Chris@16: while (TokenT::string_type::npos != p) { Chris@16: ++newlines; Chris@16: p = value.find_first_of("\n", p+1); Chris@16: } Chris@16: } Chris@16: return newlines; Chris@16: } Chris@16: #endif Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: class eat_whitespace Chris@16: : public default_preprocessing_hooks Chris@16: { Chris@16: public: Chris@16: eat_whitespace(); Chris@16: Chris@16: template Chris@16: bool may_skip_whitespace(ContextT const& ctx, TokenT &token, Chris@16: bool &skipped_newline); Chris@16: template Chris@16: bool may_skip_whitespace(ContextT const& ctx, TokenT &token, Chris@16: bool preserve_comments_, bool preserve_bol_whitespace_, Chris@16: bool &skipped_newline); Chris@16: Chris@16: protected: Chris@16: bool skip_cppcomment(boost::wave::token_id id) Chris@16: { Chris@16: return !preserve_comments && T_CPPCOMMENT == id; Chris@16: } Chris@16: Chris@16: private: Chris@16: typedef bool state_t(TokenT &token, bool &skipped_newline); Chris@16: state_t eat_whitespace::* state; Chris@16: state_t general, newline, newline_2nd, whitespace, bol_whitespace; Chris@16: bool preserve_comments; Chris@16: bool preserve_bol_whitespace; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline Chris@16: eat_whitespace::eat_whitespace() Chris@16: : state(&eat_whitespace::newline), preserve_comments(false), Chris@16: preserve_bol_whitespace(false) Chris@16: { Chris@16: } Chris@16: Chris@16: template Chris@16: template Chris@16: inline bool Chris@16: eat_whitespace::may_skip_whitespace(ContextT const& ctx, TokenT &token, Chris@16: bool &skipped_newline) Chris@16: { Chris@16: // re-initialize the preserve comments state Chris@16: preserve_comments = boost::wave::need_preserve_comments(ctx.get_language()); Chris@16: return (this->*state)(token, skipped_newline); Chris@16: } Chris@16: Chris@16: template Chris@16: template Chris@16: inline bool Chris@16: eat_whitespace::may_skip_whitespace(ContextT const& ctx, TokenT &token, Chris@16: bool preserve_comments_, bool preserve_bol_whitespace_, Chris@16: bool &skipped_newline) Chris@16: { Chris@16: // re-initialize the preserve comments state Chris@16: preserve_comments = preserve_comments_; Chris@16: preserve_bol_whitespace = preserve_bol_whitespace_; Chris@16: return (this->*state)(token, skipped_newline); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool Chris@16: eat_whitespace::general(TokenT &token, bool &skipped_newline) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: token_id id = token_id(token); Chris@16: if (T_NEWLINE == id || T_CPPCOMMENT == id) { Chris@16: state = &eat_whitespace::newline; Chris@16: } Chris@16: else if (T_SPACE == id || T_SPACE2 == id || T_CCOMMENT == id) { Chris@16: state = &eat_whitespace::whitespace; Chris@16: Chris@16: if (util::ccomment_has_newline(token)) Chris@16: skipped_newline = true; Chris@16: Chris@16: if ((!preserve_comments || T_CCOMMENT != id) && Chris@16: token.get_value().size() > 1) Chris@16: { Chris@16: token.set_value(" "); // replace with a single space Chris@16: } Chris@16: } Chris@16: else { Chris@16: state = &eat_whitespace::general; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool Chris@16: eat_whitespace::newline(TokenT &token, bool &skipped_newline) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: token_id id = token_id(token); Chris@16: if (T_NEWLINE == id || T_CPPCOMMENT == id) { Chris@16: skipped_newline = true; Chris@16: state = &eat_whitespace::newline_2nd; Chris@16: return T_NEWLINE == id || skip_cppcomment(id); Chris@16: } Chris@16: Chris@16: if (T_SPACE != id && T_SPACE2 != id && T_CCOMMENT != id) Chris@16: return general(token, skipped_newline); Chris@16: Chris@16: if (T_CCOMMENT == id) { Chris@16: if (util::ccomment_has_newline(token)) { Chris@16: skipped_newline = true; Chris@16: state = &eat_whitespace::newline_2nd; Chris@16: } Chris@16: if (preserve_comments) { Chris@16: state = &eat_whitespace::general; Chris@16: return false; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: if (preserve_bol_whitespace) { Chris@16: state = &eat_whitespace::bol_whitespace; Chris@16: return false; Chris@16: } Chris@16: Chris@16: return true; Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool Chris@16: eat_whitespace::newline_2nd(TokenT &token, bool &skipped_newline) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: token_id id = token_id(token); Chris@16: if (T_SPACE == id || T_SPACE2 == id) { Chris@16: if (preserve_bol_whitespace) { Chris@16: state = &eat_whitespace::bol_whitespace; Chris@16: return false; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: if (T_CCOMMENT == id) { Chris@16: if (util::ccomment_has_newline(token)) Chris@16: skipped_newline = true; Chris@16: Chris@16: if (preserve_comments) { Chris@16: state = &eat_whitespace::general; Chris@16: return false; Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: if (T_NEWLINE != id && T_CPPCOMMENT != id) Chris@16: return general(token, skipped_newline); Chris@16: Chris@16: skipped_newline = true; Chris@16: return T_NEWLINE == id || skip_cppcomment(id); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool Chris@16: eat_whitespace::bol_whitespace(TokenT &token, bool &skipped_newline) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: token_id id = token_id(token); Chris@16: if (T_SPACE == id || T_SPACE2 == id) Chris@16: return !preserve_bol_whitespace; Chris@16: Chris@16: return general(token, skipped_newline); Chris@16: } Chris@16: Chris@16: template Chris@16: inline bool Chris@16: eat_whitespace::whitespace(TokenT &token, bool &skipped_newline) Chris@16: { Chris@16: using namespace boost::wave; Chris@16: Chris@16: token_id id = token_id(token); Chris@16: if (T_SPACE != id && T_SPACE2 != id && Chris@16: T_CCOMMENT != id && T_CPPCOMMENT != id) Chris@16: { Chris@16: return general(token, skipped_newline); Chris@16: } Chris@16: Chris@16: if (T_CCOMMENT == id) { Chris@16: if (util::ccomment_has_newline(token)) Chris@16: skipped_newline = true; Chris@16: return !preserve_comments; Chris@16: } Chris@16: Chris@16: return T_SPACE == id || T_SPACE2 == id || skip_cppcomment(id); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: } // namespace context_policies 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(WHITESPACE_HANDLING_HPP_INCLUDED) Chris@16: