diff options
author | Erik Verbruggen <erik.verbruggen@nokia.com> | 2012-03-26 15:18:01 +0200 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@nokia.com> | 2012-03-29 14:28:17 +0200 |
commit | 60db5736604583fe99dde3c25412d97f9b77489d (patch) | |
tree | 2f5bf1342086232de0570500fd440a98eb12cb96 /src/libs/cplusplus/pp-macro-expander.cpp | |
parent | 159058d9eb7ab233f94cc6a0a5b0e7e8f691a041 (diff) | |
download | qt-creator-60db5736604583fe99dde3c25412d97f9b77489d.tar.gz |
[C++] Rewrite of the preprocessor.
This rewrite fixes a couple of issues with the pre-processor. It now
supports:
- macros in macro bodies
- stringification of parameters [cpp.stringize]
- the concatenation operator [cpp.concat]
- #include MACRO_HERE
- defined() inside macro bodies used in pp-conditions.
Change-Id: Ifdb78041fb6afadf44f939a4bd66ce2832b8601f
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
Diffstat (limited to 'src/libs/cplusplus/pp-macro-expander.cpp')
-rw-r--r-- | src/libs/cplusplus/pp-macro-expander.cpp | 449 |
1 files changed, 0 insertions, 449 deletions
diff --git a/src/libs/cplusplus/pp-macro-expander.cpp b/src/libs/cplusplus/pp-macro-expander.cpp deleted file mode 100644 index cde82884c0..0000000000 --- a/src/libs/cplusplus/pp-macro-expander.cpp +++ /dev/null @@ -1,449 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "pp-macro-expander.h" - -#include "pp.h" -#include "pp-cctype.h" -#include <QDateTime> - -namespace CPlusPlus { - - - -struct pp_frame -{ - Macro *expanding_macro; - const QVector<QByteArray> actuals; - - pp_frame(Macro *expanding_macro, const QVector<QByteArray> &actuals) - : expanding_macro (expanding_macro), - actuals (actuals) - { } -}; - - -} // namespace CPlusPlus - -using namespace CPlusPlus; - -inline static bool comment_p (const char *__first, const char *__last) -{ - if (__first == __last) - return false; - - if (*__first != '/') - return false; - - if (++__first == __last) - return false; - - return (*__first == '/' || *__first == '*'); -} - -MacroExpander::MacroExpander(Environment *env, pp_frame *frame, Client *client, unsigned start_offset) - : env(env), - frame(frame), - client(client), - start_offset(start_offset), - lines(0) -{ } - -const QByteArray *MacroExpander::resolve_formal(const QByteArray &__name) -{ - if (! (frame && frame->expanding_macro)) - return 0; - - const QVector<QByteArray> formals = frame->expanding_macro->formals(); - for (int index = 0; index < formals.size(); ++index) { - const QByteArray formal = formals.at(index); - - if (formal == __name && index < frame->actuals.size()) - return &frame->actuals.at(index); - } - - return 0; -} - -const char *MacroExpander::operator()(const char *first, const char *last, - QByteArray *result) -{ - return expand(first, last, result); -} - -const char *MacroExpander::expand(const char *__first, const char *__last, - QByteArray *__result) -{ - __first = skip_blanks (__first, __last); - lines = skip_blanks.lines; - - while (__first != __last) - { - if (*__first == '\n') - { - __result->append("\n# "); - __result->append(QByteArray::number(env->currentLine)); - __result->append(' '); - __result->append('"'); - __result->append(env->currentFile.toUtf8()); - __result->append('"'); - __result->append('\n'); - ++lines; - - __first = skip_blanks (++__first, __last); - lines += skip_blanks.lines; - - if (__first != __last && *__first == '#') - break; - } - else if (*__first == '#') - { - __first = skip_blanks (++__first, __last); - lines += skip_blanks.lines; - - const char *end_id = skip_identifier (__first, __last); - const QByteArray fast_name(__first, end_id - __first); - __first = end_id; - - if (const QByteArray *actual = resolve_formal (fast_name)) - { - __result->append('\"'); - - const char *actual_begin = actual->constData (); - const char *actual_end = actual_begin + actual->size (); - - for (const char *it = skip_whitespaces (actual_begin, actual_end); - it != actual_end; ++it) - { - if (*it == '"' || *it == '\\') - { - __result->append('\\'); - __result->append(*it); - } - else if (*it == '\n') - { - __result->append('"'); - __result->append('\n'); - __result->append('"'); - } - else - __result->append(*it); - } - - __result->append('\"'); - } - else { - // ### warning message? - } - } - else if (*__first == '\"') - { - const char *next_pos = skip_string_literal (__first, __last); - lines += skip_string_literal.lines; - __result->append(__first, next_pos - __first); - __first = next_pos; - } - else if (*__first == '\'') - { - const char *next_pos = skip_char_literal (__first, __last); - lines += skip_char_literal.lines; - __result->append(__first, next_pos - __first); - __first = next_pos; - } - else if (*__first == '\\') - { - ++__first; - if (__first != __last && *__first == '\n') - { - ++lines; - ++__first; - } else { - __result->append('\\'); - } - } - else if (comment_p (__first, __last)) - { - __first = skip_comment_or_divop (__first, __last); - int n = skip_comment_or_divop.lines; - lines += n; - - while (n-- > 0) - __result->append('\n'); - } - else if (pp_isspace (*__first)) - { - for (; __first != __last; ++__first) - { - if (*__first == '\n' || !pp_isspace (*__first)) - break; - } - - __result->append(' '); - } - else if (pp_isdigit (*__first)) - { - const char *next_pos = skip_number (__first, __last); - lines += skip_number.lines; - __result->append(__first, next_pos - __first); - __first = next_pos; - } - else if (pp_isalpha (*__first) || *__first == '_') - { - const char *name_begin = __first; - const char *name_end = skip_identifier (__first, __last); - __first = name_end; // advance - - // search for the paste token - const char *next = skip_blanks (__first, __last); - bool paste = false; - - bool need_comma = false; - if (next != __last && *next == ',') { - const char *x = skip_blanks(__first + 1, __last); - if (x != __last && *x == '#' && (x + 1) != __last && x[1] == '#') { - need_comma = true; - paste = true; - __first = skip_blanks(x + 2, __last); - } - } - - if (next != __last && *next == '#') - { - paste = true; - ++next; - if (next != __last && *next == '#') - __first = skip_blanks(++next, __last); - } - - const QByteArray fast_name(name_begin, name_end - name_begin); - const QByteArray *actual = resolve_formal (fast_name); - if (actual) - { - const char *begin = actual->constData (); - const char *end = begin + actual->size (); - if (paste) { - for (--end; end != begin - 1; --end) { - if (! pp_isspace(*end)) - break; - } - ++end; - } - __result->append(begin, end - begin); - if (need_comma) - __result->append(','); - continue; - } - - Macro *macro = env->resolve (fast_name); - if (! macro || macro->isHidden() || env->hideNext) - { - if (fast_name.size () == 7 && fast_name [0] == 'd' && fast_name == "defined") - env->hideNext = true; - else - env->hideNext = false; - - if (fast_name.size () == 8 && fast_name [0] == '_' && fast_name [1] == '_') - { - if (fast_name == "__LINE__") - { - __result->append(QByteArray::number(env->currentLine + lines)); - continue; - } - - else if (fast_name == "__FILE__") - { - __result->append('"'); - __result->append(env->currentFile.toUtf8()); - __result->append('"'); - continue; - } - - else if (fast_name == "__DATE__") - { - __result->append('"'); - __result->append(QDate::currentDate().toString().toUtf8()); - __result->append('"'); - continue; - } - - else if (fast_name == "__TIME__") - { - __result->append('"'); - __result->append(QTime::currentTime().toString().toUtf8()); - __result->append('"'); - continue; - } - - } - - __result->append(name_begin, name_end - name_begin); - continue; - } - - if (! macro->isFunctionLike()) - { - Macro *m = 0; - - if (! macro->definition().isEmpty()) - { - macro->setHidden(true); - - QByteArray __tmp; - __tmp.reserve (256); - - MacroExpander expand_macro (env); - expand_macro(macro->definition(), &__tmp); - - if (! __tmp.isEmpty ()) - { - const char *__tmp_begin = __tmp.constBegin(); - const char *__tmp_end = __tmp.constEnd(); - const char *__begin_id = skip_whitespaces (__tmp_begin, __tmp_end); - const char *__end_id = skip_identifier (__begin_id, __tmp_end); - - if (__end_id == __tmp_end) - { - const QByteArray __id (__begin_id, __end_id - __begin_id); - m = env->resolve (__id); - } - - if (! m) - *__result += __tmp; - } - - macro->setHidden(false); - } - - if (! m) - continue; - - macro = m; - } - - // function like macro - const char *arg_it = skip_whitespaces (__first, __last); - - if (arg_it == __last || *arg_it != '(') - { - __result->append(name_begin, name_end - name_begin); - lines += skip_whitespaces.lines; - __first = arg_it; - continue; - } - - QVector<QByteArray> actuals; - actuals.reserve(macro->formals().size()); - ++arg_it; // skip '(' - - MacroExpander expand_actual (env, frame); - - const char *arg_end = skip_argument(arg_it, __last); - if (arg_it != arg_end || (arg_end != __last && *arg_end == ',')) - { - const QByteArray actual(arg_it, arg_end - arg_it); - QByteArray expanded; - expand_actual(actual.constBegin (), actual.constEnd (), &expanded); - pushActuals(actuals, macro, expanded); - arg_it = arg_end; - } - - while (arg_it != __last && *arg_end == ',') - { - ++arg_it; // skip ',' - - arg_end = skip_argument(arg_it, __last); - const QByteArray actual(arg_it, arg_end - arg_it); - QByteArray expanded; - expand_actual(actual.constBegin (), actual.constEnd (), &expanded); - pushActuals(actuals, macro, expanded); - arg_it = arg_end; - } - - if (! (arg_it != __last && *arg_it == ')')) - return __last; - - ++arg_it; // skip ')' - __first = arg_it; - - pp_frame frame (macro, actuals); - MacroExpander expand_macro (env, &frame); - macro->setHidden(true); - expand_macro (macro->definition(), __result); - macro->setHidden(false); - } - else - __result->append(*__first++); - } - - return __first; -} - -const char *MacroExpander::skip_argument_variadics (QVector<QByteArray> const &__actuals, - Macro *__macro, - const char *__first, const char *__last) -{ - const char *arg_end = skip_argument (__first, __last); - - while (__macro->isVariadic() && __first != arg_end && arg_end != __last && *arg_end == ',' - && (__actuals.size () + 1) == __macro->formals().size ()) - { - arg_end = skip_argument (++arg_end, __last); - } - - return arg_end; -} - -void MacroExpander::pushActuals(QVector<QByteArray> & actuals, Macro *__macro, const QByteArray& expanded) -{ - if (__macro->isVariadic() && actuals.count() == __macro->formals().count()) { - //already enough params --> append to the last one - QByteArray& b = actuals.last(); - b.append(","); - b.append(expanded.trimmed()); - } - else { - const char * __first = expanded.constData(); - const char * __last = __first + expanded.length(); - const char * arg_it = __first; - - const char *arg_end = skip_argument_variadics(actuals, __macro, arg_it, __last); - actuals.push_back(QByteArray(arg_it, arg_end - arg_it).trimmed()); - arg_it = arg_end; - - while (arg_it != __last) { - ++arg_it; // skip ',' - const char *arg_end = skip_argument_variadics(actuals, __macro, arg_it, __last); - actuals.push_back(QByteArray(arg_it, arg_end - arg_it).trimmed()); - arg_it = arg_end; - } - } -} |