/*============================================================================= Boost.Wave: A Standard compliant C++ preprocessor library http://www.boost.org/ Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #if !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED) #define CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED #include #include #include #include #include #include #include #if BOOST_WAVE_DUMP_PARSE_TREE != 0 #include #include #endif #include #include #include #include // this must occur after all of the includes and before any code appears #ifdef BOOST_HAS_ABI_HEADERS #include BOOST_ABI_PREFIX #endif /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace wave { namespace grammars { namespace impl { /////////////////////////////////////////////////////////////////////////////// // // store_found_eof // // The store_found_eof functor sets a given flag if the T_EOF token was // found during the parsing process // /////////////////////////////////////////////////////////////////////////////// struct store_found_eof { store_found_eof(bool &found_eof_) : found_eof(found_eof_) {} template void operator()(TokenT const &/*token*/) const { found_eof = true; } bool &found_eof; }; /////////////////////////////////////////////////////////////////////////////// // // store_found_directive // // The store_found_directive functor stores the token_id of the recognized // pp directive // /////////////////////////////////////////////////////////////////////////////// template struct store_found_directive { store_found_directive(TokenT &found_directive_) : found_directive(found_directive_) {} void operator()(TokenT const &token) const { found_directive = token; } TokenT &found_directive; }; /////////////////////////////////////////////////////////////////////////////// // // store_found_eoltokens // // The store_found_eoltokens functor stores the token sequence of the // line ending for a particular pp directive // /////////////////////////////////////////////////////////////////////////////// template struct store_found_eoltokens { store_found_eoltokens(ContainerT &found_eoltokens_) : found_eoltokens(found_eoltokens_) {} template void operator()(IteratorT const &first, IteratorT const& last) const { std::copy(first, last, std::inserter(found_eoltokens, found_eoltokens.end())); } ContainerT &found_eoltokens; }; /////////////////////////////////////////////////////////////////////////////// // // flush_underlying_parser // // The flush_underlying_parser flushes the underlying // multi_pass_iterator during the normal parsing process. This is // used at certain points during the parsing process, when it is // clear, that no backtracking is needed anymore and the input // gathered so far may be discarded. // /////////////////////////////////////////////////////////////////////////////// struct flush_underlying_parser : public boost::spirit::classic::parser { typedef flush_underlying_parser this_t; template typename boost::spirit::classic::parser_result::type parse(ScannerT const& scan) const { scan.first.clear_queue(); return scan.empty_match(); } }; flush_underlying_parser const flush_underlying_parser_p = flush_underlying_parser(); } // anonymous namespace /////////////////////////////////////////////////////////////////////////////// // define, whether the rule's should generate some debug output #define TRACE_CPP_GRAMMAR \ bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \ /**/ /////////////////////////////////////////////////////////////////////////////// // Encapsulation of the C++ preprocessor grammar. template struct cpp_grammar : public boost::spirit::classic::grammar > { typedef typename TokenT::position_type position_type; typedef cpp_grammar grammar_type; typedef impl::store_found_eof store_found_eof_type; typedef impl::store_found_directive store_found_directive_type; typedef impl::store_found_eoltokens store_found_eoltokens_type; template struct definition { // non-parse_tree generating rule type typedef typename ScannerT::iteration_policy_t iteration_policy_t; typedef boost::spirit::classic::match_policy match_policy_t; typedef typename ScannerT::action_policy_t action_policy_t; typedef boost::spirit::classic::scanner_policies< iteration_policy_t, match_policy_t, action_policy_t> policies_t; typedef boost::spirit::classic::scanner non_tree_scanner_t; typedef boost::spirit::classic::rule< non_tree_scanner_t, boost::spirit::classic::dynamic_parser_tag> no_tree_rule_type; // 'normal' (parse_tree generating) rule type typedef boost::spirit::classic::rule< ScannerT, boost::spirit::classic::dynamic_parser_tag> rule_type; rule_type pp_statement, macro_include_file; // rule_type include_file, system_include_file; rule_type plain_define, macro_definition, macro_parameters; rule_type undefine; rule_type ppifdef, ppifndef, ppif, ppelif; // rule_type ppelse, ppendif; rule_type ppline; rule_type pperror; rule_type ppwarning; rule_type pppragma; rule_type illformed; rule_type ppqualifiedname; rule_type eol_tokens; no_tree_rule_type ppsp; #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 rule_type ppregion; rule_type ppendregion; #endif definition(cpp_grammar const &self) { // import the spirit and cpplexer namespaces here using namespace boost::spirit::classic; using namespace boost::wave; using namespace boost::wave::util; // set the rule id's for later use pp_statement.set_id(BOOST_WAVE_PP_STATEMENT_ID); // include_file.set_id(BOOST_WAVE_INCLUDE_FILE_ID); // system_include_file.set_id(BOOST_WAVE_SYSINCLUDE_FILE_ID); macro_include_file.set_id(BOOST_WAVE_MACROINCLUDE_FILE_ID); plain_define.set_id(BOOST_WAVE_PLAIN_DEFINE_ID); macro_parameters.set_id(BOOST_WAVE_MACRO_PARAMETERS_ID); macro_definition.set_id(BOOST_WAVE_MACRO_DEFINITION_ID); undefine.set_id(BOOST_WAVE_UNDEFINE_ID); ppifdef.set_id(BOOST_WAVE_IFDEF_ID); ppifndef.set_id(BOOST_WAVE_IFNDEF_ID); ppif.set_id(BOOST_WAVE_IF_ID); ppelif.set_id(BOOST_WAVE_ELIF_ID); // ppelse.set_id(BOOST_WAVE_ELSE_ID); // ppendif.set_id(BOOST_WAVE_ENDIF_ID); ppline.set_id(BOOST_WAVE_LINE_ID); pperror.set_id(BOOST_WAVE_ERROR_ID); ppwarning.set_id(BOOST_WAVE_WARNING_ID); pppragma.set_id(BOOST_WAVE_PRAGMA_ID); illformed.set_id(BOOST_WAVE_ILLFORMED_ID); ppsp.set_id(BOOST_WAVE_PPSPACE_ID); ppqualifiedname.set_id(BOOST_WAVE_PPQUALIFIEDNAME_ID); #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 ppregion.set_id(BOOST_WAVE_REGION_ID); ppendregion.set_id(BOOST_WAVE_ENDREGION_ID); #endif #if BOOST_WAVE_DUMP_PARSE_TREE != 0 self.map_rule_id_to_name.init_rule_id_to_name_map(self); #endif // recognizes preprocessor directives only // C++ standard 16.1: A preprocessing directive consists of a sequence // of preprocessing tokens. The first token in the sequence is # // preprocessing token that is either the first character in the source // file (optionally after white space containing no new-line // characters) or that follows white space containing at least one // new-line character. The last token in the sequence is the first // new-line character that follows the first token in the sequence. pp_statement = ( plain_define // | include_file // | system_include_file | ppif | ppelif | ppifndef | ppifdef | undefine // | ppelse | macro_include_file | ppline | pppragma | pperror | ppwarning // | ppendif #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 | ppregion | ppendregion #endif | illformed ) >> eol_tokens [ store_found_eoltokens_type(self.found_eoltokens) ] // In parser debug mode it is useful not to flush the underlying stream // to allow its investigation in the debugger and to see the correct // output in the printed debug log.. // Note: this may break the parser, though. #if !(defined(BOOST_SPIRIT_DEBUG) && \ (BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \ ) >> impl::flush_underlying_parser_p #endif // !(defined(BOOST_SPIRIT_DEBUG) && ; // // #include ... // include_file // include "..." // = ch_p(T_PP_QHEADER) // [ store_found_directive_type(self.found_directive) ] // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 // | ch_p(T_PP_QHEADER_NEXT) // [ store_found_directive_type(self.found_directive) ] // #endif // ; // system_include_file // include <...> // = ch_p(T_PP_HHEADER) // [ store_found_directive_type(self.found_directive) ] // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 // | ch_p(T_PP_HHEADER_NEXT) // [ store_found_directive_type(self.found_directive) ] // #endif // ; macro_include_file // include ...anything else... = no_node_d [ ch_p(T_PP_INCLUDE) [ store_found_directive_type(self.found_directive) ] #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 | ch_p(T_PP_INCLUDE_NEXT) [ store_found_directive_type(self.found_directive) ] #endif ] >> *( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) ; // #define FOO foo (with optional parameters) plain_define = no_node_d [ ch_p(T_PP_DEFINE) [ store_found_directive_type(self.found_directive) ] >> +ppsp ] >> ( ch_p(T_IDENTIFIER) | pattern_p(KeywordTokenType, TokenTypeMask|PPTokenFlag) | pattern_p(OperatorTokenType|AltExtTokenType, ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. | pattern_p(BoolLiteralTokenType, TokenTypeMask|PPTokenFlag) // true/false ) >> ( ( no_node_d[eps_p(ch_p(T_LEFTPAREN))] >> macro_parameters >> !macro_definition ) | !( no_node_d[+ppsp] >> macro_definition ) ) ; // parameter list // normal C++ mode macro_parameters = confix_p( no_node_d[ch_p(T_LEFTPAREN) >> *ppsp], !list_p( ( ch_p(T_IDENTIFIER) | pattern_p(KeywordTokenType, TokenTypeMask|PPTokenFlag) | pattern_p(OperatorTokenType|AltExtTokenType, ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. | pattern_p(BoolLiteralTokenType, TokenTypeMask|PPTokenFlag) // true/false #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 | ch_p(T_ELLIPSIS) #endif ), no_node_d[*ppsp >> ch_p(T_COMMA) >> *ppsp] ), no_node_d[*ppsp >> ch_p(T_RIGHTPAREN)] ) ; // macro body (anything left until eol) macro_definition = no_node_d[*ppsp] >> *( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) ; // #undef FOO undefine = no_node_d [ ch_p(T_PP_UNDEF) [ store_found_directive_type(self.found_directive) ] >> +ppsp ] >> ( ch_p(T_IDENTIFIER) | pattern_p(KeywordTokenType, TokenTypeMask|PPTokenFlag) | pattern_p(OperatorTokenType|AltExtTokenType, ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. | pattern_p(BoolLiteralTokenType, TokenTypeMask|PPTokenFlag) // true/false ) ; // #ifdef et.al. ppifdef = no_node_d [ ch_p(T_PP_IFDEF) [ store_found_directive_type(self.found_directive) ] >> +ppsp ] >> ppqualifiedname ; ppifndef = no_node_d [ ch_p(T_PP_IFNDEF) [ store_found_directive_type(self.found_directive) ] >> +ppsp ] >> ppqualifiedname ; ppif = no_node_d [ ch_p(T_PP_IF) [ store_found_directive_type(self.found_directive) ] // >> *ppsp ] >> +( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) ; // ppelse // = no_node_d // [ // ch_p(T_PP_ELSE) // [ store_found_directive_type(self.found_directive) ] // ] // ; ppelif = no_node_d [ ch_p(T_PP_ELIF) [ store_found_directive_type(self.found_directive) ] // >> *ppsp ] >> +( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) ; // ppendif // = no_node_d // [ // ch_p(T_PP_ENDIF) // [ store_found_directive_type(self.found_directive) ] // ] // ; // #line ... ppline = no_node_d [ ch_p(T_PP_LINE) [ store_found_directive_type(self.found_directive) ] >> *ppsp ] >> +( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) ; #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 // #region ... ppregion = no_node_d [ ch_p(T_MSEXT_PP_REGION) [ store_found_directive_type(self.found_directive) ] >> +ppsp ] >> ppqualifiedname ; // #endregion ppendregion = no_node_d [ ch_p(T_MSEXT_PP_ENDREGION) [ store_found_directive_type(self.found_directive) ] ] ; #endif // # something else (ill formed preprocessor directive) illformed // for error reporting = no_node_d [ pattern_p(T_POUND, MainTokenMask) >> *ppsp ] >> ( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) >> no_node_d [ *( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) ] ; // #error pperror = no_node_d [ ch_p(T_PP_ERROR) [ store_found_directive_type(self.found_directive) ] >> *ppsp ] >> *( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) ; // #warning ppwarning = no_node_d [ ch_p(T_PP_WARNING) [ store_found_directive_type(self.found_directive) ] >> *ppsp ] >> *( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) ; // #pragma ... pppragma = no_node_d [ ch_p(T_PP_PRAGMA) [ store_found_directive_type(self.found_directive) ] ] >> *( anychar_p - (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF)) ) ; ppqualifiedname = no_node_d[*ppsp] >> ( ch_p(T_IDENTIFIER) | pattern_p(KeywordTokenType, TokenTypeMask|PPTokenFlag) | pattern_p(OperatorTokenType|AltExtTokenType, ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc. | pattern_p(BoolLiteralTokenType, TokenTypeMask|PPTokenFlag) // true/false ) ; // auxiliary helper rules ppsp // valid space in a line with a preprocessor directive = ch_p(T_SPACE) | ch_p(T_CCOMMENT) ; // end of line tokens eol_tokens = no_node_d [ *( ch_p(T_SPACE) | ch_p(T_CCOMMENT) ) >> ( ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF) [ store_found_eof_type(self.found_eof) ] ) ] ; BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_statement, TRACE_CPP_GRAMMAR); // BOOST_SPIRIT_DEBUG_TRACE_RULE(include_file, TRACE_CPP_GRAMMAR); // BOOST_SPIRIT_DEBUG_TRACE_RULE(system_include_file, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_include_file, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(undefine, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifdef, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifndef, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(ppif, TRACE_CPP_GRAMMAR); // BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelse, TRACE_CPP_GRAMMAR); // BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelif, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendif, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(ppline, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(pperror, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(ppwarning, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(illformed, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(ppsp, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(ppqualifiedname, TRACE_CPP_GRAMMAR); #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppregion, TRACE_CPP_GRAMMAR); BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendregion, TRACE_CPP_GRAMMAR); #endif } // start rule of this grammar rule_type const& start() const { return pp_statement; } }; bool &found_eof; TokenT &found_directive; ContainerT &found_eoltokens; cpp_grammar(bool &found_eof_, TokenT &found_directive_, ContainerT &found_eoltokens_) : found_eof(found_eof_), found_directive(found_directive_), found_eoltokens(found_eoltokens_) { BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "cpp_grammar", TRACE_CPP_GRAMMAR); } #if BOOST_WAVE_DUMP_PARSE_TREE != 0 // helper function and data to get readable names of the rules known to us struct map_ruleid_to_name : public std::map { typedef std::map base_type; void init_rule_id_to_name_map(cpp_grammar const &self) { struct { int parser_id; char const *rule_name; } init_ruleid_name_map[] = { { BOOST_WAVE_PP_STATEMENT_ID, "pp_statement" }, // { BOOST_WAVE_INCLUDE_FILE_ID, "include_file" }, // { BOOST_WAVE_SYSINCLUDE_FILE_ID, "system_include_file" }, { BOOST_WAVE_MACROINCLUDE_FILE_ID, "macro_include_file" }, { BOOST_WAVE_PLAIN_DEFINE_ID, "plain_define" }, { BOOST_WAVE_MACRO_PARAMETERS_ID, "macro_parameters" }, { BOOST_WAVE_MACRO_DEFINITION_ID, "macro_definition" }, { BOOST_WAVE_UNDEFINE_ID, "undefine" }, { BOOST_WAVE_IFDEF_ID, "ppifdef" }, { BOOST_WAVE_IFNDEF_ID, "ppifndef" }, { BOOST_WAVE_IF_ID, "ppif" }, { BOOST_WAVE_ELIF_ID, "ppelif" }, // { BOOST_WAVE_ELSE_ID, "ppelse" }, // { BOOST_WAVE_ENDIF_ID, "ppendif" }, { BOOST_WAVE_LINE_ID, "ppline" }, { BOOST_WAVE_ERROR_ID, "pperror" }, { BOOST_WAVE_WARNING_ID, "ppwarning" }, { BOOST_WAVE_PRAGMA_ID, "pppragma" }, { BOOST_WAVE_ILLFORMED_ID, "illformed" }, { BOOST_WAVE_PPSPACE_ID, "ppspace" }, { BOOST_WAVE_PPQUALIFIEDNAME_ID, "ppqualifiedname" }, #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0 { BOOST_WAVE_REGION_ID, "ppregion" }, { BOOST_WAVE_ENDREGION_ID, "ppendregion" }, #endif { 0 } }; // initialize parser_id to rule_name map for (int i = 0; 0 != init_ruleid_name_map[i].parser_id; ++i) base_type::insert(base_type::value_type( boost::spirit::classic::parser_id(init_ruleid_name_map[i].parser_id), std::string(init_ruleid_name_map[i].rule_name)) ); } }; mutable map_ruleid_to_name map_rule_id_to_name; #endif // WAVE_DUMP_PARSE_TREE != 0 }; /////////////////////////////////////////////////////////////////////////////// #undef TRACE_CPP_GRAMMAR /////////////////////////////////////////////////////////////////////////////// // // Special parse function generating a parse tree using a given node_factory. // /////////////////////////////////////////////////////////////////////////////// template inline boost::spirit::classic::tree_parse_info parsetree_parse(IteratorT const& first_, IteratorT const& last, boost::spirit::classic::parser const& p) { using namespace boost::spirit::classic; typedef pt_match_policy pt_match_policy_type; typedef scanner_policies scanner_policies_type; typedef scanner scanner_type; scanner_policies_type policies; IteratorT first = first_; scanner_type scan(first, last, policies); tree_match hit = p.derived().parse(scan); return tree_parse_info( first, hit, hit && (first == last), hit.length(), hit.trees); } /////////////////////////////////////////////////////////////////////////////// // // The following parse function is defined here, to allow the separation of // the compilation of the cpp_grammar from the function using it. // /////////////////////////////////////////////////////////////////////////////// #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0 #define BOOST_WAVE_GRAMMAR_GEN_INLINE #else #define BOOST_WAVE_GRAMMAR_GEN_INLINE inline #endif template BOOST_WAVE_GRAMMAR_GEN_INLINE boost::spirit::classic::tree_parse_info< LexIteratorT, typename cpp_grammar_gen::node_factory_type > cpp_grammar_gen::parse_cpp_grammar ( LexIteratorT const &first, LexIteratorT const &last, position_type const &act_pos, bool &found_eof, token_type &found_directive, token_container_type &found_eoltokens) { using namespace boost::spirit::classic; using namespace boost::wave; cpp_grammar g(found_eof, found_directive, found_eoltokens); tree_parse_info hit = parsetree_parse(first, last, g); #if BOOST_WAVE_DUMP_PARSE_TREE != 0 if (hit.match) { tree_to_xml (BOOST_WAVE_DUMP_PARSE_TREE_OUT, hit.trees, "", g.map_rule_id_to_name, &token_type::get_token_id, &token_type::get_token_value); } #endif return hit; } #undef BOOST_WAVE_GRAMMAR_GEN_INLINE /////////////////////////////////////////////////////////////////////////////// } // namespace grammars } // namespace wave } // namespace boost // the suffix header occurs after all of the code #ifdef BOOST_HAS_ABI_HEADERS #include BOOST_ABI_SUFFIX #endif #endif // !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED)