📄 cpp_iterator.hpp
字号:
// Tests if it is necessary to pop the include file context (eof inside
// a file was reached). If yes, it pops this context. Preprocessing will
// continue with the next outer file scope.
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
inline bool
pp_iterator_functor<ContextT>::returned_from_include()
{
if (iter_ctx->first == iter_ctx->last && ctx.get_iteration_depth() > 0) {
// call the include policy trace function
ctx.get_trace_policy().returning_from_include_file();
// restore the previous iteration context after finishing the preprocessing
// of the included file
BOOST_WAVE_STRINGTYPE oldfile = iter_ctx->real_filename;
iter_ctx = ctx.pop_iteration_context();
// ensure the integrity of the #if/#endif stack
if (iter_ctx->if_block_depth != ctx.get_if_block_depth()) {
using boost::wave::util::impl::escape_lit;
BOOST_WAVE_THROW(preprocess_exception, unbalanced_if_endif,
escape_lit(oldfile).c_str(), act_pos);
}
must_emit_line_directive = true;
seen_newline = true;
// restore current file position
act_pos.set_file(iter_ctx->filename);
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
ctx.set_current_filename(iter_ctx->real_filename.c_str());
#endif
// last_line = iter_ctx->line;
act_pos.set_line(iter_ctx->line);
act_pos.set_column(0);
// restore the actual current directory
ctx.set_current_directory(iter_ctx->real_filename.c_str());
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
//
// operator()(): get the next preprocessed token
//
// throws a preprocess_exception, if appropriate
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
inline typename pp_iterator_functor<ContextT>::result_type const &
pp_iterator_functor<ContextT>::operator()()
{
using namespace boost::wave;
// loop over skipable whitespace until something significant is found
bool skipped_newline = false;
bool was_seen_newline = seen_newline;
token_id id = T_ANY;
do {
// get_next_token assigns result to act_token member
if (!seen_newline && skipped_newline)
seen_newline = true;
get_next_token();
// if comments shouldn't be preserved replace them with newlines
id = token_id(act_token);
if (!need_preserve_comments(ctx.get_language()) &&
(T_CPPCOMMENT == id || util::ccomment_has_newline(act_token)))
{
act_token.set_token_id(id = T_NEWLINE);
act_token.set_value("\n");
}
} while (eater.may_skip(act_token, skipped_newline));
// if there were skipped any newlines, we must emit a #line directive
if ((must_emit_line_directive || (was_seen_newline && skipped_newline)) &&
!IS_CATEGORY(id, WhiteSpaceTokenType) &&
!IS_CATEGORY(id, EOLTokenType) && !IS_CATEGORY(id, EOFTokenType))
{
// must emit a #line directive
emit_line_directive();
eater.may_skip(act_token, skipped_newline); // feed ws eater FSM
id = token_id(act_token);
}
// cleanup of certain tokens required
seen_newline = skipped_newline;
switch (static_cast<unsigned int>(id)) {
case T_NONREPLACABLE_IDENTIFIER:
act_token.set_token_id(T_IDENTIFIER);
break;
case T_NEWLINE:
case T_CPPCOMMENT:
seen_newline = true;
++iter_ctx->emitted_lines;
break;
case T_EOF:
seen_newline = true;
break;
default:
break;
}
if (whitespace.must_insert(id, act_token.get_value())) {
// must insert some whitespace into the output stream to avoid adjacent
// tokens, which would form different (and wrong) tokens
whitespace.shift_tokens(T_SPACE);
pending_queue.push_front(act_token); // push this token back
return act_token = result_type(T_SPACE,
typename result_type::string_type(" "),
act_token.get_position());
}
whitespace.shift_tokens(id);
return act_token;
}
template <typename ContextT>
inline typename pp_iterator_functor<ContextT>::result_type const &
pp_iterator_functor<ContextT>::get_next_token()
{
using namespace boost::wave;
// if there is something in the unput_queue, then return the next token from
// there (all tokens in the queue are preprocessed already)
if (pending_queue.size() > 0 || unput_queue.size() > 0)
return pp_token(); // return next token
// test for EOF, if there is a pending input context, pop it back and continue
// parsing with it
bool returned_from_include_file = returned_from_include();
// try to generate the next token
if (iter_ctx->first != iter_ctx->last) {
do {
// If there are pending tokens in the queue, we'll have to return
// these. This may happen from a #pragma directive, which got replaced
// by some token sequence.
if (!pending_queue.empty()) {
util::on_exit::pop_front<token_sequence_type>
pop_front_token(pending_queue);
whitespace.shift_tokens(act_token = pending_queue.front());
return act_token;
}
// fetch the current token
act_token = *iter_ctx->first;
// adjust the current position (line and column)
bool was_seen_newline = seen_newline || returned_from_include_file;
// int current_line = act_token.get_position().get_line();
//
// act_pos.set_line(act_pos.get_line() + current_line - last_line);
// act_pos.set_column(act_token.get_position().get_column());
// last_line = current_line;
act_pos = act_token.get_position();
// last_line = act_pos.get_line();
// act accordingly on the current token
token_id id = token_id(act_token);
if (T_EOF == id) {
if (!seen_newline &&
!(support_option_single_line & get_support_options(ctx.get_language())))
{
// warn, if this file does not end with a newline
BOOST_WAVE_THROW(preprocess_exception,
last_line_not_terminated, "", act_pos);
}
// returned from an include file, continue with the next token
whitespace.shift_tokens(T_EOF);
++iter_ctx->first;
continue; // if this is the main file, the while loop breaks
}
else if (T_NEWLINE == id || T_CPPCOMMENT == id) {
// a newline is to be returned ASAP, a C++ comment too
// (the C++ comment token includes the trailing newline)
seen_newline = true;
++iter_ctx->first;
whitespace.shift_tokens(id); // whitespace controller
if (!ctx.get_if_block_status()) {
// skip this token because of the disabled #if block
continue;
}
return act_token;
}
seen_newline = false;
if (was_seen_newline && pp_directive()) {
// a pp directive was found
seen_newline = true;
must_emit_line_directive = true;
// loop to the next token to analyze
// simply fall through, since the iterator was already adjusted
// correctly
}
else if (ctx.get_if_block_status()) {
// preprocess this token, eat up more, if appropriate, return
// the next preprocessed token
return pp_token(was_seen_newline);
}
else {
// compilation condition is false: if the current token is a
// newline, account for it, otherwise discard the actual token and
// try the next one
if (T_NEWLINE == act_token) {
seen_newline = true;
must_emit_line_directive = true;
}
// next token
++iter_ctx->first;
}
} while (iter_ctx->first != iter_ctx->last || returned_from_include());
}
if (returned_from_include_file) {
// if there was an '#include' statement on the last line of the main file
// we have to return an additional newline token
seen_newline = true;
whitespace.shift_tokens(T_NEWLINE); // whitespace controller
return act_token = result_type(T_NEWLINE,
typename result_type::string_type("\n"),
cpp_grammar_type::pos_of_newline);
}
// overall eof reached
if (ctx.get_if_block_depth() > 0) {
// missing endif directive(s)
BOOST_WAVE_THROW(preprocess_exception, missing_matching_endif, "",
act_pos);
}
whitespace.shift_tokens(T_EOF); // whitespace controller
return act_token = eof; // return eof token
}
///////////////////////////////////////////////////////////////////////////////
//
// emit_line_directive(): emits a line directive from the act_token data
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
inline typename pp_iterator_functor<ContextT>::result_type const &
pp_iterator_functor<ContextT>::emit_line_directive()
{
using namespace boost::wave;
typename ContextT::position_type pos = act_token.get_position();
if (must_emit_line_directive ||
iter_ctx->emitted_lines != act_pos.get_line())
{
// unput the current token
pending_queue.push_front(act_token);
pos.set_line(act_pos.get_line());
if (!must_emit_line_directive &&
iter_ctx->emitted_lines+1 == act_pos.get_line())
{
// prefer to output a single newline instead of the #line directive
whitespace.shift_tokens(T_NEWLINE);
act_token = result_type(T_NEWLINE, "\n", pos);
}
else {
// account for the newline emitted here
act_pos.set_line(act_pos.get_line()-1);
iter_ctx->emitted_lines = act_pos.get_line();
// --last_line;
// the #line directive has to be pushed back into the pending queue in
// reverse order
// unput the complete #line directive in reverse order
std::string file("\"");
boost::filesystem::path filename(act_pos.get_file().c_str(),
boost::filesystem::native);
using boost::wave::util::impl::escape_lit;
file += escape_lit(filename.native_file_string()) + "\"";
// 21 is the max required size for a 64 bit integer represented as a
// string
char buffer[22];
using namespace std; // for some systems sprintf is in namespace std
sprintf (buffer, "%d", pos.get_line());
// adjust the generated column numbers accordingly
// #line<space>number<space>filename<newline>
unsigned int filenamelen = (unsigned int)file.size();
unsigned int column = 7 + (unsigned int)strlen(buffer) + filenamelen;
pos.set_line(pos.get_line() - 1); // adjust line number
pos.set_column(column);
pending_queue.push_front(result_type(T_NEWLINE, "\n", pos));
pos.set_column(column -= filenamelen); // account for filename
pending_queue.push_front(result_type(T_STRINGLIT, file.c_str(), pos));
pos.set_column(--column); // account for ' '
pending_queue.push_front(result_type(T_SPACE, " ", pos));
pos.set_column(column -= (unsigned int)strlen(buffer)); // account for <number>
pending_queue.push_front(result_type(T_INTLIT, buffer, pos));
pos.set_column(--column); // account for ' '
pending_queue.push_front(result_type(T_SPACE, " ", pos));
// return the #line token itself
whitespace.shift_tokens(T_PP_LINE);
pos.set_column(1);
act_token = result_type(T_PP_LINE, "#line", pos);
}
}
// we are now in sync
must_emit_line_directive = false;
return act_token;
}
///////////////////////////////////////////////////////////////////////////////
//
// pptoken(): return the next preprocessed token
//
///////////////////////////////////////////////////////////////////////////////
template <typename ContextT>
inline typename pp_iterator_functor<ContextT>::result_type const &
pp_iterator_functor<ContextT>::pp_token(bool consider_emitting_line_directive)
{
using namespace boost::wave;
token_id id = token_id(*iter_ctx->first);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -