📄 cpp_iterator.hpp
字号:
// eat all T_PLACEHOLDER tokens, eventually slipped through out of the
// macro engine
do {
if (!pending_queue.empty()) {
// if there are pending tokens in the queue, return the first one
act_token = pending_queue.front();
pending_queue.pop_front();
}
else if (!unput_queue.empty()
|| T_IDENTIFIER == id
|| IS_CATEGORY(id, KeywordTokenType)
|| IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType))
{
// call the lexer, preprocess the required number of tokens, put them
// into the unput queue
act_token = ctx.expand_tokensequence(iter_ctx->first,
iter_ctx->last, pending_queue, unput_queue);
}
else {
// simply return the next token
act_token = *iter_ctx->first;
++iter_ctx->first;
}
id = token_id(act_token);
} while (T_PLACEHOLDER == id);
return act_token;
}
///////////////////////////////////////////////////////////////////////////////
//
// pp_directive(): recognize a preprocessor directive
//
///////////////////////////////////////////////////////////////////////////////
namespace {
template <typename IteratorT>
bool next_token_is_pp_directive(IteratorT &it, IteratorT const &end)
{
using namespace boost::wave;
token_id id = T_ANY;
for (/**/; it != end; ++it) {
id = token_id(*it);
if (!IS_CATEGORY(id, WhiteSpaceTokenType))
break; // skip leading whitespace
if (IS_CATEGORY(id, EOLTokenType))
break; // do not enter a new line
}
BOOST_ASSERT(it == end || id != T_ANY);
return it != end && IS_CATEGORY(id, PPTokenType);
}
template <typename IteratorT>
bool is_pp_null(IteratorT &it, IteratorT const &end)
{
using namespace boost::wave;
BOOST_ASSERT(T_POUND == BASE_TOKEN(token_id(*it)));
for (++it; it != end; ++it) {
token_id id = token_id(*it);
if (T_CPPCOMMENT == id || T_NEWLINE == id) {
++it; // skip eol/C++ comment
return true; // found pp_null
}
if (!IS_CATEGORY(id, WhiteSpaceTokenType))
break;
}
return false;
}
template <typename IteratorT>
bool skip_to_eol(IteratorT &it, IteratorT const &end)
{
using namespace boost::wave;
for (/**/; it != end; ++it) {
token_id id = token_id(*it);
if (T_CPPCOMMENT == id || T_NEWLINE == id) {
++it; // skip eol/C++ comment
return true; // found pp_null
}
}
return false;
}
}
template <typename ContextT>
inline bool
pp_iterator_functor<ContextT>::pp_directive()
{
using namespace cpplexer;
// test, if the next non-whitespace token is a pp directive
lexer_type it = iter_ctx->first;
if (!next_token_is_pp_directive(it, iter_ctx->last)) {
// eventually skip null pp directive (no need to do it via the parser)
if (it != iter_ctx->last && T_POUND == BASE_TOKEN(token_id(*it))) {
if (is_pp_null(it, iter_ctx->last)) {
seen_newline = true;
iter_ctx->first = it; // start over with the next line
return true;
}
else {
on_illformed((*it).get_value());
}
}
// this line does not contain a pp directive, so simply return
return false;
}
if (it == iter_ctx->last)
return false;
// ignore all pp directives not related to conditional compilation while
// if block status is false
if (!ctx.get_if_block_status() &&
!IS_EXTCATEGORY(*it, PPConditionalTokenType))
{
seen_newline = true;
skip_to_eol(it, iter_ctx->last);
iter_ctx->first = it; // start over with the next line
return true;
}
// found a pp directive, so try to identify it, start with the pp_token
bool found_eof = false;
boost::spirit::tree_parse_info<lexer_type> hit =
cpp_grammar_type::parse_cpp_grammar(it, iter_ctx->last, found_eof, act_pos);
if (hit.match) {
// position the iterator past the matched sequence to allow
// resynchronisation, if an error occurs
iter_ctx->first = hit.stop;
// found a valid pp directive, dispatch to the correct function to handle
// the found pp directive
bool result = dispatch_directive (hit);
if (found_eof) {
// The line was terminated with an end of file token.
// So trigger a warning, that the last line was not terminated with a
// newline.
BOOST_WAVE_THROW(preprocess_exception, last_line_not_terminated, "",
act_pos);
}
return result;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
//
// dispatch_directive(): dispatch a recognized preprocessor directive
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
inline bool
pp_iterator_functor<ContextT>::dispatch_directive(
boost::spirit::tree_parse_info<lexer_type> const &hit)
{
using namespace cpplexer;
using namespace boost::spirit;
typedef typename parse_tree_type::const_iterator const_child_iterator_t;
// this iterator points to the root node of the parse tree
const_child_iterator_t begin = hit.trees.begin();
// decide, which preprocessor directive was found
parse_tree_type const &root = (*begin).children;
parse_node_value_type const &nodeval = get_first_leaf(*root.begin()).value;
//long node_id = nodeval.id().to_long();
const_child_iterator_t begin_child_it = (*root.begin()).children.begin();
const_child_iterator_t end_child_it = (*root.begin()).children.end();
token_id id = cpp_grammar_type::found_directive;
switch (static_cast<unsigned int>(id)) {
case T_PP_QHEADER: // #include "..."
#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
case T_PP_QHEADER_NEXT: // #include_next "..."
#endif
on_include ((*nodeval.begin()).get_value(), false,
T_PP_QHEADER_NEXT == id);
break;
case T_PP_HHEADER: // #include <...>
#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
case T_PP_HHEADER_NEXT: // #include_next <...>
#endif
on_include ((*nodeval.begin()).get_value(), true,
T_PP_HHEADER_NEXT == id);
break;
case T_PP_INCLUDE: // #include ...
#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
case T_PP_INCLUDE_NEXT: // #include_next ...
#endif
on_include (begin_child_it, end_child_it, T_PP_INCLUDE_NEXT == id);
break;
case T_PP_DEFINE: // #define
on_define (*begin);
break;
case T_PP_UNDEF: // #undef
on_undefine(*nodeval.begin());
break;
case T_PP_IFDEF: // #ifdef
on_ifdef(begin_child_it, end_child_it);
break;
case T_PP_IFNDEF: // #ifndef
on_ifndef(begin_child_it, end_child_it);
break;
case T_PP_IF: // #if
on_if(begin_child_it, end_child_it);
break;
case T_PP_ELIF: // #elif
on_elif(begin_child_it, end_child_it);
break;
case T_PP_ELSE: // #else
on_else();
break;
case T_PP_ENDIF: // #endif
on_endif();
break;
case T_PP_LINE: // #line
on_line(begin_child_it, end_child_it);
break;
case T_PP_ERROR: // #error
on_error(begin_child_it, end_child_it);
break;
#if BOOST_WAVE_SUPPORT_WARNING_DIRECTIVE != 0
case T_PP_WARNING: // #warning
on_warning(begin_child_it, end_child_it);
break;
#endif
case T_PP_PRAGMA: // #pragma
return on_pragma(begin_child_it, end_child_it);
#if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
case T_MSEXT_PP_REGION:
case T_MSEXT_PP_ENDREGION:
break; // ignore these
#endif
default: // #something else
on_illformed((*nodeval.begin()).get_value());
break;
}
return true; // return newline only
}
///////////////////////////////////////////////////////////////////////////////
//
// on_include: handle #include <...> or #include "..." directives
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
inline void
pp_iterator_functor<ContextT>::on_include (string_type const &s,
bool is_system, bool include_next)
{
BOOST_ASSERT(ctx.get_if_block_status());
// strip quotes first, extract filename
typename string_type::size_type pos_end = s.find_last_of(is_system ? '>' : '\"');
if (string_type::npos == pos_end) {
BOOST_WAVE_THROW(preprocess_exception, bad_include_statement,
s.c_str(), act_pos);
}
typename string_type::size_type pos_begin =
s.find_last_of(is_system ? '<' : '\"', pos_end-1);
if (string_type::npos == pos_begin) {
BOOST_WAVE_THROW(preprocess_exception, bad_include_statement,
s.c_str(), act_pos);
}
std::string file_token(s.substr(pos_begin, pos_end-pos_begin+1).c_str());
std::string file_path(s.substr(pos_begin+1, pos_end-pos_begin-1).c_str());
// finally include the file
on_include_helper(file_token.c_str(), file_path.c_str(), is_system,
include_next);
}
template <typename ContextT>
inline void
pp_iterator_functor<ContextT>::on_include_helper (char const *f, char const *s,
bool is_system, bool include_next)
{
namespace fs = boost::filesystem;
// try to locate the given file, searching through the include path lists
std::string file_path(s);
std::string dir_path;
#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
char const *current_name = include_next ? iter_ctx->real_filename.c_str() : 0;
#else
char const *current_name = 0; // never try to match current file name
#endif
// call the include policy trace function
ctx.get_trace_policy().found_include_directive(f, include_next);
if (!ctx.find_include_file (file_path, dir_path, is_system, current_name)) {
BOOST_WAVE_THROW(preprocess_exception, bad_include_file,
file_path.c_str(), act_pos);
}
fs::path native_path(file_path, fs::native);
if (!fs::exists(native_path)) {
BOOST_WAVE_THROW(preprocess_exception, bad_include_file,
file_path.c_str(), act_pos);
}
// test, if this file is known through a #pragma once directive
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
if (!ctx.has_pragma_once(native_path.native_file_string()))
#endif
{
// the new include file determines the actual current directory
ctx.set_current_directory(native_path.native_file_string().c_str());
// preprocess the opened file
boost::shared_ptr<base_iteration_context_type> new_iter_ctx (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -