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 + -
显示快捷键?