tools/icheck/parser/src/libs/cplusplus/pp-macro-expander.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 #include "pp-macro-expander.h"
       
    43 
       
    44 #include "pp.h"
       
    45 #include "pp-cctype.h"
       
    46 #include <QDateTime>
       
    47 
       
    48 namespace CPlusPlus {
       
    49 
       
    50 
       
    51 
       
    52 struct pp_frame
       
    53 {
       
    54     Macro *expanding_macro;
       
    55     const QVector<QByteArray> actuals;
       
    56 
       
    57     pp_frame(Macro *expanding_macro, const QVector<QByteArray> &actuals)
       
    58         : expanding_macro (expanding_macro),
       
    59           actuals (actuals)
       
    60     { }
       
    61 };
       
    62 
       
    63 
       
    64 } // end of namespace CPlusPlus
       
    65 
       
    66 using namespace CPlusPlus;
       
    67 
       
    68 inline static bool comment_p (const char *__first, const char *__last)
       
    69 {
       
    70     if (__first == __last)
       
    71         return false;
       
    72 
       
    73     if (*__first != '/')
       
    74         return false;
       
    75 
       
    76     if (++__first == __last)
       
    77         return false;
       
    78 
       
    79     return (*__first == '/' || *__first == '*');
       
    80 }
       
    81 
       
    82 MacroExpander::MacroExpander(Environment *env, pp_frame *frame, Client *client, unsigned start_offset)
       
    83     : env(env),
       
    84       frame(frame),
       
    85       client(client),
       
    86       start_offset(start_offset),
       
    87       lines(0)
       
    88 { }
       
    89 
       
    90 const QByteArray *MacroExpander::resolve_formal(const QByteArray &__name)
       
    91 {
       
    92     if (! (frame && frame->expanding_macro))
       
    93         return 0;
       
    94 
       
    95     const QVector<QByteArray> formals = frame->expanding_macro->formals();
       
    96     for (int index = 0; index < formals.size(); ++index) {
       
    97         const QByteArray formal = formals.at(index);
       
    98 
       
    99         if (formal == __name && index < frame->actuals.size())
       
   100             return &frame->actuals.at(index);
       
   101     }
       
   102 
       
   103     return 0;
       
   104 }
       
   105 
       
   106 const char *MacroExpander::operator()(const char *first, const char *last,
       
   107                                       QByteArray *result)
       
   108 {
       
   109     return expand(first, last, result);
       
   110 }
       
   111 
       
   112 const char *MacroExpander::expand(const char *__first, const char *__last,
       
   113                                   QByteArray *__result)
       
   114 {
       
   115     const char *start = __first;
       
   116     __first = skip_blanks (__first, __last);
       
   117     lines = skip_blanks.lines;
       
   118 
       
   119     while (__first != __last)
       
   120     {
       
   121         if (*__first == '\n')
       
   122         {
       
   123             __result->append("\n# ");
       
   124             __result->append(QByteArray::number(env->currentLine));
       
   125             __result->append(' ');
       
   126             __result->append('"');
       
   127             __result->append(env->currentFile.toUtf8());
       
   128             __result->append('"');
       
   129             __result->append('\n');
       
   130             ++lines;
       
   131 
       
   132             __first = skip_blanks (++__first, __last);
       
   133             lines += skip_blanks.lines;
       
   134 
       
   135             if (__first != __last && *__first == '#')
       
   136                 break;
       
   137         }
       
   138         else if (*__first == '#')
       
   139         {
       
   140             __first = skip_blanks (++__first, __last);
       
   141             lines += skip_blanks.lines;
       
   142 
       
   143             const char *end_id = skip_identifier (__first, __last);
       
   144             const QByteArray fast_name(__first, end_id - __first);
       
   145             __first = end_id;
       
   146 
       
   147             if (const QByteArray *actual = resolve_formal (fast_name))
       
   148             {
       
   149                 __result->append('\"');
       
   150 
       
   151                 const char *actual_begin = actual->constData ();
       
   152                 const char *actual_end = actual_begin + actual->size ();
       
   153 
       
   154                 for (const char *it = skip_whitespaces (actual_begin, actual_end);
       
   155                         it != actual_end; ++it)
       
   156                 {
       
   157                     if (*it == '"' || *it == '\\')
       
   158                     {
       
   159                         __result->append('\\');
       
   160                         __result->append(*it);
       
   161                     }
       
   162                     else if (*it == '\n')
       
   163                     {
       
   164                         __result->append('"');
       
   165                         __result->append('\n');
       
   166                         __result->append('"');
       
   167                     }
       
   168                     else
       
   169                         __result->append(*it);
       
   170                 }
       
   171 
       
   172                 __result->append('\"');
       
   173             }
       
   174             else
       
   175                 __result->append('#'); // ### warning message?
       
   176         }
       
   177         else if (*__first == '\"')
       
   178         {
       
   179             const char *next_pos = skip_string_literal (__first, __last);
       
   180             lines += skip_string_literal.lines;
       
   181             __result->append(__first, next_pos - __first);
       
   182             __first = next_pos;
       
   183         }
       
   184         else if (*__first == '\'')
       
   185         {
       
   186             const char *next_pos = skip_char_literal (__first, __last);
       
   187             lines += skip_char_literal.lines;
       
   188             __result->append(__first, next_pos - __first);
       
   189             __first = next_pos;
       
   190         }
       
   191         else if (comment_p (__first, __last))
       
   192         {
       
   193             __first = skip_comment_or_divop (__first, __last);
       
   194             int n = skip_comment_or_divop.lines;
       
   195             lines += n;
       
   196 
       
   197             while (n-- > 0)
       
   198                 __result->append('\n');
       
   199         }
       
   200         else if (pp_isspace (*__first))
       
   201         {
       
   202             for (; __first != __last; ++__first)
       
   203             {
       
   204                 if (*__first == '\n' || !pp_isspace (*__first))
       
   205                     break;
       
   206             }
       
   207 
       
   208             __result->append(' ');
       
   209         }
       
   210         else if (pp_isdigit (*__first))
       
   211         {
       
   212             const char *next_pos = skip_number (__first, __last);
       
   213             lines += skip_number.lines;
       
   214             __result->append(__first, next_pos - __first);
       
   215             __first = next_pos;
       
   216         }
       
   217         else if (pp_isalpha (*__first) || *__first == '_')
       
   218         {
       
   219             const char *name_begin = __first;
       
   220             const char *name_end = skip_identifier (__first, __last);
       
   221             __first = name_end; // advance
       
   222 
       
   223             // search for the paste token
       
   224             const char *next = skip_blanks (__first, __last);
       
   225             bool paste = false;
       
   226             if (next != __last && *next == '#')
       
   227             {
       
   228                 paste = true;
       
   229                 ++next;
       
   230                 if (next != __last && *next == '#')
       
   231                     __first = skip_blanks(++next, __last);
       
   232             }
       
   233 
       
   234             const QByteArray fast_name(name_begin, name_end - name_begin);
       
   235 
       
   236             if (const QByteArray *actual = resolve_formal (fast_name))
       
   237             {
       
   238                 const char *begin = actual->constData ();
       
   239                 const char *end = begin + actual->size ();
       
   240                 if (paste) {
       
   241                     for (--end; end != begin - 1; --end) {
       
   242                         if (! pp_isspace(*end))
       
   243                             break;
       
   244                     }
       
   245                     ++end;
       
   246                 }
       
   247                 __result->append(begin, end - begin);
       
   248                 continue;
       
   249             }
       
   250 
       
   251             Macro *macro = env->resolve (fast_name);
       
   252             if (! macro || macro->isHidden() || env->hideNext)
       
   253             {
       
   254                 if (fast_name.size () == 7 && fast_name [0] == 'd' && fast_name == "defined")
       
   255                     env->hideNext = true;
       
   256                 else
       
   257                     env->hideNext = false;
       
   258 
       
   259                 if (fast_name.size () == 8 && fast_name [0] == '_' && fast_name [1] == '_')
       
   260                 {
       
   261                     if (fast_name == "__LINE__")
       
   262                     {
       
   263                         __result->append(QByteArray::number(env->currentLine + lines));
       
   264                         continue;
       
   265                     }
       
   266 
       
   267                     else if (fast_name == "__FILE__")
       
   268                     {
       
   269                         __result->append('"');
       
   270                         __result->append(env->currentFile.toUtf8());
       
   271                         __result->append('"');
       
   272                         continue;
       
   273                     }
       
   274 
       
   275                     else if (fast_name == "__DATE__")
       
   276                     {
       
   277                         __result->append('"');
       
   278                         __result->append(QDate::currentDate().toString().toUtf8());
       
   279                         __result->append('"');
       
   280                         continue;
       
   281                     }
       
   282 
       
   283                     else if (fast_name == "__TIME__")
       
   284                     {
       
   285                         __result->append('"');
       
   286                         __result->append(QTime::currentTime().toString().toUtf8());
       
   287                         __result->append('"');
       
   288                         continue;
       
   289                     }
       
   290 
       
   291                 }
       
   292 
       
   293                 __result->append(name_begin, name_end - name_begin);
       
   294                 continue;
       
   295             }
       
   296 
       
   297             if (! macro->isFunctionLike())
       
   298             {
       
   299                 Macro *m = 0;
       
   300 
       
   301                 if (! macro->definition().isEmpty())
       
   302                 {
       
   303                     macro->setHidden(true);
       
   304 
       
   305                     QByteArray __tmp;
       
   306                     __tmp.reserve (256);
       
   307 
       
   308                     MacroExpander expand_macro (env);
       
   309                     expand_macro(macro->definition(), &__tmp);
       
   310 
       
   311                     if (! __tmp.isEmpty ())
       
   312                     {
       
   313                         const char *__tmp_begin = __tmp.constBegin();
       
   314                         const char *__tmp_end = __tmp.constEnd();
       
   315                         const char *__begin_id = skip_whitespaces (__tmp_begin, __tmp_end);
       
   316                         const char *__end_id = skip_identifier (__begin_id, __tmp_end);
       
   317 
       
   318                         if (__end_id == __tmp_end)
       
   319                         {
       
   320                             const QByteArray __id (__begin_id, __end_id - __begin_id);
       
   321                             m = env->resolve (__id);
       
   322                         }
       
   323 
       
   324                         if (! m)
       
   325                             *__result += __tmp;
       
   326                     }
       
   327 
       
   328                     macro->setHidden(false);
       
   329                 }
       
   330 
       
   331                 if (! m)
       
   332                     continue;
       
   333 
       
   334                 macro = m;
       
   335             }
       
   336 
       
   337             // function like macro
       
   338             const char *arg_it = skip_whitespaces (__first, __last);
       
   339 
       
   340             if (arg_it == __last || *arg_it != '(')
       
   341             {
       
   342                 __result->append(name_begin, name_end - name_begin);
       
   343                 lines += skip_whitespaces.lines;
       
   344                 __first = arg_it;
       
   345                 continue;
       
   346             }
       
   347 
       
   348             QVector<QByteArray> actuals;
       
   349             QVector<MacroArgumentReference> actuals_ref;
       
   350             actuals.reserve (5);
       
   351             ++arg_it; // skip '('
       
   352 
       
   353             MacroExpander expand_actual (env, frame);
       
   354 
       
   355             const char *arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
       
   356             if (arg_it != arg_end)
       
   357             {
       
   358                 actuals_ref.append(MacroArgumentReference(start_offset + (arg_it-start), arg_end - arg_it));
       
   359                 const QByteArray actual (arg_it, arg_end - arg_it);
       
   360                 QByteArray expanded;
       
   361                 expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
       
   362                 actuals.push_back (expanded);
       
   363                 arg_it = arg_end;
       
   364             }
       
   365 
       
   366             while (arg_it != __last && *arg_end == ',')
       
   367             {
       
   368                 ++arg_it; // skip ','
       
   369 
       
   370                 arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
       
   371                 actuals_ref.append(MacroArgumentReference(start_offset + (arg_it-start), arg_end - arg_it));
       
   372                 const QByteArray actual (arg_it, arg_end - arg_it);
       
   373                 QByteArray expanded;
       
   374                 expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
       
   375                 actuals.push_back (expanded);
       
   376                 arg_it = arg_end;
       
   377             }
       
   378 
       
   379             if (! (arg_it != __last && *arg_it == ')'))
       
   380                 return __last;
       
   381 
       
   382             ++arg_it; // skip ')'
       
   383             __first = arg_it;
       
   384 
       
   385             pp_frame frame (macro, actuals);
       
   386             MacroExpander expand_macro (env, &frame);
       
   387             macro->setHidden(true);
       
   388             expand_macro (macro->definition(), __result);
       
   389             macro->setHidden(false);
       
   390         }
       
   391         else
       
   392             __result->append(*__first++);
       
   393     }
       
   394 
       
   395     return __first;
       
   396 }
       
   397 
       
   398 const char *MacroExpander::skip_argument_variadics (QVector<QByteArray> const &__actuals,
       
   399                                                     Macro *__macro,
       
   400                                                     const char *__first, const char *__last)
       
   401 {
       
   402     const char *arg_end = skip_argument (__first, __last);
       
   403 
       
   404     while (__macro->isVariadic() && __first != arg_end && arg_end != __last && *arg_end == ','
       
   405            && (__actuals.size () + 1) == __macro->formals().size ())
       
   406     {
       
   407         arg_end = skip_argument (++arg_end, __last);
       
   408     }
       
   409 
       
   410     return arg_end;
       
   411 }