preprocess_pragma_output.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*=============================================================================
  2. Boost.Wave: A Standard compliant C++ preprocessor library
  3. Example demonstrating how to preprocess the token stream generated by a
  4. #pragma directive
  5. http://www.boost.org/
  6. Copyright (c) 2001-2010 Hartmut Kaiser. Distributed under the Boost
  7. Software License, Version 1.0. (See accompanying file
  8. LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. =============================================================================*/
  10. #if !defined(BOOST_WAVE_SAMPLE_PREPROCESS_PRAGMA_OUTPUT_APR_03_2008_0813AM)
  11. #define BOOST_WAVE_SAMPLE_PREPROCESS_PRAGMA_OUTPUT_APR_03_2008_0813AM
  12. template <typename String, typename Iterator>
  13. inline String
  14. as_unescaped_string(Iterator it, Iterator const& end)
  15. {
  16. using namespace boost::wave;
  17. String result;
  18. for (/**/; it != end; ++it)
  19. {
  20. switch (token_id(*it)) {
  21. case T_STRINGLIT:
  22. {
  23. string val (util::impl::unescape_lit((*it).get_value()).c_str());
  24. val.erase(val.size()-1);
  25. val.erase(0, 1);
  26. result += val;
  27. }
  28. break;
  29. default: // just skip everything else (hey it's a sample)
  30. break;
  31. }
  32. }
  33. return result;
  34. }
  35. // return the string representation of a token sequence
  36. template <typename String, typename Container>
  37. inline String
  38. as_unescaped_string(Container const &token_sequence)
  39. {
  40. return as_unescaped_string<String>(token_sequence.begin(),
  41. token_sequence.end());
  42. }
  43. ///////////////////////////////////////////////////////////////////////////////
  44. //
  45. // The preprocess_pragma_output_hooks policy class is used implement a special
  46. // #pragma wave pp("some C++ code") directive allowing to insert preprocessed
  47. // code into the output sequence generated by the tool.
  48. //
  49. // This policy type is used as a template parameter to the boost::wave::context<>
  50. // object.
  51. //
  52. ///////////////////////////////////////////////////////////////////////////////
  53. class preprocess_pragma_output_hooks
  54. : public boost::wave::context_policies::default_preprocessing_hooks
  55. {
  56. public:
  57. preprocess_pragma_output_hooks() {}
  58. template <typename Context>
  59. struct reset_language_support
  60. {
  61. reset_language_support(Context& ctx)
  62. : ctx_(ctx), lang_(ctx.get_language())
  63. {
  64. ctx.set_language(boost::wave::enable_single_line(lang_), false);
  65. }
  66. ~reset_language_support()
  67. {
  68. ctx_.set_language(lang_, false);
  69. }
  70. Context& ctx_;
  71. boost::wave::language_support lang_;
  72. };
  73. ///////////////////////////////////////////////////////////////////////////
  74. //
  75. // The function 'interpret_pragma' is called, whenever a #pragma command
  76. // directive is found which isn't known to the core Wave library, where
  77. // command is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant
  78. // which defaults to "wave".
  79. //
  80. // The parameter 'ctx' is a reference to the context object used for
  81. // instantiating the preprocessing iterators by the user.
  82. //
  83. // The parameter 'pending' may be used to push tokens back into the input
  84. // stream, which are to be used as the replacement text for the whole
  85. // #pragma directive.
  86. //
  87. // The parameter 'option' contains the name of the interpreted pragma.
  88. //
  89. // The parameter 'values' holds the values of the parameter provided to
  90. // the pragma operator.
  91. //
  92. // The parameter 'act_token' contains the actual #pragma token, which may
  93. // be used for error output.
  94. //
  95. // If the return value is 'false', the whole #pragma directive is
  96. // interpreted as unknown and a corresponding error message is issued. A
  97. // return value of 'true' signs a successful interpretation of the given
  98. // #pragma.
  99. //
  100. ///////////////////////////////////////////////////////////////////////////
  101. template <typename Context, typename Container>
  102. bool
  103. interpret_pragma(Context& ctx, Container &pending,
  104. typename Context::token_type const& option,
  105. Container const& values, typename Context::token_type const& act_token)
  106. {
  107. typedef typename Context::token_type token_type;
  108. typedef typename Context::iterator_type iterator_type;
  109. if (option.get_value() == "pp") {
  110. // Concatenate the string(s) passed as the options to this pragma,
  111. // preprocess the result using the current context and insert the
  112. // generated token sequence in place of the pragma directive into the
  113. // output stream.
  114. try {
  115. // We're explicitly using a std::string here since the type of the
  116. // iterators passed to the ctx.begin() below must match the types
  117. // of the iterator the original context instance has been created
  118. // with.
  119. std::string s (as_unescaped_string<std::string>(values));
  120. reset_language_support<Context> lang(ctx);
  121. using namespace boost::wave;
  122. // The expanded token sequence is stored in the 'pragma' container
  123. // to ensure consistency in the output in the case of an error
  124. // while preprocessing the pragma option strings.
  125. Container pragma;
  126. iterator_type end = ctx.end();
  127. for (iterator_type it = ctx.begin(s.begin(), s.end());
  128. it != end && token_id(*it) != T_EOF; ++it)
  129. {
  130. pragma.push_back(*it);
  131. it++;
  132. }
  133. // prepend the newly generated token sequence to the 'pending'
  134. // container
  135. pending.splice(pending.begin(), pragma);
  136. }
  137. catch (boost::wave::preprocess_exception const& /*e*/) {
  138. // the library will report an 'ill_formed_pragma_option' for us
  139. return false;
  140. }
  141. return true;
  142. }
  143. // we don't know anything about this #pragma wave directive
  144. return false;
  145. }
  146. };
  147. #endif