cpp_macromap_utils.hpp 17 KB

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