tools/icheck/parser/src/libs/cplusplus/pp-engine.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 /*
       
    42   Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
       
    43 
       
    44   Permission to use, copy, modify, distribute, and sell this software and its
       
    45   documentation for any purpose is hereby granted without fee, provided that
       
    46   the above copyright notice appear in all copies and that both that
       
    47   copyright notice and this permission notice appear in supporting
       
    48   documentation.
       
    49 
       
    50   The above copyright notice and this permission notice shall be included in
       
    51   all copies or substantial portions of the Software.
       
    52 
       
    53   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    54   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    55   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
       
    56   KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
       
    57   AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
       
    58   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       
    59 */
       
    60 
       
    61 #include "pp.h"
       
    62 #include "pp-cctype.h"
       
    63 
       
    64 #include <Lexer.h>
       
    65 #include <Token.h>
       
    66 #include <Literals.h>
       
    67 #include <cctype>
       
    68 
       
    69 #include <QtDebug>
       
    70 #include <algorithm>
       
    71 
       
    72 namespace CPlusPlus {
       
    73 
       
    74 struct Value
       
    75 {
       
    76     enum Kind {
       
    77         Kind_Long,
       
    78         Kind_ULong
       
    79     };
       
    80 
       
    81     Kind kind;
       
    82 
       
    83     union {
       
    84         long l;
       
    85         unsigned long ul;
       
    86     };
       
    87 
       
    88 
       
    89     Value()
       
    90         : kind(Kind_Long), l(0)
       
    91     { }
       
    92 
       
    93     inline bool is_ulong () const
       
    94     { return kind == Kind_ULong; }
       
    95 
       
    96     inline void set_ulong (unsigned long v)
       
    97     {
       
    98         ul = v;
       
    99         kind = Kind_ULong;
       
   100     }
       
   101 
       
   102     inline void set_long (long v)
       
   103     {
       
   104         l = v;
       
   105         kind = Kind_Long;
       
   106     }
       
   107 
       
   108     inline bool is_zero () const
       
   109     { return l == 0; }
       
   110 
       
   111 #define PP_DEFINE_BIN_OP(name, op) \
       
   112     inline Value operator op(const Value &other) const \
       
   113     { \
       
   114         Value v = *this; \
       
   115         if (v.is_ulong () || other.is_ulong ()) \
       
   116             v.set_ulong (v.ul op other.ul); \
       
   117         else \
       
   118             v.set_long (v.l op other.l); \
       
   119         return v; \
       
   120     }
       
   121 
       
   122     PP_DEFINE_BIN_OP(op_add, +)
       
   123     PP_DEFINE_BIN_OP(op_sub, -)
       
   124     PP_DEFINE_BIN_OP(op_mult, *)
       
   125     PP_DEFINE_BIN_OP(op_div, /)
       
   126     PP_DEFINE_BIN_OP(op_mod, %)
       
   127     PP_DEFINE_BIN_OP(op_lhs, <<)
       
   128     PP_DEFINE_BIN_OP(op_rhs, >>)
       
   129     PP_DEFINE_BIN_OP(op_lt, <)
       
   130     PP_DEFINE_BIN_OP(op_gt, >)
       
   131     PP_DEFINE_BIN_OP(op_le, <=)
       
   132     PP_DEFINE_BIN_OP(op_ge, >=)
       
   133     PP_DEFINE_BIN_OP(op_eq, ==)
       
   134     PP_DEFINE_BIN_OP(op_ne, !=)
       
   135     PP_DEFINE_BIN_OP(op_bit_and, &)
       
   136     PP_DEFINE_BIN_OP(op_bit_or, |)
       
   137     PP_DEFINE_BIN_OP(op_bit_xor, ^)
       
   138     PP_DEFINE_BIN_OP(op_and, &&)
       
   139     PP_DEFINE_BIN_OP(op_or, ||)
       
   140 
       
   141 #undef PP_DEFINE_BIN_OP
       
   142 };
       
   143 
       
   144 } // end of namespace CPlusPlus
       
   145 
       
   146 
       
   147 using namespace CPlusPlus;
       
   148 
       
   149 
       
   150 namespace {
       
   151 
       
   152 bool isMacroDefined(QByteArray name, unsigned offset, Environment *env, Client *client)
       
   153 {
       
   154     Macro *m = env->resolve(name);
       
   155     if (client) {
       
   156         if (m)
       
   157             client->passedMacroDefinitionCheck(offset, *m);
       
   158         else
       
   159             client->failedMacroDefinitionCheck(offset, name);
       
   160     }
       
   161     return m != 0;
       
   162 }
       
   163 
       
   164 class RangeLexer
       
   165 {
       
   166     const Token *first;
       
   167     const Token *last;
       
   168     Token trivial;
       
   169 
       
   170 public:
       
   171     inline RangeLexer(const Token *first, const Token *last)
       
   172         : first(first), last(last)
       
   173     {
       
   174         // WARN: `last' must be a valid iterator.
       
   175         trivial.offset = last->offset;
       
   176     }
       
   177 
       
   178     inline operator bool() const
       
   179     { return first != last; }
       
   180 
       
   181     inline bool isValid() const
       
   182     { return first != last; }
       
   183 
       
   184     inline int size() const
       
   185     { return std::distance(first, last); }
       
   186 
       
   187     inline const Token *dot() const
       
   188     { return first; }
       
   189 
       
   190     inline const Token &operator*() const
       
   191     {
       
   192         if (first != last)
       
   193             return *first;
       
   194 
       
   195         return trivial;
       
   196     }
       
   197 
       
   198     inline const Token *operator->() const
       
   199     {
       
   200         if (first != last)
       
   201             return first;
       
   202 
       
   203         return &trivial;
       
   204     }
       
   205 
       
   206     inline RangeLexer &operator++()
       
   207     {
       
   208         ++first;
       
   209         return *this;
       
   210     }
       
   211 };
       
   212 
       
   213 class ExpressionEvaluator
       
   214 {
       
   215     ExpressionEvaluator(const ExpressionEvaluator &other);
       
   216     void operator = (const ExpressionEvaluator &other);
       
   217 
       
   218 public:
       
   219     ExpressionEvaluator(Client *client, Environment *env)
       
   220         : client(client), env(env), _lex(0)
       
   221     { }
       
   222 
       
   223     Value operator()(const Token *firstToken, const Token *lastToken,
       
   224                      const QByteArray &source)
       
   225     {
       
   226         this->source = source;
       
   227         const Value previousValue = switchValue(Value());
       
   228         RangeLexer tmp(firstToken, lastToken);
       
   229         RangeLexer *previousLex = _lex;
       
   230         _lex = &tmp;
       
   231         process_expression();
       
   232         _lex = previousLex;
       
   233         return switchValue(previousValue);
       
   234     }
       
   235 
       
   236 protected:
       
   237     Value switchValue(const Value &value)
       
   238     {
       
   239         Value previousValue = _value;
       
   240         _value = value;
       
   241         return previousValue;
       
   242     }
       
   243 
       
   244     bool isTokenDefined() const
       
   245     {
       
   246         if ((*_lex)->isNot(T_IDENTIFIER))
       
   247             return false;
       
   248         const QByteArray spell = tokenSpell();
       
   249         if (spell.size() != 7)
       
   250             return false;
       
   251         return spell == "defined";
       
   252     }
       
   253 
       
   254     QByteArray tokenSpell() const
       
   255     {
       
   256         const QByteArray text = QByteArray::fromRawData(source.constData() + (*_lex)->offset,
       
   257                                                         (*_lex)->f.length);
       
   258         return text;
       
   259     }
       
   260 
       
   261     inline void process_expression()
       
   262     { process_constant_expression(); }
       
   263 
       
   264     void process_primary()
       
   265     {
       
   266         if ((*_lex)->is(T_NUMERIC_LITERAL)) {
       
   267             int base = 10;
       
   268             const QByteArray spell = tokenSpell();
       
   269             if (spell.at(0) == '0') {
       
   270                 if (spell.size() > 1 && (spell.at(1) == 'x' || spell.at(1) == 'X'))
       
   271                     base = 16;
       
   272                 else
       
   273                     base = 8;
       
   274             }
       
   275             _value.set_long(tokenSpell().toLong(0, base));
       
   276             ++(*_lex);
       
   277         } else if (isTokenDefined()) {
       
   278             ++(*_lex);
       
   279             if ((*_lex)->is(T_IDENTIFIER)) {
       
   280                 _value.set_long(isMacroDefined(tokenSpell(), (*_lex)->offset, env, client));
       
   281                 ++(*_lex);
       
   282             } else if ((*_lex)->is(T_LPAREN)) {
       
   283                 ++(*_lex);
       
   284                 if ((*_lex)->is(T_IDENTIFIER)) {
       
   285                     _value.set_long(isMacroDefined(tokenSpell(), (*_lex)->offset, env, client));
       
   286                     ++(*_lex);
       
   287                     if ((*_lex)->is(T_RPAREN)) {
       
   288                         ++(*_lex);
       
   289                     }
       
   290                 }
       
   291             }
       
   292         } else if ((*_lex)->is(T_IDENTIFIER)) {
       
   293             _value.set_long(0);
       
   294             ++(*_lex);
       
   295         } else if ((*_lex)->is(T_MINUS)) {
       
   296             ++(*_lex);
       
   297             process_primary();
       
   298             _value.set_long(- _value.l);
       
   299         } else if ((*_lex)->is(T_PLUS)) {
       
   300             ++(*_lex);
       
   301             process_primary();
       
   302         } else if ((*_lex)->is(T_EXCLAIM)) {
       
   303             ++(*_lex);
       
   304             process_primary();
       
   305             _value.set_long(_value.is_zero());
       
   306         } else if ((*_lex)->is(T_LPAREN)) {
       
   307             ++(*_lex);
       
   308             process_expression();
       
   309             if ((*_lex)->is(T_RPAREN))
       
   310                 ++(*_lex);
       
   311         }
       
   312     }
       
   313 
       
   314     Value process_expression_with_operator_precedence(const Value &lhs, int minPrecedence)
       
   315     {
       
   316         Value result = lhs;
       
   317 
       
   318         while (precedence((*_lex)->kind()) >= minPrecedence) {
       
   319             const int oper = (*_lex)->kind();
       
   320             const int operPrecedence = precedence(oper);
       
   321             ++(*_lex);
       
   322             process_primary();
       
   323             Value rhs = _value;
       
   324 
       
   325             for (int LA_token_kind = (*_lex)->kind(), LA_precedence = precedence(LA_token_kind);
       
   326                     LA_precedence > operPrecedence && isBinaryOperator(LA_token_kind);
       
   327                     LA_token_kind = (*_lex)->kind(), LA_precedence = precedence(LA_token_kind)) {
       
   328                 rhs = process_expression_with_operator_precedence(rhs, LA_precedence);
       
   329             }
       
   330 
       
   331             result = evaluate_expression(oper, result, rhs);
       
   332         }
       
   333 
       
   334         return result;
       
   335     }
       
   336 
       
   337     void process_constant_expression()
       
   338     {
       
   339         process_primary();
       
   340         _value = process_expression_with_operator_precedence(_value, precedence(T_PIPE_PIPE));
       
   341 
       
   342         if ((*_lex)->is(T_QUESTION)) {
       
   343             const Value cond = _value;
       
   344             ++(*_lex);
       
   345             process_constant_expression();
       
   346             Value left = _value, right;
       
   347             if ((*_lex)->is(T_COLON)) {
       
   348                 ++(*_lex);
       
   349                 process_constant_expression();
       
   350                 right = _value;
       
   351             }
       
   352             _value = ! cond.is_zero() ? left : right;
       
   353         }
       
   354     }
       
   355 
       
   356 private:
       
   357     inline int precedence(int tokenKind) const
       
   358     {
       
   359         switch (tokenKind) {
       
   360         case T_PIPE_PIPE:       return 0;
       
   361         case T_AMPER_AMPER:     return 1;
       
   362         case T_PIPE:            return 2;
       
   363         case T_CARET:           return 3;
       
   364         case T_AMPER:           return 4;
       
   365         case T_EQUAL_EQUAL:
       
   366         case T_EXCLAIM_EQUAL:   return 5;
       
   367         case T_GREATER:
       
   368         case T_LESS:
       
   369         case T_LESS_EQUAL:
       
   370         case T_GREATER_EQUAL:   return 6;
       
   371         case T_LESS_LESS:
       
   372         case T_GREATER_GREATER: return 7;
       
   373         case T_PLUS:
       
   374         case T_MINUS:           return 8;
       
   375         case T_STAR:
       
   376         case T_SLASH:
       
   377         case T_PERCENT:         return 9;
       
   378 
       
   379         default:
       
   380             return -1;
       
   381         }
       
   382     }
       
   383 
       
   384     static inline bool isBinaryOperator(int tokenKind)
       
   385     {
       
   386         switch (tokenKind) {
       
   387         case T_PIPE_PIPE:
       
   388         case T_AMPER_AMPER:
       
   389         case T_PIPE:
       
   390         case T_CARET:
       
   391         case T_AMPER:
       
   392         case T_EQUAL_EQUAL:
       
   393         case T_EXCLAIM_EQUAL:
       
   394         case T_GREATER:
       
   395         case T_LESS:
       
   396         case T_LESS_EQUAL:
       
   397         case T_GREATER_EQUAL:
       
   398         case T_LESS_LESS:
       
   399         case T_GREATER_GREATER:
       
   400         case T_PLUS:
       
   401         case T_MINUS:
       
   402         case T_STAR:
       
   403         case T_SLASH:
       
   404         case T_PERCENT:
       
   405             return true;
       
   406 
       
   407         default:
       
   408             return false;
       
   409         }
       
   410     }
       
   411 
       
   412     static inline Value evaluate_expression(int tokenKind, const Value &lhs, const Value &rhs)
       
   413     {
       
   414         switch (tokenKind) {
       
   415         case T_PIPE_PIPE:       return lhs || rhs;
       
   416         case T_AMPER_AMPER:     return lhs && rhs;
       
   417         case T_PIPE:            return lhs | rhs;
       
   418         case T_CARET:           return lhs ^ rhs;
       
   419         case T_AMPER:           return lhs & rhs;
       
   420         case T_EQUAL_EQUAL:     return lhs == rhs;
       
   421         case T_EXCLAIM_EQUAL:   return lhs != rhs;
       
   422         case T_GREATER:         return lhs > rhs;
       
   423         case T_LESS:            return lhs < rhs;
       
   424         case T_LESS_EQUAL:      return lhs <= rhs;
       
   425         case T_GREATER_EQUAL:   return lhs >= rhs;
       
   426         case T_LESS_LESS:       return lhs << rhs;
       
   427         case T_GREATER_GREATER: return lhs >> rhs;
       
   428         case T_PLUS:            return lhs + rhs;
       
   429         case T_MINUS:           return lhs - rhs;
       
   430         case T_STAR:            return lhs * rhs;
       
   431         case T_SLASH:           return rhs.is_zero() ? Value() : lhs / rhs;
       
   432         case T_PERCENT:         return rhs.is_zero() ? Value() : lhs % rhs;
       
   433 
       
   434         default:
       
   435             return Value();
       
   436         }
       
   437     }
       
   438 
       
   439 private:
       
   440     Client *client;
       
   441     Environment *env;
       
   442     QByteArray source;
       
   443     RangeLexer *_lex;
       
   444     Value _value;
       
   445 };
       
   446 
       
   447 } // end of anonymous namespace
       
   448 
       
   449 
       
   450 Preprocessor::Preprocessor(Client *client, Environment *env)
       
   451     : client(client),
       
   452       env(env),
       
   453       _expand(env),
       
   454       _skipping(MAX_LEVEL),
       
   455       _trueTest(MAX_LEVEL),
       
   456       _dot(_tokens.end()),
       
   457       _result(0),
       
   458       _markGeneratedTokens(false),
       
   459       _expandMacros(true)
       
   460 {
       
   461     resetIfLevel ();
       
   462 }
       
   463 
       
   464 void Preprocessor::pushState(const State &s)
       
   465 {
       
   466     _savedStates.append(state());
       
   467     _source = s.source;
       
   468     _tokens = s.tokens;
       
   469     _dot = s.dot;
       
   470 }
       
   471 
       
   472 Preprocessor::State Preprocessor::state() const
       
   473 {
       
   474     State state;
       
   475     state.source = _source;
       
   476     state.tokens = _tokens;
       
   477     state.dot = _dot;
       
   478     return state;
       
   479 }
       
   480 
       
   481 void Preprocessor::popState()
       
   482 {
       
   483     const State &state = _savedStates.last();
       
   484     _source = state.source;
       
   485     _tokens = state.tokens;
       
   486     _dot = state.dot;
       
   487     _savedStates.removeLast();
       
   488 }
       
   489 
       
   490 QByteArray Preprocessor::operator()(const QString &fileName, const QString &source)
       
   491 {
       
   492     const QString previousOriginalSource = _originalSource;
       
   493     _originalSource = source;
       
   494     const QByteArray bytes = source.toLatin1();
       
   495     const QByteArray preprocessedCode = operator()(fileName, bytes);
       
   496     _originalSource = previousOriginalSource;
       
   497     return preprocessedCode;
       
   498 }
       
   499 
       
   500 QByteArray Preprocessor::operator()(const QString &fileName,
       
   501                                     const QByteArray &source)
       
   502 {
       
   503     QByteArray preprocessed;
       
   504     preprocess(fileName, source, &preprocessed);
       
   505     return preprocessed;
       
   506 }
       
   507 
       
   508 QByteArray Preprocessor::expand(const QByteArray &source)
       
   509 {
       
   510     QByteArray result;
       
   511     result.reserve(256);
       
   512     expand(source, &result);
       
   513     return result;
       
   514 }
       
   515 
       
   516 void Preprocessor::expand(const QByteArray &source, QByteArray *result)
       
   517 {
       
   518     if (result)
       
   519         _expand(source, result);
       
   520 }
       
   521 
       
   522 void Preprocessor::expand(const char *first, const char *last, QByteArray *result)
       
   523 {
       
   524     const QByteArray source = QByteArray::fromRawData(first, last - first);
       
   525     return expand(source, result);
       
   526 }
       
   527 
       
   528 void Preprocessor::out(const QByteArray &text)
       
   529 {
       
   530     if (_result)
       
   531         _result->append(text);
       
   532 }
       
   533 
       
   534 void Preprocessor::out(char ch)
       
   535 {
       
   536     if (_result)
       
   537         _result->append(ch);
       
   538 }
       
   539 
       
   540 void Preprocessor::out(const char *s)
       
   541 {
       
   542     if (_result)
       
   543         _result->append(s);
       
   544 }
       
   545 
       
   546 bool Preprocessor::expandMacros() const
       
   547 {
       
   548     return _expandMacros;
       
   549 }
       
   550 
       
   551 void Preprocessor::setExpandMacros(bool expandMacros)
       
   552 {
       
   553     _expandMacros = expandMacros;
       
   554 }
       
   555 
       
   556 Preprocessor::State Preprocessor::createStateFromSource(const QByteArray &source) const
       
   557 {
       
   558     State state;
       
   559     state.source = source;
       
   560     Lexer lex(state.source.constBegin(), state.source.constEnd());
       
   561     lex.setScanKeywords(false);
       
   562     Token tok;
       
   563     do {
       
   564         lex(&tok);
       
   565         state.tokens.append(tok);
       
   566     } while (tok.isNot(T_EOF_SYMBOL));
       
   567     state.dot = state.tokens.constBegin();
       
   568     return state;
       
   569 }
       
   570 
       
   571 void Preprocessor::processNewline(bool force)
       
   572 {
       
   573     if (_dot != _tokens.constBegin()) {
       
   574         TokenIterator prevTok = _dot - 1;
       
   575 
       
   576         if (prevTok->isLiteral()) {
       
   577             const char *ptr = _source.constBegin() + prevTok->begin();
       
   578             const char *end = ptr + prevTok->length();
       
   579 
       
   580             for (; ptr != end; ++ptr) {
       
   581                 if (*ptr == '\n')
       
   582                     ++env->currentLine;
       
   583             }
       
   584         }
       
   585     }
       
   586 
       
   587     if (! force && env->currentLine == _dot->lineno)
       
   588         return;
       
   589 
       
   590     if (force || env->currentLine > _dot->lineno) {
       
   591         out("\n# ");
       
   592         out(QByteArray::number(_dot->lineno));
       
   593         out(' ');
       
   594         out('"');
       
   595         out(env->currentFile.toUtf8());
       
   596         out('"');
       
   597         out('\n');
       
   598     } else {
       
   599         for (unsigned i = env->currentLine; i < _dot->lineno; ++i)
       
   600             out('\n');
       
   601     }
       
   602 
       
   603     env->currentLine = _dot->lineno;
       
   604 }
       
   605 
       
   606 void Preprocessor::processSkippingBlocks(bool skippingBlocks,
       
   607                                          TokenIterator start, TokenIterator /*end*/)
       
   608 {
       
   609     if (! client)
       
   610         return;
       
   611 
       
   612     if (skippingBlocks != _skipping[iflevel]) {
       
   613         unsigned offset = start->offset;
       
   614 
       
   615         if (_skipping[iflevel]) {
       
   616             if (_dot->f.newline)
       
   617                 ++offset;
       
   618 
       
   619             client->startSkippingBlocks(offset);
       
   620 
       
   621         } else {
       
   622             if (offset)
       
   623                 --offset;
       
   624 
       
   625             client->stopSkippingBlocks(offset);
       
   626         }
       
   627     }
       
   628 }
       
   629 
       
   630 bool Preprocessor::markGeneratedTokens(bool markGeneratedTokens,
       
   631                                        TokenIterator dot)
       
   632 {
       
   633     bool previous = _markGeneratedTokens;
       
   634     _markGeneratedTokens = markGeneratedTokens;
       
   635 
       
   636     if (previous != _markGeneratedTokens) {
       
   637         if (! dot)
       
   638             dot = _dot;
       
   639 
       
   640         if (_markGeneratedTokens)
       
   641             out("\n#gen true");
       
   642         else
       
   643             out("\n#gen false");
       
   644 
       
   645         processNewline(/*force = */ true);
       
   646 
       
   647         const char *begin = _source.constBegin();
       
   648         const char *end   = begin;
       
   649 
       
   650         if (markGeneratedTokens)
       
   651             end += dot->begin();
       
   652         else
       
   653             end += (dot - 1)->end();
       
   654 
       
   655         const char *it = end - 1;
       
   656         for (; it != begin - 1; --it) {
       
   657             if (*it == '\n')
       
   658                 break;
       
   659         }
       
   660         ++it;
       
   661 
       
   662         for (; it != end; ++it) {
       
   663             if (! pp_isspace(*it))
       
   664                 out(' ');
       
   665 
       
   666             else
       
   667                 out(*it);
       
   668         }
       
   669 
       
   670         if (! markGeneratedTokens && dot->f.newline)
       
   671             processNewline(/*force = */ true);
       
   672     }
       
   673 
       
   674     return previous;
       
   675 }
       
   676 
       
   677 void Preprocessor::preprocess(const QString &fileName, const QByteArray &source,
       
   678                               QByteArray *result)
       
   679 {
       
   680     const int previousIfLevel = iflevel;
       
   681 
       
   682     QByteArray *previousResult = _result;
       
   683     _result = result;
       
   684 
       
   685     pushState(createStateFromSource(source));
       
   686 
       
   687     const QString previousFileName = env->currentFile;
       
   688     env->currentFile = fileName;
       
   689 
       
   690     const unsigned previousCurrentLine = env->currentLine;
       
   691     env->currentLine = 0;
       
   692 
       
   693     while (true) {
       
   694 
       
   695         if (_dot->f.joined)
       
   696             out("\\");
       
   697 
       
   698         processNewline();
       
   699 
       
   700         if (_dot->is(T_EOF_SYMBOL)) {
       
   701             break;
       
   702 
       
   703         } else if (_dot->is(T_POUND) && (! _dot->f.joined && _dot->f.newline)) {
       
   704             // handle the preprocessor directive
       
   705 
       
   706             TokenIterator start = _dot;
       
   707             do {
       
   708                 ++_dot;
       
   709             } while (_dot->isNot(T_EOF_SYMBOL) && (_dot->f.joined || ! _dot->f.newline));
       
   710 
       
   711             const bool skippingBlocks = _skipping[iflevel];
       
   712 
       
   713             processDirective(start, _dot);
       
   714             processSkippingBlocks(skippingBlocks, start, _dot);
       
   715 
       
   716         } else if (skipping()) {
       
   717             // skip the current line
       
   718 
       
   719             do {
       
   720                 ++_dot;
       
   721             } while (_dot->isNot(T_EOF_SYMBOL) && (_dot->f.joined || ! _dot->f.newline));
       
   722 
       
   723         } else {
       
   724 
       
   725             if (_dot->f.whitespace) {
       
   726                 unsigned endOfPreviousToken = 0;
       
   727 
       
   728                 if (_dot != _tokens.constBegin())
       
   729                     endOfPreviousToken = (_dot - 1)->end();
       
   730 
       
   731                 const unsigned beginOfToken = _dot->begin();
       
   732 
       
   733                 const char *start = _source.constBegin() + endOfPreviousToken;
       
   734                 const char *end = _source.constBegin() + beginOfToken;
       
   735 
       
   736                 const char *it = end - 1;
       
   737                 for (; it != start - 1; --it) {
       
   738                     if (*it == '\n')
       
   739                         break;
       
   740                 }
       
   741                 ++it;
       
   742 
       
   743                 for (; it != end; ++it) {
       
   744                     if (pp_isspace(*it))
       
   745                         out(*it);
       
   746 
       
   747                     else
       
   748                         out(' ');
       
   749                 }
       
   750             }
       
   751 
       
   752             if (_dot->isNot(T_IDENTIFIER)) {
       
   753                 out(tokenSpell(*_dot));
       
   754                 ++_dot;
       
   755 
       
   756             } else {
       
   757                 const TokenIterator identifierToken = _dot;
       
   758                 ++_dot; // skip T_IDENTIFIER
       
   759 
       
   760                 const QByteArray spell = tokenSpell(*identifierToken);
       
   761                 if (! _expandMacros) {
       
   762                     if (! env->isBuiltinMacro(spell)) {
       
   763                         Macro *m = env->resolve(spell);
       
   764                         if (m && ! m->isFunctionLike()) {
       
   765                             QByteArray expandedDefinition;
       
   766                             expandObjectLikeMacro(identifierToken, spell, m, &expandedDefinition);
       
   767                             if (expandedDefinition.trimmed().isEmpty()) {
       
   768                                 out(QByteArray(spell.length(), ' '));
       
   769                                 continue;
       
   770                             }
       
   771                         }
       
   772                     }
       
   773                     out(spell);
       
   774                     continue;
       
   775                 }
       
   776 
       
   777                 else if (env->isBuiltinMacro(spell))
       
   778                     expandBuiltinMacro(identifierToken, spell);
       
   779 
       
   780                 else {
       
   781 #ifdef ICHECK_BUILD
       
   782                     if(spell != "Q_PROPERTY" && spell != "Q_INVOKABLE" && spell != "Q_ENUMS"
       
   783                         && spell != "Q_FLAGS" && spell != "Q_DECLARE_FLAGS"){
       
   784 #endif
       
   785                         if (Macro *m = env->resolve(spell)) {
       
   786                             if (! m->isFunctionLike()) {
       
   787                                 if (0 == (m = processObjectLikeMacro(identifierToken, spell, m)))
       
   788                                     continue;
       
   789 
       
   790                                 // the macro expansion generated something that looks like
       
   791                                 // a function-like macro.
       
   792                             }
       
   793 
       
   794                             // `m' is function-like macro.
       
   795                             if (_dot->is(T_LPAREN)) {
       
   796                                 QVector<MacroArgumentReference> actuals;
       
   797                                 collectActualArguments(&actuals);
       
   798 
       
   799                                 if (_dot->is(T_RPAREN)) {
       
   800                                     expandFunctionLikeMacro(identifierToken, m, actuals);
       
   801                                     continue;
       
   802                                 }
       
   803                             }
       
   804                         }
       
   805 #ifdef ICHECK_BUILD
       
   806                     }
       
   807 #endif
       
   808                     // it's not a function or object-like macro.
       
   809                     out(spell);
       
   810                 }
       
   811             }
       
   812         }
       
   813     }
       
   814 
       
   815     popState();
       
   816 
       
   817     env->currentFile = previousFileName;
       
   818     env->currentLine = previousCurrentLine;
       
   819     _result = previousResult;
       
   820 
       
   821     iflevel = previousIfLevel;
       
   822 }
       
   823 
       
   824 void Preprocessor::collectActualArguments(QVector<MacroArgumentReference> *actuals)
       
   825 {
       
   826     if (_dot->isNot(T_LPAREN))
       
   827         return;
       
   828 
       
   829     ++_dot;
       
   830 
       
   831     if (_dot->is(T_RPAREN))
       
   832         return;
       
   833 
       
   834     actuals->append(collectOneActualArgument());
       
   835 
       
   836     while (_dot->is(T_COMMA)) {
       
   837         ++_dot;
       
   838 
       
   839         actuals->append(collectOneActualArgument());
       
   840     }
       
   841 }
       
   842 
       
   843 MacroArgumentReference Preprocessor::collectOneActualArgument()
       
   844 {
       
   845     const unsigned position = _dot->begin();
       
   846 
       
   847     while (_dot->isNot(T_EOF_SYMBOL)) {
       
   848         if (_dot->is(T_COMMA) || _dot->is(T_RPAREN))
       
   849             break;
       
   850 
       
   851         if (_dot->isNot(T_LPAREN))
       
   852             ++_dot;
       
   853 
       
   854         else {
       
   855             int count = 0;
       
   856 
       
   857             for (; _dot->isNot(T_EOF_SYMBOL); ++_dot) {
       
   858                 if (_dot->is(T_LPAREN))
       
   859                     ++count;
       
   860 
       
   861                 else if (_dot->is(T_RPAREN)) {
       
   862                     if (! --count) {
       
   863                         ++_dot;
       
   864                         break;
       
   865                     }
       
   866                 }
       
   867             }
       
   868         }
       
   869     }
       
   870 
       
   871     const unsigned end = _dot->begin();
       
   872 
       
   873     return MacroArgumentReference(position, end - position);
       
   874 }
       
   875 
       
   876 Macro *Preprocessor::processObjectLikeMacro(TokenIterator identifierToken,
       
   877                                             const QByteArray &spell,
       
   878                                             Macro *m)
       
   879 {
       
   880     QByteArray tmp;
       
   881     expandObjectLikeMacro(identifierToken, spell, m, &tmp);
       
   882 
       
   883     if (_dot->is(T_LPAREN)) {
       
   884         // check if the expension generated a function-like macro.
       
   885 
       
   886         m = 0; // reset the active the macro
       
   887 
       
   888         pushState(createStateFromSource(tmp));
       
   889 
       
   890         if (_dot->is(T_IDENTIFIER)) {
       
   891             const QByteArray id = tokenSpell(*_dot);
       
   892 
       
   893             if (Macro *macro = env->resolve(id)) {
       
   894                 if (macro->isFunctionLike())
       
   895                     m = macro;
       
   896             }
       
   897         }
       
   898 
       
   899         popState();
       
   900 
       
   901         if (m != 0)
       
   902             return m;
       
   903     }
       
   904 
       
   905     const bool was = markGeneratedTokens(true, identifierToken);
       
   906     out(tmp);
       
   907     (void) markGeneratedTokens(was);
       
   908     return 0;
       
   909 }
       
   910 
       
   911 void Preprocessor::expandBuiltinMacro(TokenIterator identifierToken,
       
   912                                       const QByteArray &spell)
       
   913 {
       
   914     const bool was = markGeneratedTokens(true, identifierToken);
       
   915     expand(spell, _result);
       
   916     (void) markGeneratedTokens(was);
       
   917 }
       
   918 
       
   919 void Preprocessor::expandObjectLikeMacro(TokenIterator identifierToken,
       
   920                                          const QByteArray &spell,
       
   921                                          Macro *m,
       
   922                                          QByteArray *result)
       
   923 {
       
   924     if (client)
       
   925         client->startExpandingMacro(identifierToken->offset,
       
   926                                     *m, spell, false);
       
   927 
       
   928     m->setHidden(true);
       
   929     expand(m->definition(), result);
       
   930     m->setHidden(false);
       
   931 
       
   932     if (client)
       
   933         client->stopExpandingMacro(_dot->offset, *m);
       
   934 }
       
   935 
       
   936 void Preprocessor::expandFunctionLikeMacro(TokenIterator identifierToken,
       
   937                                            Macro *m,
       
   938                                            const QVector<MacroArgumentReference> &actuals)
       
   939 {
       
   940     const char *beginOfText = startOfToken(*identifierToken);
       
   941     const char *endOfText = endOfToken(*_dot);
       
   942     ++_dot; // skip T_RPAREN
       
   943 
       
   944     if (client) {
       
   945         const QByteArray text =
       
   946                 QByteArray::fromRawData(beginOfText,
       
   947                                         endOfText - beginOfText);
       
   948 
       
   949         client->startExpandingMacro(identifierToken->offset,
       
   950                                     *m, text, false, actuals);
       
   951     }
       
   952 
       
   953     const bool was = markGeneratedTokens(true, identifierToken);
       
   954     expand(beginOfText, endOfText, _result);
       
   955     (void) markGeneratedTokens(was);
       
   956 
       
   957     if (client)
       
   958         client->stopExpandingMacro(_dot->offset, *m);
       
   959 }
       
   960 
       
   961 const char *Preprocessor::startOfToken(const Token &token) const
       
   962 { return _source.constBegin() + token.begin(); }
       
   963 
       
   964 const char *Preprocessor::endOfToken(const Token &token) const
       
   965 { return _source.constBegin() + token.end(); }
       
   966 
       
   967 QByteArray Preprocessor::tokenSpell(const Token &token) const
       
   968 {
       
   969     const QByteArray text = QByteArray::fromRawData(_source.constBegin() + token.offset,
       
   970                                                      token.f.length);
       
   971     return text;
       
   972 }
       
   973 
       
   974 QByteArray Preprocessor::tokenText(const Token &token) const
       
   975 {
       
   976     const QByteArray text(_source.constBegin() + token.offset,
       
   977                           token.f.length);
       
   978     return text;
       
   979 }
       
   980 
       
   981 void Preprocessor::processDirective(TokenIterator firstToken, TokenIterator lastToken)
       
   982 {
       
   983     RangeLexer tk(firstToken, lastToken);
       
   984     ++tk; // skip T_POUND
       
   985 
       
   986     if (tk->is(T_IDENTIFIER)) {
       
   987         const QByteArray directive = tokenSpell(*tk);
       
   988         switch (PP_DIRECTIVE_TYPE d = classifyDirective(directive)) {
       
   989         case PP_DEFINE:
       
   990             if (! skipping())
       
   991                 processDefine(firstToken, lastToken);
       
   992             break;
       
   993 
       
   994         case PP_INCLUDE:
       
   995         case PP_INCLUDE_NEXT:
       
   996         case PP_IMPORT:
       
   997             if (! skipping())
       
   998                 processInclude(d == PP_INCLUDE_NEXT, firstToken, lastToken);
       
   999             break;
       
  1000 
       
  1001         case PP_UNDEF:
       
  1002             if (! skipping())
       
  1003                 processUndef(firstToken, lastToken);
       
  1004             break;
       
  1005 
       
  1006         case PP_ELIF:
       
  1007             processElif(firstToken, lastToken);
       
  1008             break;
       
  1009 
       
  1010         case PP_ELSE:
       
  1011             processElse(firstToken, lastToken);
       
  1012             break;
       
  1013 
       
  1014         case PP_ENDIF:
       
  1015             processEndif(firstToken, lastToken);
       
  1016             break;
       
  1017 
       
  1018         case PP_IF:
       
  1019             processIf(firstToken, lastToken);
       
  1020             break;
       
  1021 
       
  1022         case PP_IFDEF:
       
  1023         case PP_IFNDEF:
       
  1024             processIfdef(d == PP_IFNDEF, firstToken, lastToken);
       
  1025             break;
       
  1026 
       
  1027         default:
       
  1028             break;
       
  1029         } // switch
       
  1030     }
       
  1031 }
       
  1032 
       
  1033 QVector<Token> Preprocessor::tokenize(const QByteArray &text) const
       
  1034 {
       
  1035     QVector<Token> tokens;
       
  1036     Lexer lex(text.constBegin(), text.constEnd());
       
  1037     lex.setScanKeywords(false);
       
  1038     Token tk;
       
  1039     do {
       
  1040         lex(&tk);
       
  1041         tokens.append(tk);
       
  1042     } while (tk.isNot(T_EOF_SYMBOL));
       
  1043     return tokens;
       
  1044 }
       
  1045 
       
  1046 void Preprocessor::processInclude(bool, TokenIterator firstToken,
       
  1047                                   TokenIterator lastToken, bool acceptMacros)
       
  1048 {
       
  1049     if (! client)
       
  1050         return; // nothing to do.
       
  1051 
       
  1052     RangeLexer tk(firstToken, lastToken);
       
  1053     ++tk; // skip T_POUND
       
  1054     ++tk; // skip `include|nclude_next'
       
  1055 
       
  1056     if (acceptMacros && tk->is(T_IDENTIFIER)) {
       
  1057         // ### TODO: implement me
       
  1058 #if 0
       
  1059         QByteArray name;
       
  1060         name.reserve(256);
       
  1061         MacroExpander expandInclude(env);
       
  1062         expandInclude(startOfToken(tokens.at(2)),
       
  1063                       startOfToken(tokens.last()),
       
  1064                       &name);
       
  1065         const QByteArray previousSource = switchSource(name);
       
  1066         //processInclude(skipCurentPath, tokenize(name), /*accept macros=*/ false);
       
  1067         (void) switchSource(previousSource);
       
  1068 #endif
       
  1069 
       
  1070     } else if (tk->is(T_LESS)) {
       
  1071 
       
  1072         TokenIterator start = tk.dot();
       
  1073 
       
  1074         for (; tk->isNot(T_EOF_SYMBOL); ++tk) {
       
  1075             if (tk->is(T_GREATER))
       
  1076                 break;
       
  1077         }
       
  1078 
       
  1079         const char *beginOfPath = endOfToken(*start);
       
  1080         const char *endOfPath = startOfToken(*tk);
       
  1081 
       
  1082         QString fn = string(beginOfPath, endOfPath - beginOfPath);
       
  1083         client->sourceNeeded(fn, Client::IncludeGlobal, firstToken->lineno);
       
  1084 
       
  1085     } else if (tk->is(T_ANGLE_STRING_LITERAL) || tk->is(T_STRING_LITERAL)) {
       
  1086 
       
  1087         const QByteArray spell = tokenSpell(*tk);
       
  1088         const char *beginOfPath = spell.constBegin();
       
  1089         const char *endOfPath = spell.constEnd();
       
  1090         const char quote = *beginOfPath;
       
  1091 
       
  1092         if (beginOfPath + 1 != endOfPath && ((quote == '"' && endOfPath[-1] == '"') ||
       
  1093                                               (quote == '<' && endOfPath[-1] == '>'))) {
       
  1094 
       
  1095             QString fn = string(beginOfPath + 1, spell.length() - 2);
       
  1096             client->sourceNeeded(fn, Client::IncludeLocal, firstToken->lineno);
       
  1097         }
       
  1098     }
       
  1099 }
       
  1100 
       
  1101 void Preprocessor::processDefine(TokenIterator firstToken, TokenIterator lastToken)
       
  1102 {
       
  1103     RangeLexer tk(firstToken, lastToken);
       
  1104 
       
  1105     if (tk.size() < 3)
       
  1106         return; // nothing to do
       
  1107 
       
  1108     ++tk; // skip T_POUND
       
  1109     ++tk; // skip T_DEFINE
       
  1110 
       
  1111     if (tk->isNot(T_IDENTIFIER)) {
       
  1112         // ### warning expected an `identifier'
       
  1113         return;
       
  1114     }
       
  1115 
       
  1116     Macro macro;
       
  1117     macro.setFileName(env->currentFile);
       
  1118     macro.setLine(env->currentLine);
       
  1119     macro.setName(tokenText(*tk));
       
  1120     macro.setOffset(firstToken->offset);
       
  1121     macro.setLength(endOfToken(lastToken[- 1]) - startOfToken(*firstToken));
       
  1122     ++tk; // skip T_IDENTIFIER
       
  1123 
       
  1124     if (tk->is(T_LPAREN) && ! tk->f.whitespace) {
       
  1125         // a function-like macro definition
       
  1126         macro.setFunctionLike(true);
       
  1127 
       
  1128         ++tk; // skip T_LPAREN
       
  1129         if (tk->is(T_IDENTIFIER)) {
       
  1130             macro.addFormal(tokenText(*tk));
       
  1131             ++tk; // skip T_IDENTIFIER
       
  1132             while (tk->is(T_COMMA)) {
       
  1133                 ++tk;// skip T_COMMA
       
  1134                 if (tk->isNot(T_IDENTIFIER))
       
  1135                     break;
       
  1136                 macro.addFormal(tokenText(*tk));
       
  1137                 ++tk; // skip T_IDENTIFIER
       
  1138             }
       
  1139         }
       
  1140 
       
  1141         if (tk->is(T_DOT_DOT_DOT)) {
       
  1142             macro.setVariadic(true);
       
  1143             ++tk; // skip T_DOT_DOT_DOT
       
  1144         }
       
  1145 
       
  1146         if (tk->isNot(T_RPAREN)) {
       
  1147             // ### warning expected `)'
       
  1148             return;
       
  1149         }
       
  1150 
       
  1151         ++tk; // skip T_RPAREN
       
  1152     }
       
  1153 
       
  1154     if (isQtReservedWord(macro.name())) {
       
  1155         QByteArray macroId = macro.name();
       
  1156 
       
  1157         if (macro.isFunctionLike()) {
       
  1158             macroId += '(';
       
  1159             bool fst = true;
       
  1160             foreach (const QByteArray formal, macro.formals()) {
       
  1161                 if (! fst)
       
  1162                     macroId += ", ";
       
  1163                 fst = false;
       
  1164                 macroId += formal;
       
  1165             }
       
  1166             macroId += ')';
       
  1167         }
       
  1168 
       
  1169         macro.setDefinition(macroId);
       
  1170     } else {
       
  1171         // ### make me fast!
       
  1172         const char *startOfDefinition = startOfToken(*tk);
       
  1173         const char *endOfDefinition = endOfToken(lastToken[- 1]);
       
  1174         QByteArray definition(startOfDefinition,
       
  1175                               endOfDefinition - startOfDefinition);
       
  1176         definition.replace("\\\n", " ");
       
  1177         definition.replace('\n', ' ');
       
  1178         macro.setDefinition(definition.trimmed());
       
  1179     }
       
  1180 
       
  1181     env->bind(macro);
       
  1182 
       
  1183     if (client)
       
  1184         client->macroAdded(macro);
       
  1185 }
       
  1186 
       
  1187 void Preprocessor::processIf(TokenIterator firstToken, TokenIterator lastToken)
       
  1188 {
       
  1189     RangeLexer tk(firstToken, lastToken);
       
  1190 
       
  1191     ++tk; // skip T_POUND
       
  1192     ++tk; // skipt `if'
       
  1193 
       
  1194     if (testIfLevel()) {
       
  1195         const char *first = startOfToken(*tk);
       
  1196         const char *last = startOfToken(*lastToken);
       
  1197 
       
  1198         MacroExpander expandCondition (env, 0, client, tk.dot()->offset);
       
  1199         QByteArray condition;
       
  1200         condition.reserve(256);
       
  1201         expandCondition(first, last, &condition);
       
  1202 
       
  1203         QVector<Token> tokens = tokenize(condition);
       
  1204 
       
  1205         const Value result = evalExpression(tokens.constBegin(),
       
  1206                                             tokens.constEnd() - 1,
       
  1207                                             condition);
       
  1208 
       
  1209         _trueTest[iflevel] = ! result.is_zero ();
       
  1210         _skipping[iflevel]  =   result.is_zero ();
       
  1211     }
       
  1212 }
       
  1213 
       
  1214 void Preprocessor::processElse(TokenIterator firstToken, TokenIterator lastToken)
       
  1215 {
       
  1216     RangeLexer tk(firstToken, lastToken);
       
  1217 
       
  1218     if (iflevel == 0 && !skipping ()) {
       
  1219         // std::cerr << "*** WARNING #else without #if" << std::endl;
       
  1220     } else if (iflevel > 0 && _skipping[iflevel - 1]) {
       
  1221         _skipping[iflevel] = true;
       
  1222     } else {
       
  1223         _skipping[iflevel] = _trueTest[iflevel];
       
  1224     }
       
  1225 }
       
  1226 
       
  1227 void Preprocessor::processElif(TokenIterator firstToken, TokenIterator lastToken)
       
  1228 {
       
  1229     RangeLexer tk(firstToken, lastToken);
       
  1230     ++tk; // skip T_POUND
       
  1231     ++tk; // skipt `elif'
       
  1232 
       
  1233     if (! (iflevel > 0)) {
       
  1234         // std::cerr << "*** WARNING: " << __FILE__ << __LINE__ << std::endl;
       
  1235     } else if (iflevel == 0 && !skipping()) {
       
  1236         // std::cerr << "*** WARNING #else without #if" << std::endl;
       
  1237     } else if (!_trueTest[iflevel] && !_skipping[iflevel - 1]) {
       
  1238 
       
  1239         const char *first = startOfToken(*tk);
       
  1240         const char *last = startOfToken(*lastToken);
       
  1241 
       
  1242         MacroExpander expandCondition (env, 0, client, tk.dot()->offset);
       
  1243         QByteArray condition;
       
  1244         condition.reserve(256);
       
  1245         expandCondition(first, last, &condition);
       
  1246 
       
  1247         QVector<Token> tokens = tokenize(condition);
       
  1248 
       
  1249         const Value result = evalExpression(tokens.constBegin(),
       
  1250                                             tokens.constEnd() - 1,
       
  1251                                             condition);
       
  1252 
       
  1253         _trueTest[iflevel] = ! result.is_zero ();
       
  1254         _skipping[iflevel]  =   result.is_zero ();
       
  1255     } else {
       
  1256         _skipping[iflevel] = true;
       
  1257     }
       
  1258 }
       
  1259 
       
  1260 void Preprocessor::processEndif(TokenIterator, TokenIterator)
       
  1261 {
       
  1262     if (iflevel == 0 && !skipping()) {
       
  1263         // std::cerr << "*** WARNING #endif without #if" << std::endl;
       
  1264     } else {
       
  1265         _skipping[iflevel] = false;
       
  1266         _trueTest[iflevel] = false;
       
  1267 
       
  1268         --iflevel;
       
  1269     }
       
  1270 }
       
  1271 
       
  1272 void Preprocessor::processIfdef(bool checkUndefined,
       
  1273                                 TokenIterator firstToken,
       
  1274                                 TokenIterator lastToken)
       
  1275 {
       
  1276     RangeLexer tk(firstToken, lastToken);
       
  1277 
       
  1278     ++tk; // skip T_POUND
       
  1279     ++tk; // skip `ifdef'
       
  1280     if (testIfLevel()) {
       
  1281         if (tk->is(T_IDENTIFIER)) {
       
  1282             const QByteArray macroName = tokenSpell(*tk);
       
  1283             bool value = isMacroDefined(macroName, tk->offset, env, client) || env->isBuiltinMacro(macroName);
       
  1284 
       
  1285             if (checkUndefined)
       
  1286                 value = ! value;
       
  1287 
       
  1288             _trueTest[iflevel] =   value;
       
  1289             _skipping [iflevel] = ! value;
       
  1290         }
       
  1291     }
       
  1292 }
       
  1293 
       
  1294 void Preprocessor::processUndef(TokenIterator firstToken, TokenIterator lastToken)
       
  1295 {
       
  1296     RangeLexer tk(firstToken, lastToken);
       
  1297 
       
  1298     ++tk; // skip T_POUND
       
  1299     ++tk; // skip `undef'
       
  1300 
       
  1301     if (tk->is(T_IDENTIFIER)) {
       
  1302         const QByteArray macroName = tokenText(*tk);
       
  1303         const Macro *macro = env->remove(macroName);
       
  1304 
       
  1305         if (client && macro)
       
  1306             client->macroAdded(*macro);
       
  1307     }
       
  1308 }
       
  1309 
       
  1310 void Preprocessor::resetIfLevel ()
       
  1311 {
       
  1312     iflevel = 0;
       
  1313     _skipping[iflevel] = false;
       
  1314     _trueTest[iflevel] = false;
       
  1315 }
       
  1316 
       
  1317 Preprocessor::PP_DIRECTIVE_TYPE Preprocessor::classifyDirective(const QByteArray &directive) const
       
  1318 {
       
  1319     switch (directive.size())
       
  1320     {
       
  1321     case 2:
       
  1322         if (directive[0] == 'i' && directive[1] == 'f')
       
  1323             return PP_IF;
       
  1324         break;
       
  1325 
       
  1326     case 4:
       
  1327         if (directive[0] == 'e' && directive == "elif")
       
  1328             return PP_ELIF;
       
  1329         else if (directive[0] == 'e' && directive == "else")
       
  1330             return PP_ELSE;
       
  1331         break;
       
  1332 
       
  1333     case 5:
       
  1334         if (directive[0] == 'i' && directive == "ifdef")
       
  1335             return PP_IFDEF;
       
  1336         else if (directive[0] == 'u' && directive == "undef")
       
  1337             return PP_UNDEF;
       
  1338         else if (directive[0] == 'e' && directive == "endif")
       
  1339             return PP_ENDIF;
       
  1340         break;
       
  1341 
       
  1342     case 6:
       
  1343         if (directive[0] == 'i' && directive == "ifndef")
       
  1344             return PP_IFNDEF;
       
  1345         else if (directive[0] == 'i' && directive == "import")
       
  1346             return PP_IMPORT;
       
  1347         else if (directive[0] == 'd' && directive == "define")
       
  1348             return PP_DEFINE;
       
  1349         break;
       
  1350 
       
  1351     case 7:
       
  1352         if (directive[0] == 'i' && directive == "include")
       
  1353             return PP_INCLUDE;
       
  1354         break;
       
  1355 
       
  1356     case 12:
       
  1357         if (directive[0] == 'i' && directive == "include_next")
       
  1358             return PP_INCLUDE_NEXT;
       
  1359         break;
       
  1360 
       
  1361     default:
       
  1362         break;
       
  1363     }
       
  1364 
       
  1365     return PP_UNKNOWN_DIRECTIVE;
       
  1366 }
       
  1367 
       
  1368 bool Preprocessor::testIfLevel()
       
  1369 {
       
  1370     const bool result = !_skipping[iflevel++];
       
  1371     _skipping[iflevel] = _skipping[iflevel - 1];
       
  1372     _trueTest[iflevel] = false;
       
  1373     return result;
       
  1374 }
       
  1375 
       
  1376 int Preprocessor::skipping() const
       
  1377 { return _skipping[iflevel]; }
       
  1378 
       
  1379 Value Preprocessor::evalExpression(TokenIterator firstToken, TokenIterator lastToken,
       
  1380                                    const QByteArray &source) const
       
  1381 {
       
  1382     ExpressionEvaluator eval(client, env);
       
  1383     const Value result = eval(firstToken, lastToken, source);
       
  1384     return result;
       
  1385 }
       
  1386 
       
  1387 bool Preprocessor::isQtReservedWord(const QByteArray &macroId) const
       
  1388 {
       
  1389     const int size = macroId.size();
       
  1390     if      (size == 9 && macroId.at(0) == 'Q' && macroId == "Q_SIGNALS")
       
  1391         return true;
       
  1392     else if (size == 9 && macroId.at(0) == 'Q' && macroId == "Q_FOREACH")
       
  1393         return true;
       
  1394     else if (size == 7 && macroId.at(0) == 'Q' && macroId == "Q_SLOTS")
       
  1395         return true;
       
  1396     else if (size == 8 && macroId.at(0) == 'Q' && macroId == "Q_SIGNAL")
       
  1397         return true;
       
  1398     else if (size == 6 && macroId.at(0) == 'Q' && macroId == "Q_SLOT")
       
  1399         return true;
       
  1400     else if (size == 3 && macroId.at(0) == 'Q' && macroId == "Q_D")
       
  1401         return true;
       
  1402     else if (size == 3 && macroId.at(0) == 'Q' && macroId == "Q_Q")
       
  1403         return true;
       
  1404     else if (size == 6 && macroId.at(0) == 'S' && macroId == "SIGNAL")
       
  1405         return true;
       
  1406     else if (size == 4 && macroId.at(0) == 'S' && macroId == "SLOT")
       
  1407         return true;
       
  1408     else if (size == 7 && macroId.at(0) == 's' && macroId == "signals")
       
  1409         return true;
       
  1410     else if (size == 7 && macroId.at(0) == 'f' && macroId == "foreach")
       
  1411         return true;
       
  1412     else if (size == 5 && macroId.at(0) == 's' && macroId == "slots")
       
  1413         return true;
       
  1414     return false;
       
  1415 }
       
  1416 
       
  1417 QString Preprocessor::string(const char *first, int length) const
       
  1418 {
       
  1419     if (_originalSource.isEmpty())
       
  1420         return QString::fromUtf8(first, length);
       
  1421 
       
  1422     const int position = first - _source.constData();
       
  1423     return _originalSource.mid(position, length);
       
  1424 }