cpp_iterator.hpp
来自「support vector clustering for vc++」· HPP 代码 · 共 1,705 行 · 第 1/5 页
HPP
1,705 行
// 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();
// 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_GENERATEDNEWLINE, "\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);
}
must_emit_line_directive = false; // we are now in sync
return true;
}
must_emit_line_directive = false; // we are now in sync
return false;
}
///////////////////////////////////////////////////////////////////////////////
//
// 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);
// 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();
act_pos = act_token.get_position();
}
else if (!unput_queue.empty()
|| T_IDENTIFIER == id
|| IS_CATEGORY(id, KeywordTokenType)
|| IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType)
|| IS_CATEGORY(id, BoolLiteralTokenType))
{
// 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 impl {
template <typename ContexT, typename IteratorT>
bool next_token_is_pp_directive(ContexT &ctx, IteratorT &it, IteratorT const &end)
{
using namespace boost::wave;
token_id id = T_UNKNOWN;
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
ctx.get_hooks().skipped_token(*it); // this token get's skipped
}
BOOST_ASSERT(it == end || id != T_UNKNOWN);
return it != end && IS_CATEGORY(id, PPTokenType);
}
template <typename ContexT, typename IteratorT>
bool pp_is_last_on_line(ContexT &ctx, IteratorT &it, IteratorT const &end)
{
using namespace boost::wave;
ctx.get_hooks().skipped_token(*it); // this token get's skipped
for (++it; it != end; ++it) {
token_id id = token_id(*it);
if (T_CPPCOMMENT == id || T_NEWLINE == id ||
context_policies::util::ccomment_has_newline(*it))
{
ctx.get_hooks().skipped_token(*it);
++it; // skip eol/C/C++ comment
return true; // no more significant tokens on this line
}
if (!IS_CATEGORY(id, WhiteSpaceTokenType))
break;
ctx.get_hooks().skipped_token(*it); // this token get's skipped
}
return false;
}
template <typename ContexT, typename IteratorT>
bool skip_to_eol(ContexT &ctx, IteratorT &it, IteratorT const &end)
{
using namespace boost::wave;
for (/**/; it != end; ++it) {
token_id id = token_id(*it);
ctx.get_hooks().skipped_token(*it);
if (T_CPPCOMMENT == id || T_NEWLINE == id ||
context_policies::util::ccomment_has_newline(*it))
{
++it; // skip eol/C/C++ comment
return true; // found eol
}
}
return false;
}
}
///////////////////////////////////////////////////////////////////////////////
// can_ignore_pp_directive: handle certain pp_directives if if_block_status is
// false
template <typename ContextT>
template <typename IteratorT>
inline bool
pp_iterator_functor<ContextT>::can_ignore_pp_directive(IteratorT &it)
{
bool can_exit = true;
if (IS_EXTCATEGORY(*it, PPConditionalTokenType)) {
// simulate the if block hierarchy
switch (static_cast<unsigned int>(token_id(*it))) {
case T_PP_IFDEF: // #ifdef
case T_PP_IFNDEF: // #ifndef
case T_PP_IF: // #if
ctx.enter_if_block(false);
break;
case T_PP_ELIF: // #elif
if (!ctx.get_enclosing_if_block_status()) {
if (!ctx.enter_elif_block(false)) {
// #else without matching #if
BOOST_WAVE_THROW(preprocess_exception,
missing_matching_if, "#elif", act_pos);
}
}
else {
can_exit = false; // #elif is not always safe to skip
}
break;
case T_PP_ELSE: // #else
case T_PP_ENDIF: // #endif
{
// handle this directive
if (T_PP_ELSE == token_id(*it))
on_else();
else
on_endif();
// make sure, there are no (non-whitespace) tokens left on this line
string_type value ((*it).get_value());
if (!impl::pp_is_last_on_line(ctx, it, iter_ctx->last)) {
// enable error recovery (start over with the next line)
impl::skip_to_eol(ctx, it, iter_ctx->last);
seen_newline = true;
iter_ctx->first = it;
// report an invalid #else directive
on_illformed(value);
break;
}
// we skipped to the end of this line already
seen_newline = true;
iter_ctx->first = it;
}
return true;
default: // #something else
on_illformed((*it).get_value());
break;
}
}
// start over with the next line, if only possible
if (can_exit) {
string_type value ((*it).get_value());
if (!impl::skip_to_eol(ctx, it, iter_ctx->last)) {
// The line doesn't end with an eol but eof token.
seen_newline = true; // allow to resume after warning
iter_ctx->first = it;
// 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 true; // may be safely ignored
}
return false; // do not ignore this pp directive
}
///////////////////////////////////////////////////////////////////////////////
// pp_directive(): recognize a preprocessor directive
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 (!impl::next_token_is_pp_directive(ctx, 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 (impl::pp_is_last_on_line(ctx, it, iter_ctx->last)) {
// start over with the next line
seen_newline = true;
iter_ctx->first = it;
return true;
}
else if (ctx.get_if_block_status()) {
// report invalid pp directive
on_illformed((*it).get_value());
}
}
// this line does not contain a pp directive, so simply return
return false;
}
// found eof
if (it == iter_ctx->last)
return false;
// ignore/handle all pp directives not related to conditional compilation while
// if block status is false
if (!ctx.get_if_block_status() && can_ignore_pp_directive(it)) {
// we may skip pp directives only, if the current if block status is false
seen_newline = true;
iter_ctx->first = it;
return true; // the pp directive was handled/skipped
}
// found a pp directive, so try to identify it, start with the pp_token
bool found_eof = false;
result_type found_directive;
token_sequence_type found_eoltokens;
tree_parse_info_type hit = cpp_grammar_type::parse_cpp_grammar(
it, iter_ctx->last, act_pos, found_eof, found_directive, found_eoltokens);
if (hit.match) {
// position the iterator past the matched sequence to allow
// resynchronization, if an error occurs
iter_ctx->first = hit.stop;
seen_newline = true;
must_emit_line_directive = true;
// found a valid pp directive, dispatch to the correct function to handle
// the found pp directive
bool result = dispatch_directive (hit, found_directive, found_eoltokens);
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;
}
else if (token_id(found_directive) != T_EOF) {
// recognized invalid directive
impl::skip_to_eol(ctx, it, iter_ctx->last);
seen_newline = true;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?