macro_helpers.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*=============================================================================
  2. Boost.Wave: A Standard compliant C++ preprocessor library
  3. http://www.boost.org/
  4. Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
  5. Software License, Version 1.0. (See accompanying file
  6. LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #if !defined(BOOST_MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED)
  9. #define BOOST_MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED
  10. #include <vector>
  11. #include <boost/assert.hpp>
  12. #include <boost/wave/wave_config.hpp>
  13. #include <boost/wave/token_ids.hpp>
  14. #include <boost/wave/cpplexer/validate_universal_char.hpp>
  15. #include <boost/wave/util/unput_queue_iterator.hpp>
  16. // this must occur after all of the includes and before any code appears
  17. #ifdef BOOST_HAS_ABI_HEADERS
  18. #include BOOST_ABI_PREFIX
  19. #endif
  20. ///////////////////////////////////////////////////////////////////////////////
  21. namespace boost {
  22. namespace wave {
  23. namespace util {
  24. namespace impl {
  25. // escape a string literal (insert '\\' before every '\"', '?' and '\\')
  26. template <typename StringT>
  27. inline StringT
  28. escape_lit(StringT const &value)
  29. {
  30. StringT result;
  31. typename StringT::size_type pos = 0;
  32. typename StringT::size_type pos1 = value.find_first_of ("\"\\?", 0);
  33. if (StringT::npos != pos1) {
  34. do {
  35. result += value.substr(pos, pos1-pos)
  36. + StringT("\\")
  37. + StringT(1, value[pos1]);
  38. pos1 = value.find_first_of ("\"\\?", pos = pos1+1);
  39. } while (StringT::npos != pos1);
  40. result += value.substr(pos);
  41. }
  42. else {
  43. result = value;
  44. }
  45. return result;
  46. }
  47. // un-escape a string literal (remove '\\' just before '\\', '\"' or '?')
  48. template <typename StringT>
  49. inline StringT
  50. unescape_lit(StringT const &value)
  51. {
  52. StringT result;
  53. typename StringT::size_type pos = 0;
  54. typename StringT::size_type pos1 = value.find_first_of ("\\", 0);
  55. if (StringT::npos != pos1) {
  56. do {
  57. switch (value[pos1+1]) {
  58. case '\\':
  59. case '\"':
  60. case '?':
  61. result = result + value.substr(pos, pos1-pos);
  62. pos1 = value.find_first_of ("\\", (pos = pos1+1)+1);
  63. break;
  64. case 'n':
  65. result = result + value.substr(pos, pos1-pos) + "\n";
  66. pos1 = value.find_first_of ("\\", pos = pos1+1);
  67. ++pos;
  68. break;
  69. default:
  70. result = result + value.substr(pos, pos1-pos+1);
  71. pos1 = value.find_first_of ("\\", pos = pos1+1);
  72. }
  73. } while (pos1 != StringT::npos);
  74. result = result + value.substr(pos);
  75. }
  76. else {
  77. // the string doesn't contain any escaped character sequences
  78. result = value;
  79. }
  80. return result;
  81. }
  82. // return the string representation of a token sequence
  83. template <typename ContainerT, typename PositionT>
  84. inline typename ContainerT::value_type::string_type
  85. as_stringlit (ContainerT const &token_sequence, PositionT const &pos)
  86. {
  87. using namespace boost::wave;
  88. typedef typename ContainerT::value_type::string_type string_type;
  89. string_type result("\"");
  90. bool was_whitespace = false;
  91. typename ContainerT::const_iterator end = token_sequence.end();
  92. for (typename ContainerT::const_iterator it = token_sequence.begin();
  93. it != end; ++it)
  94. {
  95. token_id id = token_id(*it);
  96. if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) {
  97. if (!was_whitespace) {
  98. // C++ standard 16.3.2.2 [cpp.stringize]
  99. // Each occurrence of white space between the argument's
  100. // preprocessing tokens becomes a single space character in the
  101. // character string literal.
  102. result += " ";
  103. was_whitespace = true;
  104. }
  105. }
  106. else if (T_STRINGLIT == id || T_CHARLIT == id) {
  107. // string literals and character literals have to be escaped
  108. result += impl::escape_lit((*it).get_value());
  109. was_whitespace = false;
  110. }
  111. else
  112. #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
  113. if (T_PLACEMARKER != id)
  114. #endif
  115. {
  116. // now append this token to the string
  117. result += (*it).get_value();
  118. was_whitespace = false;
  119. }
  120. }
  121. result += "\"";
  122. // validate the resulting literal to contain no invalid universal character
  123. // value (throws if invalid chars found)
  124. boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(),
  125. pos.get_column(), pos.get_file());
  126. return result;
  127. }
  128. #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
  129. // return the string representation of a token sequence
  130. template <typename ContainerT, typename PositionT>
  131. inline typename ContainerT::value_type::string_type
  132. as_stringlit (std::vector<ContainerT> const &arguments,
  133. typename std::vector<ContainerT>::size_type i, PositionT const &pos)
  134. {
  135. using namespace boost::wave;
  136. typedef typename ContainerT::value_type::string_type string_type;
  137. BOOST_ASSERT(i < arguments.size());
  138. string_type result("\"");
  139. bool was_whitespace = false;
  140. for (/**/; i < arguments.size(); ++i) {
  141. // stringize all remaining arguments
  142. typename ContainerT::const_iterator end = arguments[i].end();
  143. for (typename ContainerT::const_iterator it = arguments[i].begin();
  144. it != end; ++it)
  145. {
  146. token_id id = token_id(*it);
  147. if (IS_CATEGORY(*it, WhiteSpaceTokenType) || T_NEWLINE == id) {
  148. if (!was_whitespace) {
  149. // C++ standard 16.3.2.2 [cpp.stringize]
  150. // Each occurrence of white space between the argument's
  151. // preprocessing tokens becomes a single space character in the
  152. // character string literal.
  153. result += " ";
  154. was_whitespace = true;
  155. }
  156. }
  157. else if (T_STRINGLIT == id || T_CHARLIT == id) {
  158. // string literals and character literals have to be escaped
  159. result += impl::escape_lit((*it).get_value());
  160. was_whitespace = false;
  161. }
  162. else if (T_PLACEMARKER != id) {
  163. // now append this token to the string
  164. result += (*it).get_value();
  165. was_whitespace = false;
  166. }
  167. }
  168. // append comma, if not last argument
  169. if (i < arguments.size()-1) {
  170. result += ",";
  171. was_whitespace = false;
  172. }
  173. }
  174. result += "\"";
  175. // validate the resulting literal to contain no invalid universal character
  176. // value (throws if invalid chars found)
  177. boost::wave::cpplexer::impl::validate_literal(result, pos.get_line(),
  178. pos.get_column(), pos.get_file());
  179. return result;
  180. }
  181. #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
  182. // return the string representation of a token sequence
  183. template <typename StringT, typename IteratorT>
  184. inline StringT
  185. as_string(IteratorT it, IteratorT const& end)
  186. {
  187. StringT result;
  188. for (/**/; it != end; ++it)
  189. {
  190. result += (*it).get_value();
  191. }
  192. return result;
  193. }
  194. // return the string representation of a token sequence
  195. template <typename ContainerT>
  196. inline typename ContainerT::value_type::string_type
  197. as_string (ContainerT const &token_sequence)
  198. {
  199. typedef typename ContainerT::value_type::string_type string_type;
  200. return as_string<string_type>(token_sequence.begin(),
  201. token_sequence.end());
  202. }
  203. #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
  204. ///////////////////////////////////////////////////////////////////////////
  205. //
  206. // Copies all arguments beginning with the given index to the output
  207. // sequence. The arguments are separated by commas.
  208. //
  209. template <typename ContainerT, typename PositionT>
  210. void replace_ellipsis (std::vector<ContainerT> const &arguments,
  211. typename ContainerT::size_type index,
  212. ContainerT &expanded, PositionT const &pos)
  213. {
  214. using namespace cpplexer;
  215. typedef typename ContainerT::value_type token_type;
  216. token_type comma(T_COMMA, ",", pos);
  217. for (/**/; index < arguments.size(); ++index) {
  218. ContainerT const &arg = arguments[index];
  219. std::copy(arg.begin(), arg.end(),
  220. std::inserter(expanded, expanded.end()));
  221. if (index < arguments.size()-1)
  222. expanded.push_back(comma);
  223. }
  224. }
  225. #if BOOST_WAVE_SUPPORT_VA_OPT != 0
  226. ///////////////////////////////////////////////////////////////////////////
  227. //
  228. // Finds the token range inside __VA_OPT__.
  229. // Updates mdit to the position of the final rparen.
  230. // If the parenthesis do not match up, or there are none, returns false
  231. // and leaves mdit unchanged.
  232. //
  233. template <typename MDefIterT>
  234. bool find_va_opt_args (
  235. MDefIterT & mdit, // VA_OPT
  236. MDefIterT mdend)
  237. {
  238. if ((std::distance(mdit, mdend) < 3) ||
  239. (T_LEFTPAREN != next_token<MDefIterT>::peek(mdit, mdend))) {
  240. return false;
  241. }
  242. MDefIterT mdstart_it = mdit;
  243. ++mdit; // skip to lparen
  244. std::size_t scope = 0;
  245. // search for final rparen, leaving iterator there
  246. for (; (mdit != mdend) && !((scope == 1) && (T_RIGHTPAREN == token_id(*mdit)));
  247. ++mdit) {
  248. // count balanced parens
  249. if (T_RIGHTPAREN == token_id(*mdit)) {
  250. scope--;
  251. } else if (T_LEFTPAREN == token_id(*mdit)) {
  252. scope++;
  253. }
  254. }
  255. if ((mdit == mdend) && ((scope != 1) || (T_RIGHTPAREN != token_id(*mdit)))) {
  256. // arrived at end without matching rparen
  257. mdit = mdstart_it;
  258. return false;
  259. }
  260. return true;
  261. }
  262. #endif
  263. #endif
  264. // Skip all whitespace characters and queue the skipped characters into the
  265. // given container
  266. template <typename IteratorT>
  267. inline boost::wave::token_id
  268. skip_whitespace(IteratorT &first, IteratorT const &last)
  269. {
  270. token_id id = util::impl::next_token<IteratorT>::peek(first, last, false);
  271. if (IS_CATEGORY(id, WhiteSpaceTokenType)) {
  272. do {
  273. ++first;
  274. id = util::impl::next_token<IteratorT>::peek(first, last, false);
  275. } while (IS_CATEGORY(id, WhiteSpaceTokenType));
  276. }
  277. ++first;
  278. return id;
  279. }
  280. template <typename IteratorT, typename ContainerT>
  281. inline boost::wave::token_id
  282. skip_whitespace(IteratorT &first, IteratorT const &last, ContainerT &queue)
  283. {
  284. queue.push_back (*first); // queue up the current token
  285. token_id id = util::impl::next_token<IteratorT>::peek(first, last, false);
  286. if (IS_CATEGORY(id, WhiteSpaceTokenType)) {
  287. do {
  288. queue.push_back(*++first); // queue up the next whitespace
  289. id = util::impl::next_token<IteratorT>::peek(first, last, false);
  290. } while (IS_CATEGORY(id, WhiteSpaceTokenType));
  291. }
  292. ++first;
  293. return id;
  294. }
  295. // trim all whitespace from the beginning and the end of the given string
  296. template <typename StringT>
  297. inline StringT
  298. trim_whitespace(StringT const &s)
  299. {
  300. typedef typename StringT::size_type size_type;
  301. size_type first = s.find_first_not_of(" \t\v\f");
  302. if (StringT::npos == first)
  303. return StringT();
  304. size_type last = s.find_last_not_of(" \t\v\f");
  305. return s.substr(first, last-first+1);
  306. }
  307. } // namespace impl
  308. ///////////////////////////////////////////////////////////////////////////////
  309. } // namespace util
  310. } // namespace wave
  311. } // namespace boost
  312. // the suffix header occurs after all of the code
  313. #ifdef BOOST_HAS_ABI_HEADERS
  314. #include BOOST_ABI_SUFFIX
  315. #endif
  316. #endif // !defined(BOOST_MACRO_HELPERS_HPP_931BBC99_EBFA_4692_8FBE_B555998C2C39_INCLUDED)