cpp_has_include_grammar.hpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*=============================================================================
  2. Boost.Wave: A Standard compliant C++ preprocessor library
  3. http://www.boost.org/
  4. Copyright (c) 2020 Jeff Trull
  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_HAS_INCLUDE_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED)
  10. #define BOOST_CPP_HAS_INCLUDE_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED
  11. #include <boost/wave/wave_config.hpp>
  12. #include <boost/assert.hpp>
  13. #include <boost/spirit/include/classic_core.hpp>
  14. #include <boost/spirit/include/classic_closure.hpp>
  15. #include <boost/spirit/include/classic_assign_actor.hpp>
  16. #include <boost/spirit/include/classic_push_back_actor.hpp>
  17. #include <boost/wave/token_ids.hpp>
  18. #include <boost/wave/util/pattern_parser.hpp>
  19. #include <boost/wave/grammars/cpp_has_include_grammar_gen.hpp>
  20. #if !defined(spirit_append_actor)
  21. #define spirit_append_actor(actor) boost::spirit::classic::push_back_a(actor)
  22. #endif // !has_include(spirit_append_actor)
  23. // this must occur after all of the includes and before any code appears
  24. #ifdef BOOST_HAS_ABI_HEADERS
  25. #include BOOST_ABI_PREFIX
  26. #endif
  27. ///////////////////////////////////////////////////////////////////////////////
  28. namespace boost {
  29. namespace wave {
  30. namespace grammars {
  31. ///////////////////////////////////////////////////////////////////////////////
  32. // define, whether the rule's should generate some debug output
  33. #define TRACE_CPP_HAS_INCLUDE_GRAMMAR \
  34. bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_HAS_INCLUDE_GRAMMAR) \
  35. /**/
  36. template <typename ContainerT>
  37. struct has_include_grammar :
  38. public boost::spirit::classic::grammar<has_include_grammar<ContainerT> >
  39. {
  40. has_include_grammar(ContainerT &tokens_seq_,
  41. bool &is_quoted_filename_,
  42. bool &is_system_)
  43. : tokens_seq(tokens_seq_), is_quoted_filename(is_quoted_filename_),
  44. is_system(is_system_), true_(true)
  45. {
  46. BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "has_include_grammar",
  47. TRACE_CPP_HAS_INCLUDE_GRAMMAR);
  48. is_quoted_filename = false;
  49. is_system = false;
  50. }
  51. template <typename ScannerT>
  52. struct definition
  53. {
  54. typedef boost::spirit::classic::rule<ScannerT> rule_t;
  55. rule_t has_include_op;
  56. rule_t system_include;
  57. rule_t nonsystem_include;
  58. rule_t nonparen;
  59. rule_t parenthesized_exp;
  60. rule_t computed_include;
  61. definition(has_include_grammar const & self)
  62. {
  63. using namespace boost::spirit::classic;
  64. using namespace boost::wave;
  65. using namespace boost::wave::util;
  66. has_include_op
  67. = ch_p(T_IDENTIFIER) >> // token contains '__has_include'
  68. ch_p(T_LEFTPAREN) >>
  69. (system_include | nonsystem_include | computed_include) >>
  70. ch_p(T_RIGHTPAREN)
  71. ;
  72. system_include
  73. = ch_p(T_LESS)
  74. [
  75. spirit_append_actor(self.tokens_seq)
  76. ]
  77. >> * (~ch_p(T_GREATER))
  78. [
  79. spirit_append_actor(self.tokens_seq)
  80. ]
  81. >> ch_p(T_GREATER)
  82. [
  83. spirit_append_actor(self.tokens_seq)
  84. ][
  85. assign_a(self.is_quoted_filename, self.true_)
  86. ][
  87. assign_a(self.is_system, self.true_)
  88. ]
  89. ;
  90. nonsystem_include = ch_p(T_STRINGLIT)
  91. [
  92. spirit_append_actor(self.tokens_seq)
  93. ][
  94. assign_a(self.is_quoted_filename, self.true_)
  95. ]
  96. ;
  97. // an action to store a sequence of parsed tokens
  98. auto append_seq = [&](typename ScannerT::iterator_t first,
  99. typename ScannerT::iterator_t last) {
  100. for (;first != last;++first) {
  101. self.tokens_seq.push_back(*first);
  102. };
  103. };
  104. // if neither of the above match we take everything between
  105. // the parentheses and evaluate it ("computed include")
  106. // supported expressions are "implementation defined" per the gcc manual
  107. // we've tried to be fairly generous in Wave
  108. // here we accept any set of non-whitespace characters with
  109. // properly nested parentheses:
  110. nonparen = (anychar_p - ch_p(T_LEFTPAREN) - ch_p(T_RIGHTPAREN)) [ append_seq ] ;
  111. parenthesized_exp =
  112. ch_p(T_LEFTPAREN)[ spirit_append_actor(self.tokens_seq) ] >>
  113. computed_include >>
  114. ch_p(T_RIGHTPAREN)[ spirit_append_actor(self.tokens_seq) ] ;
  115. computed_include = * (nonparen | parenthesized_exp) ;
  116. BOOST_SPIRIT_DEBUG_TRACE_RULE(has_include_op, TRACE_CPP_HAS_INCLUDE_GRAMMAR);
  117. BOOST_SPIRIT_DEBUG_TRACE_RULE(system_include, TRACE_CPP_HAS_INCLUDE_GRAMMAR);
  118. BOOST_SPIRIT_DEBUG_TRACE_RULE(nonsystem_include, TRACE_CPP_HAS_INCLUDE_GRAMMAR);
  119. BOOST_SPIRIT_DEBUG_TRACE_RULE(computed_include, TRACE_CPP_HAS_INCLUDE_GRAMMAR);
  120. BOOST_SPIRIT_DEBUG_TRACE_RULE(parenthesized_exp, TRACE_CPP_HAS_INCLUDE_GRAMMAR);
  121. BOOST_SPIRIT_DEBUG_TRACE_RULE(nonparen, TRACE_CPP_HAS_INCLUDE_GRAMMAR);
  122. }
  123. // start rule of this grammar
  124. rule_t const& start() const
  125. { return has_include_op; }
  126. };
  127. ContainerT &tokens_seq;
  128. bool &is_quoted_filename;
  129. bool &is_system;
  130. const bool true_; // Spirit Classic actors operate on references, not values
  131. };
  132. ///////////////////////////////////////////////////////////////////////////////
  133. #undef TRACE_CPP_HAS_INCLUDE_GRAMMAR
  134. ///////////////////////////////////////////////////////////////////////////////
  135. //
  136. // The following parse function is has_include here, to allow the separation of
  137. // the compilation of the has_include_grammar from the function
  138. // using it.
  139. //
  140. ///////////////////////////////////////////////////////////////////////////////
  141. #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
  142. #define BOOST_WAVE_HAS_INCLUDE_GRAMMAR_GEN_INLINE
  143. #else
  144. #define BOOST_WAVE_HAS_INCLUDE_GRAMMAR_GEN_INLINE inline
  145. #endif
  146. // The parse_operator_define function is instantiated manually twice to
  147. // simplify the explicit specialization of this template. This way the user
  148. // has only to specify one template parameter (the lexer type) to correctly
  149. // formulate the required explicit specialization.
  150. // This results in no code overhead, because otherwise the function would be
  151. // generated by the compiler twice anyway.
  152. template <typename LexIteratorT>
  153. BOOST_WAVE_HAS_INCLUDE_GRAMMAR_GEN_INLINE
  154. boost::spirit::classic::parse_info<
  155. typename has_include_grammar_gen<LexIteratorT>::iterator1_type
  156. >
  157. has_include_grammar_gen<LexIteratorT>::parse_operator_has_include (
  158. iterator1_type const &first, iterator1_type const &last,
  159. token_sequence_type &tokens,
  160. bool &is_quoted_filename, bool &is_system)
  161. {
  162. using namespace boost::spirit::classic;
  163. using namespace boost::wave;
  164. has_include_grammar<token_sequence_type>
  165. g(tokens, is_quoted_filename, is_system);
  166. return boost::spirit::classic::parse (
  167. first, last, g, ch_p(T_SPACE) | ch_p(T_CCOMMENT));
  168. }
  169. template <typename LexIteratorT>
  170. BOOST_WAVE_HAS_INCLUDE_GRAMMAR_GEN_INLINE
  171. boost::spirit::classic::parse_info<
  172. typename has_include_grammar_gen<LexIteratorT>::iterator2_type
  173. >
  174. has_include_grammar_gen<LexIteratorT>::parse_operator_has_include (
  175. iterator2_type const &first, iterator2_type const &last,
  176. token_sequence_type &found_qualified_name,
  177. bool &is_quoted_filename, bool &is_system)
  178. {
  179. using namespace boost::spirit::classic;
  180. using namespace boost::wave;
  181. has_include_grammar<token_sequence_type>
  182. g(found_qualified_name, is_quoted_filename, is_system);
  183. return boost::spirit::classic::parse (
  184. first, last, g, ch_p(T_SPACE) | ch_p(T_CCOMMENT));
  185. }
  186. #undef BOOST_WAVE_HAS_INCLUDE_GRAMMAR_GEN_INLINE
  187. ///////////////////////////////////////////////////////////////////////////////
  188. } // namespace grammars
  189. } // namespace wave
  190. } // namespace boost
  191. // the suffix header occurs after all of the code
  192. #ifdef BOOST_HAS_ABI_HEADERS
  193. #include BOOST_ABI_SUFFIX
  194. #endif
  195. #endif // !defined(BOOST_CPP_HAS_INCLUDE_GRAMMAR_HPP_F48287B2_DC67_40A8_B4A1_800EFBD67869_INCLUDED)