📄 cpp_grammar.hpp
字号:
/*=============================================================================
Boost.Wave: A Standard compliant C++ preprocessor library
http://www.boost.org/
Copyright (c) 2001-2007 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 <boost/spirit/core.hpp>
#include <boost/spirit/tree/parse_tree.hpp>
#include <boost/spirit/tree/parse_tree_utils.hpp>
#include <boost/spirit/utility/confix.hpp>
#include <boost/spirit/utility/lists.hpp>
#include <boost/wave/wave_config.hpp>
#include <boost/pool/pool_alloc.hpp>
#if BOOST_WAVE_DUMP_PARSE_TREE != 0
#include <map>
#include <boost/spirit/tree/tree_to_xml.hpp>
#endif
#include <boost/wave/token_ids.hpp>
#include <boost/wave/grammars/cpp_grammar_gen.hpp>
#include <boost/wave/util/pattern_parser.hpp>
#include <boost/wave/cpp_exceptions.hpp>
// 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 <typename TokenT>
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 <typename TokenT>
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 <typename ContainerT>
struct store_found_eoltokens {
store_found_eoltokens(ContainerT &found_eoltokens_)
: found_eoltokens(found_eoltokens_) {}
template <typename IteratorT>
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::parser<flush_underlying_parser>
{
typedef flush_underlying_parser this_t;
template <typename ScannerT>
typename boost::spirit::parser_result<this_t, ScannerT>::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 <typename TokenT, typename ContainerT>
struct cpp_grammar :
public boost::spirit::grammar<cpp_grammar<TokenT, ContainerT> >
{
typedef typename TokenT::position_type position_type;
typedef cpp_grammar<TokenT, ContainerT> grammar_type;
typedef impl::store_found_eof store_found_eof_type;
typedef impl::store_found_directive<TokenT> store_found_directive_type;
typedef impl::store_found_eoltokens<ContainerT> store_found_eoltokens_type;
template <typename ScannerT>
struct definition
{
// non-parse_tree generating rule type
typedef typename ScannerT::iteration_policy_t iteration_policy_t;
typedef boost::spirit::match_policy match_policy_t;
typedef typename ScannerT::action_policy_t action_policy_t;
typedef
boost::spirit::scanner_policies<
iteration_policy_t, match_policy_t, action_policy_t>
policies_t;
typedef
boost::spirit::scanner<typename ScannerT::iterator_t, policies_t>
non_tree_scanner_t;
typedef
boost::spirit::rule<non_tree_scanner_t, boost::spirit::dynamic_parser_tag>
no_tree_rule_type;
// 'normal' (parse_tree generating) rule type
typedef
boost::spirit::rule<ScannerT, boost::spirit::dynamic_parser_tag>
rule_type;
rule_type pp_statement;
rule_type include_file, system_include_file, macro_include_file;
rule_type plain_define, macro_definition, macro_parameters;
rule_type undefine;
rule_type ppifdef, ppifndef, ppif, ppelse, ppelif, 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;
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)
| pattern_p(OperatorTokenType|AltExtTokenType,
ExtTokenTypeMask) // and, bit_and etc.
| pattern_p(BoolLiteralTokenType, TokenTypeMask) // 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)
| pattern_p(OperatorTokenType|AltExtTokenType,
ExtTokenTypeMask) // and, bit_and etc.
| pattern_p(BoolLiteralTokenType, TokenTypeMask) // 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
[
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -