insert_whitespace_detection.hpp 15.3 KB
Newer Older
xuebingbing's avatar
xuebingbing committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
/*=============================================================================
    Boost.Wave: A Standard compliant C++ preprocessor library

    Detect the need to insert a whitespace token into the output stream
    
    http://www.boost.org/

    Copyright (c) 2001-2012 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(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED)
#define INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED

#include <boost/wave/wave_config.hpp>   
#include <boost/wave/token_ids.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 util {

namespace impl {

// T_IDENTIFIER
    template <typename StringT>
    inline bool
    would_form_universal_char (StringT const &value)
    {
        if ('u' != value[0] && 'U' != value[0])
            return false;
        if ('u' == value[0] && value.size() < 5)
            return false;
        if ('U' == value[0] && value.size() < 9)
            return false;
    
    typename StringT::size_type pos = 
        value.find_first_not_of("0123456789abcdefABCDEF", 1);
        
        if (StringT::npos == pos || 
            ('u' == value[0] && pos > 5) ||
            ('U' == value[0] && pos > 9))
        {
            return true;        // would form an universal char
        }
        return false;
    }
    template <typename StringT>
    inline bool 
    handle_identifier(boost::wave::token_id prev, 
        boost::wave::token_id before, StringT const &value)
    {
        using namespace boost::wave;
        switch (static_cast<unsigned int>(prev)) {
        case T_IDENTIFIER:
        case T_NONREPLACABLE_IDENTIFIER:
        case T_COMPL_ALT:
        case T_OR_ALT:
        case T_AND_ALT:
        case T_NOT_ALT:
        case T_XOR_ALT:
        case T_ANDASSIGN_ALT:
        case T_ORASSIGN_ALT:
        case T_XORASSIGN_ALT:
        case T_NOTEQUAL_ALT:
        case T_FIXEDPOINTLIT:
            return true;

        case T_FLOATLIT:
        case T_INTLIT:
        case T_PP_NUMBER:
            return (value.size() > 1 || (value[0] != 'e' && value[0] != 'E'));
            
         // avoid constructing universal characters (\u1234)
        case TOKEN_FROM_ID('\\', UnknownTokenType):
            return would_form_universal_char(value);
        }
        return false;
    }
// T_INTLIT
    inline bool 
    handle_intlit(boost::wave::token_id prev, boost::wave::token_id /*before*/)
    {
        using namespace boost::wave;
        switch (static_cast<unsigned int>(prev)) {
        case T_IDENTIFIER:
        case T_NONREPLACABLE_IDENTIFIER:
        case T_INTLIT:
        case T_FLOATLIT:
        case T_FIXEDPOINTLIT:
        case T_PP_NUMBER:
            return true;
        }
        return false;
    }
// T_FLOATLIT
    inline bool 
    handle_floatlit(boost::wave::token_id prev, 
        boost::wave::token_id /*before*/)
    {
        using namespace boost::wave;
        switch (static_cast<unsigned int>(prev)) {
        case T_IDENTIFIER:
        case T_NONREPLACABLE_IDENTIFIER:
        case T_INTLIT:
        case T_FLOATLIT:
        case T_FIXEDPOINTLIT:
        case T_PP_NUMBER:
            return true;
        }
        return false;
    }
// <% T_LEFTBRACE
    inline bool 
    handle_alt_leftbrace(boost::wave::token_id prev, 
        boost::wave::token_id /*before*/)
    {
        using namespace boost::wave;
        switch (static_cast<unsigned int>(prev)) {
        case T_LESS:        // <<%
        case T_SHIFTLEFT:   // <<<%
            return true;
        }
        return false;
    }
// <: T_LEFTBRACKET
    inline bool 
    handle_alt_leftbracket(boost::wave::token_id prev, 
        boost::wave::token_id /*before*/)
    {
        using namespace boost::wave;
        switch (static_cast<unsigned int>(prev)) {
        case T_LESS:        // <<:
        case T_SHIFTLEFT:   // <<<:
            return true;
        }
        return false;
    }
// T_FIXEDPOINTLIT
    inline bool 
    handle_fixedpointlit(boost::wave::token_id prev, 
        boost::wave::token_id /*before*/)
    {
        using namespace boost::wave;
        switch (static_cast<unsigned int>(prev)) {
        case T_IDENTIFIER:
        case T_NONREPLACABLE_IDENTIFIER:
        case T_INTLIT:
        case T_FLOATLIT:
        case T_FIXEDPOINTLIT:
        case T_PP_NUMBER:
            return true;
        }
        return false;
    }
// T_DOT
    inline bool 
    handle_dot(boost::wave::token_id prev, boost::wave::token_id before)
    {
        using namespace boost::wave;
        switch (static_cast<unsigned int>(prev)) {
        case T_DOT:
            if (T_DOT == before)
                return true;    // ...
            break;
        }
        return false;
    }
// T_QUESTION_MARK
    inline bool 
    handle_questionmark(boost::wave::token_id prev, 
        boost::wave::token_id /*before*/)
    {
        using namespace boost::wave;
        switch(static_cast<unsigned int>(prev)) {
        case TOKEN_FROM_ID('\\', UnknownTokenType):     // \?
        case T_QUESTION_MARK:   // ??
            return true;
        }
        return false;
    }
// T_NEWLINE
    inline bool
    handle_newline(boost::wave::token_id prev, 
        boost::wave::token_id before)
    {
        using namespace boost::wave;
        switch(static_cast<unsigned int>(prev)) {
        case TOKEN_FROM_ID('\\', UnknownTokenType): // \ \n
        case T_DIVIDE:
            if (T_QUESTION_MARK == before)
                return true;    // ?/\n     // may be \\n
            break;
        }
        return false;
    }

    inline bool 
    handle_parens(boost::wave::token_id prev)
    {
        switch (static_cast<unsigned int>(prev)) {
        case T_LEFTPAREN:
        case T_RIGHTPAREN:
        case T_LEFTBRACKET:
        case T_RIGHTBRACKET:
        case T_LEFTBRACE:
        case T_RIGHTBRACE:
        case T_SEMICOLON:
        case T_COMMA:
        case T_COLON:
            // no insertion between parens/brackets/braces and operators
            return false;   

        default:
            break;
        }
        return true;
    }
        
}   // namespace impl

class insert_whitespace_detection 
{
public:
    insert_whitespace_detection(bool insert_whitespace_ = true) 
    :   insert_whitespace(insert_whitespace_),
        prev(boost::wave::T_EOF), beforeprev(boost::wave::T_EOF) 
    {}
    
    template <typename StringT>
    bool must_insert(boost::wave::token_id current, StringT const &value)
    {
        if (!insert_whitespace)
            return false;       // skip whitespace insertion alltogether
            
        using namespace boost::wave;
        switch (static_cast<unsigned int>(current)) {
        case T_NONREPLACABLE_IDENTIFIER:
        case T_IDENTIFIER: 
            return impl::handle_identifier(prev, beforeprev, value); 
        case T_PP_NUMBER:
        case T_INTLIT:
            return impl::handle_intlit(prev, beforeprev); 
        case T_FLOATLIT:
            return impl::handle_floatlit(prev, beforeprev); 
        case T_STRINGLIT:
            if (TOKEN_FROM_ID('L', IdentifierTokenType) == prev)       // 'L'
                return true;
            break;
        case T_LEFTBRACE_ALT:
            return impl::handle_alt_leftbrace(prev, beforeprev); 
        case T_LEFTBRACKET_ALT:
            return impl::handle_alt_leftbracket(prev, beforeprev); 
        case T_FIXEDPOINTLIT:
            return impl::handle_fixedpointlit(prev, beforeprev); 
        case T_DOT:
            return impl::handle_dot(prev, beforeprev); 
        case T_QUESTION_MARK:
            return impl::handle_questionmark(prev, beforeprev); 
        case T_NEWLINE:
            return impl::handle_newline(prev, beforeprev); 

        case T_LEFTPAREN:
        case T_RIGHTPAREN:
        case T_LEFTBRACKET:
        case T_RIGHTBRACKET:
        case T_SEMICOLON:
        case T_COMMA:
        case T_COLON:
            switch (static_cast<unsigned int>(prev)) {
            case T_LEFTPAREN:
            case T_RIGHTPAREN:
            case T_LEFTBRACKET:
            case T_RIGHTBRACKET:
            case T_LEFTBRACE:
            case T_RIGHTBRACE:
                return false;   // no insertion between parens/brackets/braces

            default:
                if (IS_CATEGORY(prev, OperatorTokenType))
                    return false;
                break;
            }        
            break;
            
        case T_LEFTBRACE:
        case T_RIGHTBRACE:
            switch (static_cast<unsigned int>(prev)) {
            case T_LEFTPAREN:
            case T_RIGHTPAREN:
            case T_LEFTBRACKET:
            case T_RIGHTBRACKET:
            case T_LEFTBRACE:
            case T_RIGHTBRACE:
            case T_SEMICOLON:
            case T_COMMA:
            case T_COLON:
                return false;   // no insertion between parens/brackets/braces

            case T_QUESTION_MARK:
                if (T_QUESTION_MARK == beforeprev)
                    return true;
                if (IS_CATEGORY(prev, OperatorTokenType))
                    return false;
                break;
                
            default:
                break;
            }
            break;
                            
        case T_MINUS:
        case T_MINUSMINUS:
        case T_MINUSASSIGN:
            if (T_MINUS == prev || T_MINUSMINUS == prev)
                return true;
            if (!impl::handle_parens(prev))
                return false;
            if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
                return true;
            break;
            
        case T_PLUS:
        case T_PLUSPLUS:
        case T_PLUSASSIGN:
            if (T_PLUS == prev || T_PLUSPLUS == prev)
                return true;
            if (!impl::handle_parens(prev))
                return false;
            if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
                return true;
            break;
            
        case T_DIVIDE:
        case T_DIVIDEASSIGN:
            if (T_DIVIDE == prev)
                return true;
            if (!impl::handle_parens(prev))
                return false;
            if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
                return true;
            break;
        
        case T_EQUAL:
        case T_ASSIGN:
            switch (static_cast<unsigned int>(prev)) {
            case T_PLUSASSIGN:
            case T_MINUSASSIGN:
            case T_DIVIDEASSIGN:
            case T_STARASSIGN:
            case T_SHIFTRIGHTASSIGN:
            case T_SHIFTLEFTASSIGN:
            case T_EQUAL:
            case T_NOTEQUAL:
            case T_LESSEQUAL:
            case T_GREATEREQUAL:
            case T_LESS:
            case T_GREATER:
            case T_PLUS:
            case T_MINUS:
            case T_STAR:
            case T_DIVIDE:
            case T_ORASSIGN:
            case T_ANDASSIGN:
            case T_XORASSIGN:
            case T_OR:
            case T_AND:
            case T_XOR:
            case T_OROR:
            case T_ANDAND:
                return true;

            case T_QUESTION_MARK:
                if (T_QUESTION_MARK == beforeprev)
                    return true;
                break;
                
            default:
                if (!impl::handle_parens(prev))
                    return false;
                break;
            }
            break;

        case T_GREATER:
            if (T_MINUS == prev || T_GREATER == prev)
                return true;    // prevent -> or >>
            if (!impl::handle_parens(prev))
                return false;
            if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
                return true;
            break;

        case T_LESS:
            if (T_LESS == prev)
                return true;    // prevent <<
            // fall through
        case T_CHARLIT:
        case T_NOT:
        case T_NOTEQUAL:
            if (!impl::handle_parens(prev))
                return false;
            if (T_QUESTION_MARK == prev && T_QUESTION_MARK == beforeprev)
                return true;
            break;

        case T_AND:
        case T_ANDAND:
            if (!impl::handle_parens(prev))
                return false;
            if (T_AND == prev || T_ANDAND == prev)
                return true;
            break;
            
        case T_OR:
            if (!impl::handle_parens(prev))
                return false;
            if (T_OR == prev)
                return true;
            break;
            
        case T_XOR:
            if (!impl::handle_parens(prev))
                return false;
            if (T_XOR == prev)
                return true;
            break;
            
        case T_COMPL_ALT:
        case T_OR_ALT:
        case T_AND_ALT:
        case T_NOT_ALT:
        case T_XOR_ALT:
        case T_ANDASSIGN_ALT:
        case T_ORASSIGN_ALT:
        case T_XORASSIGN_ALT:
        case T_NOTEQUAL_ALT:
            switch (static_cast<unsigned int>(prev)) {
            case T_LEFTPAREN:
            case T_RIGHTPAREN:
            case T_LEFTBRACKET:
            case T_RIGHTBRACKET:
            case T_LEFTBRACE:
            case T_RIGHTBRACE:
            case T_SEMICOLON:
            case T_COMMA:
            case T_COLON:
                // no insertion between parens/brackets/braces and operators
                return false;   

            case T_IDENTIFIER:
                if (T_NONREPLACABLE_IDENTIFIER == prev ||
                    IS_CATEGORY(prev, KeywordTokenType))
                {
                    return true;
                }
                break;
                
            default:
                break;
            }
            break;
            
        case T_STAR:
            if (T_STAR == prev)
                return false;     // '*****' do not need to be separated
            if (T_GREATER== prev && 
                (T_MINUS == beforeprev || T_MINUSMINUS == beforeprev)
               )
            {
                return true;    // prevent ->*
            }
            break;

        case T_POUND:
            if (T_POUND == prev)
                return true;
            break;
        }

    // FIXME: else, handle operators separately (will catch to many cases)
//         if (IS_CATEGORY(current, OperatorTokenType) && 
//             IS_CATEGORY(prev, OperatorTokenType))
//         {
//             return true;    // operators must be delimited always
//         }
        return false;
    }
    void shift_tokens (boost::wave::token_id next_id)
    {
        if (insert_whitespace) {
            beforeprev = prev;
            prev = next_id;
        }
    }
    
private:
    bool insert_whitespace;            // enable this component
    boost::wave::token_id prev;        // the previous analyzed token
    boost::wave::token_id beforeprev;  // the token before the previous
};

///////////////////////////////////////////////////////////////////////////////
}   //  namespace util
}   //  namespace wave 
}   //  namespace boost

// the suffix header occurs after all of the code
#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // !defined(INSERT_WHITESPACE_DETECTION_HPP_765EF77B_0513_4967_BDD6_6A38148C4C96_INCLUDED)