interpret_pragma.hpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)
  9. #define INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED
  10. #include <string>
  11. #include <list>
  12. #include <boost/spirit/include/classic_core.hpp>
  13. #include <boost/spirit/include/classic_assign_actor.hpp>
  14. #include <boost/spirit/include/classic_push_back_actor.hpp>
  15. #include <boost/spirit/include/classic_confix.hpp>
  16. #include <boost/wave/wave_config.hpp>
  17. #include <boost/wave/util/pattern_parser.hpp>
  18. #include <boost/wave/util/macro_helpers.hpp>
  19. #include <boost/wave/token_ids.hpp>
  20. #include <boost/wave/cpp_exceptions.hpp>
  21. #include <boost/wave/cpp_iteration_context.hpp>
  22. #include <boost/wave/language_support.hpp>
  23. #if !defined(spirit_append_actor)
  24. #define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
  25. #define spirit_assign_actor(actor) boost::spirit::classic::assign_a(actor)
  26. #endif // !defined(spirit_append_actor)
  27. // this must occur after all of the includes and before any code appears
  28. #ifdef BOOST_HAS_ABI_HEADERS
  29. #include BOOST_ABI_PREFIX
  30. #endif
  31. ///////////////////////////////////////////////////////////////////////////////
  32. namespace boost {
  33. namespace wave {
  34. namespace util {
  35. ///////////////////////////////////////////////////////////////////////////////
  36. //
  37. // The function interpret_pragma interprets the given token sequence as the
  38. // body of a #pragma directive (or parameter to the _Pragma operator) and
  39. // executes the actions associated with recognized Wave specific options.
  40. //
  41. ///////////////////////////////////////////////////////////////////////////////
  42. template <typename ContextT, typename IteratorT, typename ContainerT>
  43. inline bool
  44. interpret_pragma(ContextT &ctx, typename ContextT::token_type const &act_token,
  45. IteratorT it, IteratorT const &end, ContainerT &pending)
  46. {
  47. typedef typename ContextT::token_type token_type;
  48. typedef typename token_type::string_type string_type;
  49. using namespace cpplexer;
  50. if (T_IDENTIFIER == token_id(*it)) {
  51. // check for pragma wave ...
  52. if ((*it).get_value() == BOOST_WAVE_PRAGMA_KEYWORD)
  53. {
  54. // this is a wave specific option, it should have the form:
  55. //
  56. // #pragma command option(value)
  57. //
  58. // where
  59. // 'command' is the value of the preprocessor constant
  60. // BOOST_WAVE_PRAGMA_KEYWORD (defaults to "wave") and
  61. // '(value)' is required only for some pragma directives (this is
  62. // optional)
  63. //
  64. // All recognized #pragma operators are forwarded to the supplied
  65. // preprocessing hook.
  66. using namespace boost::spirit::classic;
  67. token_type option;
  68. ContainerT values;
  69. if (!parse (++it, end,
  70. ( ch_p(T_IDENTIFIER)
  71. [
  72. spirit_assign_actor(option)
  73. ]
  74. | pattern_p(KeywordTokenType,
  75. TokenTypeMask|PPTokenFlag)
  76. [
  77. spirit_assign_actor(option)
  78. ]
  79. | pattern_p(OperatorTokenType|AltExtTokenType,
  80. ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
  81. [
  82. spirit_assign_actor(option)
  83. ]
  84. | pattern_p(BoolLiteralTokenType,
  85. TokenTypeMask|PPTokenFlag)
  86. [
  87. spirit_assign_actor(option)
  88. ]
  89. )
  90. >> !comment_nest_p(
  91. ch_p(T_LEFTPAREN),
  92. ch_p(T_RIGHTPAREN)
  93. )[spirit_assign_actor(values)],
  94. pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)).hit)
  95. {
  96. typename ContextT::string_type msg(
  97. impl::as_string<string_type>(it, end));
  98. BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
  99. ill_formed_pragma_option,
  100. msg.c_str(), act_token.get_position());
  101. return false;
  102. }
  103. // remove the falsely matched surrounding parenthesis's
  104. if (values.size() >= 2) {
  105. BOOST_ASSERT(T_LEFTPAREN == values.front() && T_RIGHTPAREN == values.back());
  106. values.erase(values.begin());
  107. typename ContainerT::reverse_iterator rit = values.rbegin();
  108. values.erase((++rit).base());
  109. }
  110. // decode the option (call the context_policy hook)
  111. if (!ctx.get_hooks().interpret_pragma(
  112. ctx.derived(), pending, option, values, act_token))
  113. {
  114. // unknown #pragma option
  115. string_type option_str ((*it).get_value());
  116. option_str += option.get_value();
  117. if (values.size() > 0) {
  118. option_str += "(";
  119. option_str += impl::as_string(values);
  120. option_str += ")";
  121. }
  122. BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
  123. ill_formed_pragma_option,
  124. option_str.c_str(), act_token.get_position());
  125. return false;
  126. }
  127. return true;
  128. }
  129. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  130. else if ((*it).get_value() == "once") {
  131. // #pragma once
  132. return ctx.add_pragma_once_header(act_token, ctx.get_current_filename());
  133. }
  134. #endif
  135. #if BOOST_WAVE_SUPPORT_PRAGMA_MESSAGE != 0
  136. else if ((*it).get_value() == "message") {
  137. // #pragma message(...) or #pragma message ...
  138. using namespace boost::spirit::classic;
  139. ContainerT values;
  140. if (!parse (++it, end,
  141. ( ( ch_p(T_LEFTPAREN)
  142. >> lexeme_d[
  143. *(anychar_p[spirit_append_actor(values)] - ch_p(T_RIGHTPAREN))
  144. ]
  145. >> ch_p(T_RIGHTPAREN)
  146. )
  147. | lexeme_d[
  148. *(anychar_p[spirit_append_actor(values)] - ch_p(T_NEWLINE))
  149. ]
  150. ),
  151. pattern_p(WhiteSpaceTokenType, TokenTypeMask|PPTokenFlag)
  152. ).hit
  153. )
  154. {
  155. typename ContextT::string_type msg(
  156. impl::as_string<string_type>(it, end));
  157. BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
  158. ill_formed_pragma_message,
  159. msg.c_str(), act_token.get_position());
  160. return false;
  161. }
  162. // remove the falsely matched closing parenthesis/newline
  163. if (values.size() > 0) {
  164. BOOST_ASSERT(T_RIGHTPAREN == values.back() || T_NEWLINE == values.back());
  165. typename ContainerT::reverse_iterator rit = values.rbegin();
  166. values.erase((++rit).base());
  167. }
  168. // output the message itself
  169. typename ContextT::string_type msg(impl::as_string(values));
  170. BOOST_WAVE_THROW_CTX(ctx, preprocess_exception,
  171. pragma_message_directive,
  172. msg.c_str(), act_token.get_position());
  173. return false;
  174. }
  175. #endif
  176. }
  177. return false;
  178. }
  179. ///////////////////////////////////////////////////////////////////////////////
  180. } // namespace util
  181. } // namespace wave
  182. } // namespace boost
  183. // the suffix header occurs after all of the code
  184. #ifdef BOOST_HAS_ABI_HEADERS
  185. #include BOOST_ABI_SUFFIX
  186. #endif
  187. #endif // !defined(INTERPRET_PRAGMA_HPP_B1F2315E_C5CE_4ED1_A343_0EF548B7942A_INCLUDED)