cpp_macromap_utils.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /*=============================================================================
  2. Boost.Wave: A Standard compliant C++ preprocessor library
  3. Token sequence analysis and transformation helper functions
  4. http://www.boost.org/
  5. Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
  6. Software License, Version 1.0. (See accompanying file
  7. LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. =============================================================================*/
  9. #if !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119)
  10. #define BOOST_CPP_MACROMAP_UTIL_HPP_HK041119
  11. #include <boost/assert.hpp>
  12. #include <boost/wave/wave_config.hpp>
  13. #include <boost/wave/token_ids.hpp>
  14. #include <boost/wave/util/unput_queue_iterator.hpp>
  15. #include <boost/wave/language_support.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. //
  22. // This file contains the definition of several token sequence analyze
  23. // and transformation utility functions needed during macro handling.
  24. //
  25. ///////////////////////////////////////////////////////////////////////////////
  26. ///////////////////////////////////////////////////////////////////////////////
  27. namespace boost {
  28. namespace wave {
  29. namespace util {
  30. ///////////////////////////////////////////////////////////////////////////////
  31. namespace on_exit {
  32. ///////////////////////////////////////////////////////////////////////////
  33. //
  34. // On destruction pop the first element of the list given as the argument
  35. //
  36. ///////////////////////////////////////////////////////////////////////////
  37. template <typename ContainerT>
  38. class pop_front {
  39. public:
  40. pop_front(ContainerT &list_) : list(list_) {}
  41. ~pop_front() { list.pop_front(); }
  42. private:
  43. ContainerT &list;
  44. };
  45. ///////////////////////////////////////////////////////////////////////////
  46. //
  47. // Append a given list to the list given as argument
  48. // On destruction pop the first element of the list given as argument
  49. //
  50. ///////////////////////////////////////////////////////////////////////////
  51. template <typename ContainerT>
  52. class splice_pop_front {
  53. public:
  54. splice_pop_front(ContainerT &list_, ContainerT &queue)
  55. : list(list_)
  56. {
  57. list.splice(list.end(), queue);
  58. }
  59. ~splice_pop_front() { list.pop_front(); }
  60. private:
  61. ContainerT &list;
  62. };
  63. ///////////////////////////////////////////////////////////////////////////
  64. //
  65. // On destruction reset a referenced value to its initial state
  66. //
  67. ///////////////////////////////////////////////////////////////////////////
  68. template <typename TypeT>
  69. class reset {
  70. public:
  71. reset(TypeT &target_value_, TypeT new_value)
  72. : target_value(target_value_), old_value(target_value_)
  73. {
  74. target_value_ = new_value;
  75. }
  76. ~reset() { target_value = old_value; }
  77. private:
  78. TypeT &target_value;
  79. TypeT old_value;
  80. };
  81. ///////////////////////////////////////////////////////////////////////////
  82. //
  83. // On destruction assign the given iterator back
  84. //
  85. ///////////////////////////////////////////////////////////////////////////
  86. template <typename IteratorT, typename UnputIteratorT>
  87. class assign
  88. {
  89. public:
  90. assign(IteratorT &it_, UnputIteratorT const &uit_)
  91. : it(it_), uit(uit_) {}
  92. ~assign() { it = uit.base(); }
  93. private:
  94. IteratorT &it;
  95. UnputIteratorT const &uit;
  96. };
  97. template <typename IteratorT>
  98. class assign<IteratorT, IteratorT> {
  99. public:
  100. assign(IteratorT &it_, IteratorT const &uit_)
  101. : it(it_), uit(uit_) {}
  102. ~assign() { it = uit; }
  103. private:
  104. IteratorT &it;
  105. IteratorT const &uit;
  106. };
  107. ///////////////////////////////////////////////////////////////////////////////
  108. } // namespace on_exit
  109. ///////////////////////////////////////////////////////////////////////////////
  110. namespace impl {
  111. ///////////////////////////////////////////////////////////////////////////////
  112. //
  113. // Test, whether a given identifier resolves to a predefined name
  114. //
  115. ///////////////////////////////////////////////////////////////////////////////
  116. template <typename ContextT, typename StringT>
  117. inline bool
  118. is_special_macroname (ContextT const & ctx, StringT const &name)
  119. {
  120. if (name.size() < 7)
  121. return false;
  122. if ("defined" == name)
  123. return true;
  124. #if BOOST_WAVE_SUPPORT_HAS_INCLUDE != 0
  125. if (boost::wave::need_has_include(ctx.get_language()) &&
  126. ("__has_include" == name))
  127. return true;
  128. #endif
  129. if ('_' == name[0] && '_' == name[1]) {
  130. StringT str = name.substr(2);
  131. if (str == "cplusplus" || str == "STDC__" ||
  132. str == "TIME__" || str == "DATE__" ||
  133. str == "LINE__" || str == "FILE__" ||
  134. str == "INCLUDE_LEVEL__")
  135. {
  136. return true;
  137. }
  138. }
  139. return false;
  140. }
  141. ///////////////////////////////////////////////////////////////////////////////
  142. //
  143. // Test, whether two tokens are to be considered equal (different sequences
  144. // of whitespace are considered to be equal)
  145. //
  146. ///////////////////////////////////////////////////////////////////////////////
  147. template <typename TokenT>
  148. inline bool
  149. token_equals(TokenT const &left, TokenT const &right)
  150. {
  151. using namespace boost::wave;
  152. if (IS_CATEGORY(left, ParameterTokenType)) {
  153. // if the existing token is of type T_PARAMETERBASE, then the right token
  154. // must be of type T_IDENTIFIER or a keyword
  155. token_id id = token_id(right);
  156. return (T_IDENTIFIER == id ||
  157. IS_CATEGORY(id, KeywordTokenType) ||
  158. IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||
  159. IS_CATEGORY(id, BoolLiteralTokenType)) &&
  160. left.get_value() == right.get_value();
  161. }
  162. // if the left token has whitespace, the value is irrelevant
  163. return token_id(left) == token_id(right) && (
  164. IS_CATEGORY(left, WhiteSpaceTokenType) ||
  165. left.get_value() == right.get_value()
  166. );
  167. }
  168. ///////////////////////////////////////////////////////////////////////////////
  169. //
  170. // Tests, whether two macro definitions are equal
  171. //
  172. ///////////////////////////////////////////////////////////////////////////////
  173. template <typename ContainerT>
  174. inline bool
  175. definition_equals(ContainerT const &definition,
  176. ContainerT const &new_definition)
  177. {
  178. typedef typename ContainerT::const_iterator const_iterator_type;
  179. const_iterator_type first1 = definition.begin();
  180. const_iterator_type last1 = definition.end();
  181. const_iterator_type first2 = new_definition.begin();
  182. const_iterator_type last2 = new_definition.end();
  183. while (first1 != last1 && first2 != last2 && token_equals(*first1, *first2))
  184. {
  185. // skip whitespace, if both sequences have a whitespace next
  186. token_id id1 = next_token<const_iterator_type>::peek(first1, last1, false);
  187. token_id id2 = next_token<const_iterator_type>::peek(first2, last2, false);
  188. if (IS_CATEGORY(id1, WhiteSpaceTokenType) &&
  189. IS_CATEGORY(id2, WhiteSpaceTokenType))
  190. {
  191. // all consecutive whitespace tokens count as one whitespace
  192. // adjust first1 and first2 accordingly
  193. skip_whitespace(first1, last1);
  194. skip_whitespace(first2, last2);
  195. }
  196. else if (!IS_CATEGORY(id1, WhiteSpaceTokenType) &&
  197. !IS_CATEGORY(id2, WhiteSpaceTokenType))
  198. {
  199. ++first1;
  200. ++first2;
  201. }
  202. else {
  203. // the sequences differ
  204. break;
  205. }
  206. }
  207. return (first1 == last1 && first2 == last2) ? true : false;
  208. }
  209. ///////////////////////////////////////////////////////////////////////////////
  210. //
  211. // Tests, whether two given sets of macro parameters are equal
  212. //
  213. ///////////////////////////////////////////////////////////////////////////////
  214. template <typename ContainerT>
  215. inline bool
  216. parameters_equal(ContainerT const &parameters, ContainerT const &new_parameters)
  217. {
  218. if (parameters.size() != new_parameters.size())
  219. return false; // different parameter count
  220. typedef typename ContainerT::const_iterator const_iterator_type;
  221. const_iterator_type first1 = parameters.begin();
  222. const_iterator_type last1 = parameters.end();
  223. const_iterator_type first2 = new_parameters.begin();
  224. const_iterator_type last2 = new_parameters.end();
  225. while (first1 != last1 && first2 != last2) {
  226. // parameters are different, if the corresponding tokens are different
  227. using namespace boost::wave;
  228. if (token_id(*first1) != token_id(*first2) ||
  229. (*first1).get_value() != (*first2).get_value())
  230. {
  231. break;
  232. }
  233. ++first1;
  234. ++first2;
  235. }
  236. return (first1 == last1 && first2 == last2) ? true : false;
  237. }
  238. ///////////////////////////////////////////////////////////////////////////////
  239. //
  240. // Strip leading and trailing whitespace from the given token sequence
  241. //
  242. ///////////////////////////////////////////////////////////////////////////////
  243. template <typename ContainerT>
  244. inline void
  245. trim_replacement_list (ContainerT &replacement_list)
  246. {
  247. using namespace boost::wave;
  248. // strip leading whitespace
  249. if (replacement_list.size() > 0) {
  250. typename ContainerT::iterator end = replacement_list.end();
  251. typename ContainerT::iterator it = replacement_list.begin();
  252. while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
  253. token_id id(*it);
  254. if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
  255. typename ContainerT::iterator next = it;
  256. ++next;
  257. replacement_list.erase(it);
  258. it = next;
  259. }
  260. else {
  261. ++it;
  262. }
  263. }
  264. }
  265. // strip trailing whitespace
  266. if (replacement_list.size() > 0) {
  267. typename ContainerT::reverse_iterator rend = replacement_list.rend();
  268. typename ContainerT::reverse_iterator rit = replacement_list.rbegin();
  269. while (rit != rend && IS_CATEGORY(*rit, WhiteSpaceTokenType))
  270. ++rit;
  271. typename ContainerT::iterator end = replacement_list.end();
  272. typename ContainerT::iterator it = rit.base();
  273. while (it != end && IS_CATEGORY(*it, WhiteSpaceTokenType)) {
  274. token_id id(*it);
  275. if (T_PLACEHOLDER != id && T_PLACEMARKER != id) {
  276. typename ContainerT::iterator next = it;
  277. ++next;
  278. replacement_list.erase(it);
  279. it = next;
  280. }
  281. else {
  282. ++it;
  283. }
  284. }
  285. }
  286. }
  287. ///////////////////////////////////////////////////////////////////////////////
  288. //
  289. // Tests, whether the given token sequence consists out of whitespace only
  290. //
  291. ///////////////////////////////////////////////////////////////////////////////
  292. template <typename ContainerT>
  293. inline bool
  294. is_whitespace_only (ContainerT const &argument)
  295. {
  296. typename ContainerT::const_iterator end = argument.end();
  297. for (typename ContainerT::const_iterator it = argument.begin();
  298. it != end; ++it)
  299. {
  300. if (!IS_CATEGORY(*it, WhiteSpaceTokenType))
  301. return false;
  302. }
  303. return true;
  304. }
  305. ///////////////////////////////////////////////////////////////////////////////
  306. //
  307. // Tests whether the given token sequence consists only of whitespace
  308. // and placemarkers
  309. //
  310. ///////////////////////////////////////////////////////////////////////////////
  311. template <typename ContainerT>
  312. inline bool
  313. is_blank_only (ContainerT const &argument)
  314. {
  315. typename ContainerT::const_iterator end = argument.end();
  316. for (typename ContainerT::const_iterator it = argument.begin();
  317. it != end; ++it)
  318. {
  319. if (!IS_CATEGORY(*it, WhiteSpaceTokenType) &&
  320. (T_PLACEMARKER != token_id(*it)))
  321. return false;
  322. }
  323. return true;
  324. }
  325. ///////////////////////////////////////////////////////////////////////////////
  326. //
  327. // Remove all placeholder tokens from the given token sequence
  328. //
  329. ///////////////////////////////////////////////////////////////////////////////
  330. template <typename ContainerT>
  331. inline void
  332. remove_placeholders (ContainerT &replacement_list)
  333. {
  334. using namespace boost::wave;
  335. // strip leading whitespace
  336. if (replacement_list.size() > 0) {
  337. typename ContainerT::iterator end = replacement_list.end();
  338. typename ContainerT::iterator it = replacement_list.begin();
  339. while (it != end) {
  340. token_id id(*it);
  341. if (T_PLACEHOLDER == id || T_PLACEMARKER == id) {
  342. typename ContainerT::iterator next = it;
  343. ++next;
  344. replacement_list.erase(it);
  345. it = next;
  346. }
  347. else {
  348. ++it;
  349. }
  350. }
  351. // remove all 'new' leading and trailing whitespace
  352. if (is_whitespace_only(replacement_list))
  353. trim_replacement_list(replacement_list);
  354. }
  355. }
  356. ///////////////////////////////////////////////////////////////////////////////
  357. //
  358. // Remove all whitespace tokens on the left side of the given token sequence
  359. //
  360. ///////////////////////////////////////////////////////////////////////////////
  361. template <typename ContainerT>
  362. inline void
  363. trim_sequence_left (ContainerT &argument)
  364. {
  365. using namespace boost::wave;
  366. // strip leading whitespace (should be only one token)
  367. if (argument.size() > 0 &&
  368. IS_CATEGORY(argument.front(), WhiteSpaceTokenType))
  369. {
  370. argument.pop_front();
  371. }
  372. }
  373. ///////////////////////////////////////////////////////////////////////////////
  374. //
  375. // Remove all whitespace tokens on the right side of the given token sequence
  376. //
  377. ///////////////////////////////////////////////////////////////////////////////
  378. template <typename ContainerT>
  379. inline void
  380. trim_sequence_right (ContainerT &argument)
  381. {
  382. using namespace boost::wave;
  383. // strip trailing whitespace (should be only one token)
  384. if (argument.size() > 0 &&
  385. IS_CATEGORY(argument.back(), WhiteSpaceTokenType))
  386. {
  387. argument.pop_back();
  388. }
  389. }
  390. ///////////////////////////////////////////////////////////////////////////////
  391. //
  392. // Remove all whitespace tokens on the left and right sides of the given token
  393. // sequence
  394. //
  395. ///////////////////////////////////////////////////////////////////////////////
  396. template <typename ContainerT>
  397. inline void
  398. trim_sequence (ContainerT &argument)
  399. {
  400. trim_sequence_left(argument);
  401. trim_sequence_right(argument);
  402. }
  403. ///////////////////////////////////////////////////////////////////////////////
  404. // call 'skipped_token' preprocessing hook
  405. template <typename ContextT>
  406. void call_skipped_token_hook(ContextT& ctx,
  407. typename ContextT::token_type const& skipped)
  408. {
  409. ctx.get_hooks().skipped_token(ctx.derived(), skipped);
  410. }
  411. ///////////////////////////////////////////////////////////////////////////////
  412. //
  413. // Skip forward to a given token
  414. //
  415. ///////////////////////////////////////////////////////////////////////////////
  416. template <typename ContextT, typename IteratorT>
  417. inline bool
  418. skip_to_token(ContextT& ctx, IteratorT &it, IteratorT const &end,
  419. token_id id, bool& seen_newline)
  420. {
  421. using namespace boost::wave;
  422. if (token_id(*it) == id)
  423. return true;
  424. // call_skipped_token_hook(ctx, *it);
  425. if (++it == end)
  426. return false;
  427. while (IS_CATEGORY(*it, WhiteSpaceTokenType) ||
  428. T_NEWLINE == token_id(*it))
  429. {
  430. if (T_NEWLINE == token_id(*it))
  431. seen_newline = true;
  432. // call_skipped_token_hook(ctx, *it);
  433. if (++it == end)
  434. return false;
  435. }
  436. return token_id(*it) == id;
  437. }
  438. ///////////////////////////////////////////////////////////////////////////////
  439. //
  440. // Get the full name of a given macro name (concatenate the string
  441. // representations of the single tokens).
  442. //
  443. ///////////////////////////////////////////////////////////////////////////////
  444. template <typename IteratorT>
  445. inline std::string
  446. get_full_name(IteratorT const &begin, IteratorT const &end)
  447. {
  448. std::string full_name;
  449. for (IteratorT err_it = begin; err_it != end; ++err_it)
  450. full_name += (*err_it).get_value().c_str();
  451. return full_name;
  452. }
  453. ///////////////////////////////////////////////////////////////////////////////
  454. //
  455. // The following predicate is used in conjunction with the remove_copy_if
  456. // algorithm to allow the detection of an eventually copied operator ##.
  457. // No removal is performed in any case.
  458. //
  459. ///////////////////////////////////////////////////////////////////////////////
  460. class find_concat_operator {
  461. public:
  462. find_concat_operator(bool &found_) : found_concat(found_) {}
  463. template <typename TokenT>
  464. bool operator()(TokenT const &tok)
  465. {
  466. using namespace boost::wave;
  467. if (T_POUND_POUND == BASE_TOKEN(token_id(tok)))
  468. found_concat = true;
  469. return false;
  470. }
  471. private:
  472. bool &found_concat;
  473. };
  474. ///////////////////////////////////////////////////////////////////////////////
  475. // Convert a string of an arbitrary string compatible type to a internal
  476. // string (BOOST_WAVE_STRING)
  477. template <typename Target, typename Src>
  478. struct to_string_helper
  479. {
  480. typedef Target type;
  481. static Target call(Src const& str)
  482. {
  483. return Target(str.c_str());
  484. }
  485. };
  486. // do nothing if types are equal
  487. template <typename Src>
  488. struct to_string_helper<Src, Src>
  489. {
  490. typedef Src const& type;
  491. static Src const& call(Src const& str)
  492. {
  493. return str;
  494. }
  495. };
  496. template <typename Target>
  497. struct to_string_helper<Target, char const*>
  498. {
  499. typedef Target type;
  500. static Target call(char const* str)
  501. {
  502. return Target(str);
  503. }
  504. };
  505. ///////////////////////////////////////////////////////////////////////////////
  506. } // namespace impl
  507. template <typename Target, typename Src>
  508. inline typename impl::to_string_helper<Target, Src>::type
  509. to_string(Src const& src)
  510. {
  511. return impl::to_string_helper<Target, Src>::call(src);
  512. }
  513. ///////////////////////////////////////////////////////////////////////////////
  514. } // namespace util
  515. } // namespace wave
  516. } // namespace boost
  517. // the suffix header occurs after all of the code
  518. #ifdef BOOST_HAS_ABI_HEADERS
  519. #include BOOST_ABI_SUFFIX
  520. #endif
  521. #endif // !defined(BOOST_CPP_MACROMAP_UTIL_HPP_HK041119)