summaryrefslogtreecommitdiff
path: root/src/plugins/cpptools/rpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/cpptools/rpp')
-rw-r--r--src/plugins/cpptools/rpp/pp-cctype.h76
-rw-r--r--src/plugins/cpptools/rpp/pp-client.h69
-rw-r--r--src/plugins/cpptools/rpp/pp-engine.cpp1085
-rw-r--r--src/plugins/cpptools/rpp/pp-engine.h230
-rw-r--r--src/plugins/cpptools/rpp/pp-environment.cpp231
-rw-r--r--src/plugins/cpptools/rpp/pp-environment.h109
-rw-r--r--src/plugins/cpptools/rpp/pp-fwd.h62
-rw-r--r--src/plugins/cpptools/rpp/pp-internal.h102
-rw-r--r--src/plugins/cpptools/rpp/pp-macro-expander.cpp362
-rw-r--r--src/plugins/cpptools/rpp/pp-macro-expander.h103
-rw-r--r--src/plugins/cpptools/rpp/pp-macro.h95
-rw-r--r--src/plugins/cpptools/rpp/pp-scanner.h380
-rw-r--r--src/plugins/cpptools/rpp/pp-symbol.h52
-rw-r--r--src/plugins/cpptools/rpp/pp.h76
-rw-r--r--src/plugins/cpptools/rpp/rpp.pri20
15 files changed, 3052 insertions, 0 deletions
diff --git a/src/plugins/cpptools/rpp/pp-cctype.h b/src/plugins/cpptools/rpp/pp-cctype.h
new file mode 100644
index 0000000000..aff4fb2c51
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-cctype.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_CCTYPE_H
+#define PP_CCTYPE_H
+
+#include <cctype>
+
+namespace rpp {
+
+inline bool pp_isalpha (int __ch)
+{ return std::isalpha ((unsigned char) __ch) != 0; }
+
+inline bool pp_isalnum (int __ch)
+{ return std::isalnum ((unsigned char) __ch) != 0; }
+
+inline bool pp_isdigit (int __ch)
+{ return std::isdigit ((unsigned char) __ch) != 0; }
+
+inline bool pp_isspace (int __ch)
+{ return std::isspace ((unsigned char) __ch) != 0; }
+
+} // namespace rpp
+
+#endif // PP_CCTYPE_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/src/plugins/cpptools/rpp/pp-client.h b/src/plugins/cpptools/rpp/pp-client.h
new file mode 100644
index 0000000000..13d9eda713
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-client.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PP_CLIENT_H
+#define PP_CLIENT_H
+
+#include <QByteArray>
+#include <QString>
+#include <QFile>
+
+namespace rpp {
+
+class Client
+{
+ Client(const Client &other);
+ void operator=(const Client &other);
+
+public:
+ enum IncludeType {
+ IncludeLocal,
+ IncludeGlobal
+ };
+
+public:
+ Client()
+ { }
+
+ virtual ~Client()
+ { }
+
+ virtual void macroAdded(const QByteArray &macroId, const QByteArray &text) = 0;
+ virtual void sourceNeeded(QString &fileName, IncludeType mode) = 0; // ### FIX the signature.
+
+ virtual void startSkippingBlocks(unsigned offset) = 0;
+ virtual void stopSkippingBlocks(unsigned offset) = 0;
+};
+
+} // end of namespace rpp
+
+#endif // PP_CLIENT_H
diff --git a/src/plugins/cpptools/rpp/pp-engine.cpp b/src/plugins/cpptools/rpp/pp-engine.cpp
new file mode 100644
index 0000000000..97e168f0c2
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-engine.cpp
@@ -0,0 +1,1085 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pp.h"
+#include <Lexer.h>
+#include <Token.h>
+#include <QtDebug>
+
+using namespace rpp;
+using namespace CPlusPlus;
+
+namespace {
+
+class RangeLexer
+{
+ const Token *first;
+ const Token *last;
+ Token trivial;
+
+public:
+ inline RangeLexer(const Token *first, const Token *last)
+ : first(first), last(last)
+ {
+ // WARN: `last' must be a valid iterator.
+ trivial.offset = last->offset;
+ }
+
+ inline operator bool() const
+ { return first != last; }
+
+ inline bool isValid() const
+ { return first != last; }
+
+ inline int size() const
+ { return std::distance(first, last); }
+
+ inline const Token *dot() const
+ { return first; }
+
+ inline const Token &operator*() const
+ {
+ if (first != last)
+ return *first;
+
+ return trivial;
+ }
+
+ inline const Token *operator->() const
+ {
+ if (first != last)
+ return first;
+
+ return &trivial;
+ }
+
+ inline RangeLexer &operator++()
+ {
+ ++first;
+ return *this;
+ }
+};
+
+class ExpressionEvaluator
+{
+ ExpressionEvaluator(const ExpressionEvaluator &other);
+ void operator = (const ExpressionEvaluator &other);
+
+public:
+ ExpressionEvaluator(Environment *env)
+ : env(env), _lex(0)
+ { }
+
+ Value operator()(const Token *firstToken, const Token *lastToken,
+ const QByteArray &source)
+ {
+ this->source = source;
+ const Value previousValue = switchValue(Value());
+ RangeLexer tmp(firstToken, lastToken);
+ RangeLexer *previousLex = _lex;
+ _lex = &tmp;
+ process_expression();
+ _lex = previousLex;
+ return switchValue(previousValue);
+ }
+
+protected:
+ Value switchValue(const Value &value)
+ {
+ Value previousValue = _value;
+ _value = value;
+ return previousValue;
+ }
+
+ bool isTokenDefined() const
+ {
+ if ((*_lex)->isNot(T_IDENTIFIER))
+ return false;
+ const QByteArray spell = tokenSpell();
+ if (spell.size() != 7)
+ return false;
+ return spell == "defined";
+ }
+
+ QByteArray tokenSpell() const
+ {
+ const QByteArray text = QByteArray::fromRawData(source.constData() + (*_lex)->offset,
+ (*_lex)->length);
+ return text;
+ }
+
+ bool process_expression()
+ { return process_constant_expression(); }
+
+ bool process_primary()
+ {
+ if ((*_lex)->is(T_INT_LITERAL)) {
+ _value.set_long(tokenSpell().toLong());
+ ++(*_lex);
+ return true;
+ } else if (isTokenDefined()) {
+ ++(*_lex);
+ if ((*_lex)->is(T_IDENTIFIER)) {
+ _value.set_long(env->resolve(tokenSpell()) != 0);
+ ++(*_lex);
+ return true;
+ } else if ((*_lex)->is(T_LPAREN)) {
+ ++(*_lex);
+ if ((*_lex)->is(T_IDENTIFIER)) {
+ _value.set_long(env->resolve(tokenSpell()) != 0);
+ ++(*_lex);
+ if ((*_lex)->is(T_RPAREN)) {
+ ++(*_lex);
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+ } else if ((*_lex)->is(T_IDENTIFIER)) {
+ _value.set_long(0);
+ ++(*_lex);
+ return true;
+ } else if ((*_lex)->is(T_MINUS)) {
+ ++(*_lex);
+ process_primary();
+ _value.set_long(- _value.l);
+ return true;
+ } else if ((*_lex)->is(T_PLUS)) {
+ ++(*_lex);
+ process_primary();
+ return true;
+ } else if ((*_lex)->is(T_EXCLAIM)) {
+ ++(*_lex);
+ process_primary();
+ _value.set_long(_value.is_zero());
+ return true;
+ } else if ((*_lex)->is(T_LPAREN)) {
+ ++(*_lex);
+ process_expression();
+ if ((*_lex)->is(T_RPAREN))
+ ++(*_lex);
+ return true;
+ }
+
+ return false;
+ }
+
+ bool process_multiplicative()
+ {
+ process_primary();
+
+ while ((*_lex)->is(T_STAR) || (*_lex)->is(T_SLASH) || (*_lex)->is(T_PERCENT)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_primary();
+
+ if (op.is(T_STAR)) {
+ _value = left * _value;
+ } else if (op.is(T_SLASH)) {
+ if (_value.is_zero())
+ _value.set_long(0);
+ else
+ _value = left / _value;
+ } else if (op.is(T_PERCENT)) {
+ if (_value.is_zero())
+ _value.set_long(0);
+ else
+ _value = left % _value;
+ }
+ }
+
+ return true;
+ }
+
+ bool process_additive()
+ {
+ process_multiplicative();
+
+ while ((*_lex)->is(T_PLUS) || (*_lex)->is(T_MINUS)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_multiplicative();
+
+ if (op.is(T_PLUS))
+ _value = left + _value;
+ else if (op.is(T_MINUS))
+ _value = left - _value;
+ }
+
+ return true;
+ }
+
+ bool process_shift()
+ {
+ process_additive();
+
+ while ((*_lex)->is(T_MINUS_MINUS) || (*_lex)->is(T_GREATER_GREATER)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_additive();
+
+ if (op.is(T_MINUS_MINUS))
+ _value = left << _value;
+ else if (op.is(T_GREATER_GREATER))
+ _value = left >> _value;
+ }
+
+ return true;
+ }
+
+ bool process_relational()
+ {
+ process_shift();
+
+ while ((*_lex)->is(T_LESS) || (*_lex)->is(T_LESS_EQUAL) ||
+ (*_lex)->is(T_GREATER) || (*_lex)->is(T_GREATER_EQUAL)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_shift();
+
+ if (op.is(T_LESS))
+ _value = left < _value;
+ else if (op.is(T_LESS_EQUAL))
+ _value = left <= _value;
+ else if (op.is(T_GREATER))
+ _value = left > _value;
+ else if (op.is(T_GREATER_EQUAL))
+ _value = left >= _value;
+ }
+
+ return true;
+ }
+
+ bool process_equality()
+ {
+ process_relational();
+
+ while ((*_lex)->is(T_EXCLAIM_EQUAL) || (*_lex)->is(T_EQUAL_EQUAL)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_relational();
+
+ if (op.is(T_EXCLAIM_EQUAL))
+ _value = left != _value;
+ else if (op.is(T_EQUAL_EQUAL))
+ _value = left == _value;
+ }
+
+ return true;
+ }
+
+ bool process_and()
+ {
+ process_equality();
+
+ while ((*_lex)->is(T_AMPER)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_equality();
+
+ _value = left & _value;
+ }
+
+ return true;
+ }
+
+ bool process_xor()
+ {
+ process_and();
+
+ while ((*_lex)->is(T_CARET)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_and();
+
+ _value = left ^ _value;
+ }
+
+ return true;
+ }
+
+ bool process_or()
+ {
+ process_xor();
+
+ while ((*_lex)->is(T_CARET)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_xor();
+
+ _value = left | _value;
+ }
+
+ return true;
+ }
+
+ bool process_logical_and()
+ {
+ process_or();
+
+ while ((*_lex)->is(T_AMPER_AMPER)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_or();
+
+ _value = left && _value;
+ }
+
+ return true;
+ }
+
+ bool process_logical_or()
+ {
+ process_logical_and();
+
+ while ((*_lex)->is(T_PIPE_PIPE)) {
+ const Token op = *(*_lex);
+ ++(*_lex);
+
+ const Value left = _value;
+ process_logical_and();
+
+ _value = left || _value;
+ }
+
+ return true;
+ }
+
+ bool process_constant_expression()
+ {
+ process_logical_or();
+ const Value cond = _value;
+ if ((*_lex)->is(T_QUESTION)) {
+ ++(*_lex);
+ process_constant_expression();
+ Value left = _value, right;
+ if ((*_lex)->is(T_COLON)) {
+ ++(*_lex);
+ process_constant_expression();
+ right = _value;
+ }
+ _value = ! cond.is_zero() ? left : right;
+ }
+
+ return true;
+ }
+
+private:
+ Environment *env;
+ QByteArray source;
+ RangeLexer *_lex;
+ Value _value;
+};
+
+} // end of anonymous namespace
+
+
+pp::pp (Client *client, Environment &env)
+ : client(client),
+ env(env),
+ expand(env)
+{
+ resetIfLevel ();
+}
+
+void pp::pushState(const State &s)
+{
+ _savedStates.append(state());
+ _source = s.source;
+ _tokens = s.tokens;
+ _dot = s.dot;
+}
+
+pp::State pp::state() const
+{
+ State state;
+ state.source = _source;
+ state.tokens = _tokens;
+ state.dot = _dot;
+ return state;
+}
+
+void pp::popState()
+{
+ const State &state = _savedStates.last();
+ _source = state.source;
+ _tokens = state.tokens;
+ _dot = state.dot;
+ _savedStates.removeLast();
+}
+
+void pp::operator () (const QByteArray &filename,
+ const QByteArray &source,
+ QByteArray *result)
+{
+ const QByteArray previousFile = env.current_file;
+ env.current_file = filename;
+
+ operator () (source, result);
+
+ env.current_file = previousFile;
+}
+
+pp::State pp::createStateFromSource(const QByteArray &source) const
+{
+ State state;
+ state.source = source;
+ Lexer lex(state.source.constBegin(), state.source.constEnd());
+ lex.setScanKeywords(false);
+ Token tok;
+ do {
+ lex(&tok);
+ state.tokens.append(tok);
+ } while (tok.isNot(T_EOF_SYMBOL));
+ state.dot = state.tokens.constBegin();
+ return state;
+}
+
+void pp::operator()(const QByteArray &source, QByteArray *result)
+{
+ pushState(createStateFromSource(source));
+
+ const unsigned previousCurrentLine = env.currentLine;
+ env.currentLine = 0;
+
+ while (true) {
+ if (env.currentLine != _dot->lineno) {
+ if (env.currentLine > _dot->lineno) {
+ result->append('\n');
+ result->append('#');
+ result->append(QByteArray::number(_dot->lineno));
+ result->append(' ');
+ result->append('"');
+ result->append(env.current_file);
+ result->append('"');
+ result->append('\n');
+ } else {
+ for (unsigned i = env.currentLine; i < _dot->lineno; ++i)
+ result->append('\n');
+ }
+ env.currentLine = _dot->lineno;
+ }
+
+ if (_dot->is(T_EOF_SYMBOL)) {
+ break;
+ } else if (_dot->is(T_POUND) && (! _dot->joined && _dot->newline)) {
+ TokenIterator start = _dot;
+ do {
+ ++_dot;
+ } while (_dot->isNot(T_EOF_SYMBOL) && (_dot->joined || ! _dot->newline));
+
+ //qDebug() << QByteArray(first + beginPP.offset,
+ //tokens.last().end() - beginPP.offset);
+
+ const bool skippingBlocks = _skipping[iflevel];
+
+ processDirective(start, _dot);
+
+ if (client && skippingBlocks != _skipping[iflevel]) {
+ unsigned offset = start->offset;
+ if (_skipping[iflevel]) {
+ if (_dot->newline)
+ ++offset;
+ client->startSkippingBlocks(offset);
+ } else {
+ if (offset)
+ --offset;
+ client->stopSkippingBlocks(offset);
+ }
+ }
+ } else if (skipping()) {
+ do {
+ ++_dot;
+ } while (_dot->isNot(T_EOF_SYMBOL) && (_dot->joined || ! _dot->newline));
+ } else {
+ if (_dot->joined)
+ result->append("\\\n");
+ else if (_dot->newline) {
+ result->append('\n');
+ result->append('#');
+ result->append(QByteArray::number(_dot->lineno));
+ result->append(' ');
+ result->append('"');
+ result->append(env.current_file);
+ result->append('"');
+ result->append('\n');
+ }
+ else if (_dot->whitespace)
+ result->append(' ');
+
+ if (_dot->isNot(T_IDENTIFIER)) {
+ result->append(tokenSpell(*_dot));
+ ++_dot;
+ } else {
+ const TokenIterator identifierToken = _dot;
+ ++_dot; // skip T_IDENTIFIER
+
+ const QByteArray spell = tokenSpell(*identifierToken);
+ if (env.isBuiltinMacro(spell)) {
+ expand(spell.constBegin(), spell.constEnd(), result);
+ continue;
+ }
+
+ Macro *m = env.resolve(spell);
+ if (! m) {
+ result->append(spell);
+ } else {
+ if (! m->function_like) {
+ if (_dot->isNot(T_LPAREN)) {
+ expand(m->definition.constBegin(),
+ m->definition.constEnd(),
+ result);
+ continue;
+ } else {
+ QByteArray tmp;
+ expand(m->definition.constBegin(),
+ m->definition.constEnd(),
+ &tmp);
+
+ m = 0; // reset the active the macro
+
+ pushState(createStateFromSource(tmp));
+ if (_dot->is(T_IDENTIFIER)) {
+ const QByteArray id = tokenSpell(*_dot);
+ Macro *macro = env.resolve(id);
+ if (macro && macro->function_like)
+ m = macro;
+ }
+ popState();
+
+ if (! m) {
+ result->append(tmp);
+ continue;
+ }
+ }
+ }
+
+ // collect the actual arguments
+ if (_dot->isNot(T_LPAREN)) {
+ // ### warnng expected T_LPAREN
+ result->append(m->name);
+ continue;
+ }
+
+ int count = 0;
+ while (_dot->isNot(T_EOF_SYMBOL)) {
+ if (_dot->is(T_LPAREN))
+ ++count;
+ else if (_dot->is(T_RPAREN)) {
+ if (! --count)
+ break;
+ }
+ ++_dot;
+ }
+ if (_dot->isNot(T_RPAREN)) {
+ // ### warning expected T_RPAREN
+ } else {
+ const char *beginOfText = startOfToken(*identifierToken);
+ const char *endOfText = endOfToken(*_dot);
+ ++_dot; // skip T_RPAREN
+ expand(beginOfText, endOfText, result);
+ }
+ }
+ }
+ }
+ }
+
+ popState();
+ env.currentLine = previousCurrentLine;
+}
+
+const char *pp::startOfToken(const Token &token) const
+{ return _source.constBegin() + token.begin(); }
+
+const char *pp::endOfToken(const Token &token) const
+{ return _source.constBegin() + token.end(); }
+
+QByteArray pp::tokenSpell(const Token &token) const
+{
+ const QByteArray text = QByteArray::fromRawData(_source.constBegin() + token.offset,
+ token.length);
+ return text;
+}
+
+QByteArray pp::tokenText(const Token &token) const
+{
+ const QByteArray text(_source.constBegin() + token.offset,
+ token.length);
+ return text;
+}
+
+void pp::processDirective(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+ ++tk; // skip T_POUND
+
+ if (tk->is(T_IDENTIFIER)) {
+ const QByteArray directive = tokenSpell(*tk);
+ switch (PP_DIRECTIVE_TYPE d = classifyDirective(directive)) {
+ case PP_DEFINE:
+ if (! skipping())
+ processDefine(firstToken, lastToken);
+ break;
+
+ case PP_INCLUDE:
+ case PP_INCLUDE_NEXT:
+ if (! skipping())
+ processInclude(d == PP_INCLUDE_NEXT, firstToken, lastToken);
+ break;
+
+ case PP_UNDEF:
+ if (! skipping())
+ processUndef(firstToken, lastToken);
+ break;
+
+ case PP_ELIF:
+ processElif(firstToken, lastToken);
+ break;
+
+ case PP_ELSE:
+ processElse(firstToken, lastToken);
+ break;
+
+ case PP_ENDIF:
+ processEndif(firstToken, lastToken);
+ break;
+
+ case PP_IF:
+ processIf(firstToken, lastToken);
+ break;
+
+ case PP_IFDEF:
+ case PP_IFNDEF:
+ processIfdef(d == PP_IFNDEF, firstToken, lastToken);
+ break;
+
+ default:
+ break;
+ } // switch
+ }
+}
+
+QVector<Token> pp::tokenize(const QByteArray &text) const
+{
+ QVector<Token> tokens;
+ Lexer lex(text.constBegin(), text.constEnd());
+ lex.setScanKeywords(false);
+ Token tk;
+ do {
+ lex(&tk);
+ tokens.append(tk);
+ } while (tk.isNot(T_EOF_SYMBOL));
+ return tokens;
+}
+
+void pp::processInclude(bool skipCurentPath,
+ TokenIterator firstToken, TokenIterator lastToken,
+ bool acceptMacros)
+{
+ RangeLexer tk(firstToken, lastToken);
+ ++tk; // skip T_POUND
+ ++tk; // skip `include|nclude_next'
+
+ if (acceptMacros && tk->is(T_IDENTIFIER)) {
+#if 0
+ QByteArray name;
+ name.reserve(256);
+ MacroExpander expandInclude(env);
+ expandInclude(startOfToken(tokens.at(2)),
+ startOfToken(tokens.last()),
+ &name);
+ const QByteArray previousSource = switchSource(name);
+ //processInclude(skipCurentPath, tokenize(name), /*accept macros=*/ false);
+ (void) switchSource(previousSource);
+#endif
+ } else if (tk->is(T_LESS)) {
+ TokenIterator start = tk.dot();
+ for (; tk->isNot(T_EOF_SYMBOL); ++tk) {
+ if (tk->is(T_GREATER))
+ break;
+ }
+ const char *beginOfPath = endOfToken(*start);
+ const char *endOfPath = startOfToken(*tk);
+ const QByteArray path = QByteArray::fromRawData(beginOfPath,
+ endOfPath - beginOfPath);
+
+ QString fn = QString::fromUtf8(path.constData(), path.length());
+
+ if (client)
+ client->sourceNeeded(fn, Client::IncludeGlobal);
+ } else if (tk->is(T_ANGLE_STRING_LITERAL) || tk->is(T_STRING_LITERAL)) {
+ const QByteArray spell = tokenSpell(*tk);
+ const char *beginOfPath = spell.constBegin();
+ const char *endOfPath = spell.constEnd();
+ const char quote = *beginOfPath;
+ if (beginOfPath + 1 != endOfPath && ((quote == '"' && endOfPath[-1] == '"') ||
+ (quote == '<' && endOfPath[-1] == '>'))) {
+ const QByteArray path = QByteArray::fromRawData(beginOfPath + 1,
+ spell.length() - 2);
+ QString fn = QString::fromUtf8(path.constData(), path.length());
+
+ if (client)
+ client->sourceNeeded(fn, Client::IncludeLocal);
+ }
+ }
+}
+
+void pp::processDefine(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ if (tk.size() < 3)
+ return; // nothing to do
+
+ ++tk; // skip T_POUND
+ ++tk; // skip T_DEFINE
+
+ if (tk->isNot(T_IDENTIFIER)) {
+ // ### warning expected an `identifier'
+ return;
+ }
+
+ Macro macro;
+ macro.name = tokenText(*tk);
+ ++tk; // skip T_IDENTIFIER
+
+ if (tk->is(T_LPAREN) && ! tk->whitespace) {
+ // a function-like macro definition
+ macro.function_like = true;
+
+ ++tk; // skip T_LPAREN
+ if (tk->is(T_IDENTIFIER)) {
+ macro.formals.append(tokenText(*tk));
+ ++tk; // skip T_IDENTIFIER
+ while (tk->is(T_COMMA)) {
+ ++tk;// skip T_COMMA
+ if (tk->isNot(T_IDENTIFIER))
+ break;
+ macro.formals.append(tokenText(*tk));
+ ++tk; // skip T_IDENTIFIER
+ }
+ }
+
+ if (tk->is(T_DOT_DOT_DOT)) {
+ macro.variadics = true;
+ ++tk; // skip T_DOT_DOT_DOT
+ }
+
+ if (tk->isNot(T_RPAREN)) {
+ // ### warning expected `)'
+ return;
+ }
+
+ ++tk; // skip T_RPAREN
+ }
+
+ QByteArray macroId = macro.name;
+ const bool isQtWord = isQtReservedWord(macroId);
+
+ if (macro.function_like) {
+ macroId += '(';
+ for (int i = 0; i < macro.formals.size(); ++i) {
+ if (i != 0)
+ macroId += ", ";
+
+ const QByteArray formal = macro.formals.at(i);
+ macroId += formal;
+ }
+ macroId += ')';
+ }
+
+ if (isQtWord)
+ macro.definition = macroId;
+ else {
+ const char *startOfDefinition = startOfToken(*tk);
+ const char *endOfDefinition = startOfToken(*lastToken);
+ macro.definition.append(startOfDefinition,
+ endOfDefinition - startOfDefinition);
+ macro.definition.replace("\\\n", " ");
+ }
+
+ env.bind(macro);
+
+ QByteArray macroText;
+ macroText.reserve(64);
+ macroText += "#define ";
+
+ macroText += macroId;
+ macroText += ' ';
+ macroText += macro.definition;
+ macroText += '\n';
+
+ client->macroAdded(macroId, macroText);
+}
+
+void pp::processIf(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ ++tk; // skip T_POUND
+ ++tk; // skipt `if'
+
+ if (testIfLevel()) {
+ const char *first = startOfToken(*tk);
+ const char *last = startOfToken(*lastToken);
+
+ MacroExpander expandCondition (env);
+ QByteArray condition;
+ condition.reserve(256);
+ expandCondition(first, last, &condition);
+
+ QVector<Token> tokens = tokenize(condition);
+
+ const Value result = evalExpression(tokens.constBegin(),
+ tokens.constEnd() - 1,
+ condition);
+
+ _true_test[iflevel] = ! result.is_zero ();
+ _skipping[iflevel] = result.is_zero ();
+ }
+}
+
+void pp::processElse(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ if (iflevel == 0 && !skipping ()) {
+ // std::cerr << "*** WARNING #else without #if" << std::endl;
+ } else if (iflevel > 0 && _skipping[iflevel - 1]) {
+ _skipping[iflevel] = true;
+ } else {
+ _skipping[iflevel] = _true_test[iflevel];
+ }
+}
+
+void pp::processElif(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+ ++tk; // skip T_POUND
+ ++tk; // skipt `elif'
+
+ if (! (iflevel > 0)) {
+ // std::cerr << "*** WARNING: " << __FILE__ << __LINE__ << std::endl;
+ } else if (iflevel == 0 && !skipping()) {
+ // std::cerr << "*** WARNING #else without #if" << std::endl;
+ } else if (!_true_test[iflevel] && !_skipping[iflevel - 1]) {
+ const Value result = evalExpression(tk.dot(), lastToken, _source);
+ _true_test[iflevel] = ! result.is_zero ();
+ _skipping[iflevel] = result.is_zero ();
+ } else {
+ _skipping[iflevel] = true;
+ }
+}
+
+void pp::processEndif(TokenIterator, TokenIterator)
+{
+ if (iflevel == 0 && !skipping()) {
+ // std::cerr << "*** WARNING #endif without #if" << std::endl;
+ } else {
+ _skipping[iflevel] = false;
+ _true_test[iflevel] = false;
+
+ --iflevel;
+ }
+}
+
+void pp::processIfdef(bool checkUndefined,
+ TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ ++tk; // skip T_POUND
+ ++tk; // skip `ifdef'
+ if (testIfLevel()) {
+ if (tk->is(T_IDENTIFIER)) {
+ const QByteArray macroName = tokenSpell(*tk);
+ bool value = env.resolve(macroName) != 0 || env.isBuiltinMacro(macroName);
+
+ if (checkUndefined)
+ value = ! value;
+
+ _true_test[iflevel] = value;
+ _skipping [iflevel] = ! value;
+ }
+ }
+}
+
+void pp::processUndef(TokenIterator firstToken, TokenIterator lastToken)
+{
+ RangeLexer tk(firstToken, lastToken);
+
+ ++tk; // skip T_POUND
+ ++tk; // skip `undef'
+
+ if (tk->is(T_IDENTIFIER)) {
+ const QByteArray macroName = tokenText(*tk);
+ env.remove(macroName);
+
+ QByteArray macroText;
+ macroText += "#undef ";
+ macroText += macroName;
+ macroText += '\n';
+ client->macroAdded(macroName, macroText);
+ }
+}
+
+void pp::resetIfLevel ()
+{
+ iflevel = 0;
+ _skipping[iflevel] = false;
+ _true_test[iflevel] = false;
+}
+
+pp::PP_DIRECTIVE_TYPE pp::classifyDirective (const QByteArray &__directive) const
+{
+ switch (__directive.size())
+ {
+ case 2:
+ if (__directive[0] == 'i' && __directive[1] == 'f')
+ return PP_IF;
+ break;
+
+ case 4:
+ if (__directive[0] == 'e' && __directive == "elif")
+ return PP_ELIF;
+ else if (__directive[0] == 'e' && __directive == "else")
+ return PP_ELSE;
+ break;
+
+ case 5:
+ if (__directive[0] == 'i' && __directive == "ifdef")
+ return PP_IFDEF;
+ else if (__directive[0] == 'u' && __directive == "undef")
+ return PP_UNDEF;
+ else if (__directive[0] == 'e' && __directive == "endif")
+ return PP_ENDIF;
+ break;
+
+ case 6:
+ if (__directive[0] == 'i' && __directive == "ifndef")
+ return PP_IFNDEF;
+ else if (__directive[0] == 'd' && __directive == "define")
+ return PP_DEFINE;
+ break;
+
+ case 7:
+ if (__directive[0] == 'i' && __directive == "include")
+ return PP_INCLUDE;
+ break;
+
+ case 12:
+ if (__directive[0] == 'i' && __directive == "include_next")
+ return PP_INCLUDE_NEXT;
+ break;
+
+ default:
+ break;
+ }
+
+ return PP_UNKNOWN_DIRECTIVE;
+}
+
+bool pp::testIfLevel()
+{
+ const bool result = !_skipping[iflevel++];
+ _skipping[iflevel] = _skipping[iflevel - 1];
+ _true_test[iflevel] = false;
+ return result;
+}
+
+int pp::skipping() const
+{ return _skipping[iflevel]; }
+
+Value pp::evalExpression(TokenIterator firstToken, TokenIterator lastToken,
+ const QByteArray &source) const
+{
+ ExpressionEvaluator eval(&env);
+ const Value result = eval(firstToken, lastToken, source);
+ return result;
+}
+
+bool pp::isQtReservedWord (const QByteArray &macroId) const
+{
+ const int size = macroId.size();
+ if (size == 9 && macroId.at(0) == 'Q' && macroId == "Q_SIGNALS")
+ return true;
+ else if (size == 7 && macroId.at(0) == 'Q' && macroId == "Q_SLOTS")
+ return true;
+ else if (size == 6 && macroId.at(0) == 'S' && macroId == "SIGNAL")
+ return true;
+ else if (size == 4 && macroId.at(0) == 'S' && macroId == "SLOT")
+ return true;
+ else if (size == 7 && macroId.at(0) == 's' && macroId == "signals")
+ return true;
+ else if (size == 5 && macroId.at(0) == 's' && macroId == "slots")
+ return true;
+ return false;
+}
diff --git a/src/plugins/cpptools/rpp/pp-engine.h b/src/plugins/cpptools/rpp/pp-engine.h
new file mode 100644
index 0000000000..fb3b9a3212
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-engine.h
@@ -0,0 +1,230 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_ENGINE_H
+#define PP_ENGINE_H
+
+#include "pp-client.h"
+#include <Token.h>
+#include <QVector>
+
+namespace CPlusPlus {
+ class Token;
+}
+
+namespace rpp {
+
+ struct Value
+ {
+ enum Kind {
+ Kind_Long,
+ Kind_ULong,
+ };
+
+ Kind kind;
+
+ union {
+ long l;
+ unsigned long ul;
+ };
+
+
+ Value()
+ : kind(Kind_Long), l(0)
+ { }
+
+ inline bool is_ulong () const
+ { return kind == Kind_ULong; }
+
+ inline void set_ulong (unsigned long v)
+ {
+ ul = v;
+ kind = Kind_ULong;
+ }
+
+ inline void set_long (long v)
+ {
+ l = v;
+ kind = Kind_Long;
+ }
+
+ inline bool is_zero () const
+ { return l == 0; }
+
+#define PP_DEFINE_BIN_OP(name, op) \
+ inline Value operator op(const Value &other) const \
+ { \
+ Value v = *this; \
+ if (v.is_ulong () || other.is_ulong ()) \
+ v.set_ulong (v.ul op other.ul); \
+ else \
+ v.set_long (v.l op other.l); \
+ return v; \
+ }
+
+ PP_DEFINE_BIN_OP(op_add, +)
+ PP_DEFINE_BIN_OP(op_sub, -)
+ PP_DEFINE_BIN_OP(op_mult, *)
+ PP_DEFINE_BIN_OP(op_div, /)
+ PP_DEFINE_BIN_OP(op_mod, %)
+ PP_DEFINE_BIN_OP(op_lhs, <<)
+ PP_DEFINE_BIN_OP(op_rhs, >>)
+ PP_DEFINE_BIN_OP(op_lt, <)
+ PP_DEFINE_BIN_OP(op_gt, >)
+ PP_DEFINE_BIN_OP(op_le, <=)
+ PP_DEFINE_BIN_OP(op_ge, >=)
+ PP_DEFINE_BIN_OP(op_eq, ==)
+ PP_DEFINE_BIN_OP(op_ne, !=)
+ PP_DEFINE_BIN_OP(op_bit_and, &)
+ PP_DEFINE_BIN_OP(op_bit_or, |)
+ PP_DEFINE_BIN_OP(op_bit_xor, ^)
+ PP_DEFINE_BIN_OP(op_and, &&)
+ PP_DEFINE_BIN_OP(op_or, ||)
+
+#undef PP_DEFINE_BIN_OP
+ };
+
+ class pp
+ {
+ Client *client;
+ Environment &env;
+ MacroExpander expand;
+
+ enum { MAX_LEVEL = 512 };
+
+ bool _skipping[MAX_LEVEL]; // ### move in state
+ bool _true_test[MAX_LEVEL]; // ### move in state
+ int iflevel; // ### move in state
+
+ enum PP_DIRECTIVE_TYPE
+ {
+ PP_UNKNOWN_DIRECTIVE,
+ PP_DEFINE,
+ PP_INCLUDE,
+ PP_INCLUDE_NEXT,
+ PP_ELIF,
+ PP_ELSE,
+ PP_ENDIF,
+ PP_IF,
+ PP_IFDEF,
+ PP_IFNDEF,
+ PP_UNDEF
+ };
+
+ typedef const CPlusPlus::Token *TokenIterator;
+
+ struct State {
+ QByteArray source;
+ QVector<CPlusPlus::Token> tokens;
+ TokenIterator dot;
+ };
+
+ QList<State> _savedStates;
+
+ State state() const;
+ void pushState(const State &state);
+ void popState();
+
+ QByteArray _source;
+ QVector<CPlusPlus::Token> _tokens;
+ TokenIterator _dot;
+
+ State createStateFromSource(const QByteArray &source) const;
+
+ public:
+ pp(Client *client, Environment &env);
+
+ void operator()(const QByteArray &filename,
+ const QByteArray &source,
+ QByteArray *result);
+
+ void operator()(const QByteArray &source,
+ QByteArray *result);
+
+ private:
+ void resetIfLevel();
+ bool testIfLevel();
+ int skipping() const;
+
+ PP_DIRECTIVE_TYPE classifyDirective(const QByteArray &directive) const;
+
+ Value evalExpression(TokenIterator firstToken,
+ TokenIterator lastToken,
+ const QByteArray &source) const;
+
+ QVector<CPlusPlus::Token> tokenize(const QByteArray &text) const;
+
+ const char *startOfToken(const CPlusPlus::Token &token) const;
+ const char *endOfToken(const CPlusPlus::Token &token) const;
+
+ QByteArray tokenSpell(const CPlusPlus::Token &token) const;
+ QByteArray tokenText(const CPlusPlus::Token &token) const; // does a deep copy
+
+ void processDirective(TokenIterator dot, TokenIterator lastToken);
+ void processInclude(bool skipCurrentPath,
+ TokenIterator dot, TokenIterator lastToken,
+ bool acceptMacros = true);
+ void processDefine(TokenIterator dot, TokenIterator lastToken);
+ void processIf(TokenIterator dot, TokenIterator lastToken);
+ void processElse(TokenIterator dot, TokenIterator lastToken);
+ void processElif(TokenIterator dot, TokenIterator lastToken);
+ void processEndif(TokenIterator dot, TokenIterator lastToken);
+ void processIfdef(bool checkUndefined,
+ TokenIterator dot, TokenIterator lastToken);
+ void processUndef(TokenIterator dot, TokenIterator lastToken);
+
+ bool isQtReservedWord(const QByteArray &name) const;
+ };
+
+} // namespace rpp
+
+#endif // PP_ENGINE_H
diff --git a/src/plugins/cpptools/rpp/pp-environment.cpp b/src/plugins/cpptools/rpp/pp-environment.cpp
new file mode 100644
index 0000000000..1503787898
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-environment.cpp
@@ -0,0 +1,231 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "pp-environment.h"
+#include "pp.h"
+#include <cstring>
+
+using namespace rpp;
+
+Environment::Environment ()
+ : currentLine(0),
+ hide_next(false),
+ _macros(0),
+ _allocated_macros(0),
+ _macro_count(-1),
+ _hash(0),
+ _hash_count(401)
+{
+}
+
+Environment::~Environment ()
+{
+ if (_macros) {
+ qDeleteAll(firstMacro(), lastMacro());
+ free(_macros);
+ }
+
+ if (_hash)
+ free(_hash);
+}
+
+unsigned Environment::macroCount () const
+{ return _macro_count + 1; }
+
+Macro *Environment::macroAt (unsigned index) const
+{ return _macros[index]; }
+
+Macro *Environment::bind(const Macro &__macro)
+{
+ Q_ASSERT(! __macro.name.isEmpty());
+
+ Macro *m = new Macro (__macro);
+ m->hashcode = hash_code(m->name);
+ m->fileName = current_file;
+ m->line = currentLine;
+
+ if (++_macro_count == _allocated_macros) {
+ if (! _allocated_macros)
+ _allocated_macros = 401;
+ else
+ _allocated_macros <<= 1;
+
+ _macros = (Macro **) realloc(_macros, sizeof(Macro *) * _allocated_macros);
+ }
+
+ _macros[_macro_count] = m;
+
+ if (! _hash || _macro_count > (_hash_count >> 1)) {
+ rehash();
+ } else {
+ const unsigned h = m->hashcode % _hash_count;
+ m->next = _hash[h];
+ _hash[h] = m;
+ }
+
+ return m;
+}
+
+void Environment::remove (const QByteArray &name)
+{
+ Macro macro;
+ macro.name = name;
+ macro.hidden = true;
+ bind(macro);
+}
+
+bool Environment::isBuiltinMacro(const QByteArray &s) const
+{
+ if (s.length() != 8)
+ return false;
+
+ if (s[0] == '_') {
+ if (s[1] == '_') {
+ if (s[2] == 'D') {
+ if (s[3] == 'A') {
+ if (s[4] == 'T') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'F') {
+ if (s[3] == 'I') {
+ if (s[4] == 'L') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'L') {
+ if (s[3] == 'I') {
+ if (s[4] == 'N') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[2] == 'T') {
+ if (s[3] == 'I') {
+ if (s[4] == 'M') {
+ if (s[5] == 'E') {
+ if (s[6] == '_') {
+ if (s[7] == '_') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+Macro *Environment::resolve (const QByteArray &name) const
+{
+ if (! _macros)
+ return 0;
+
+ Macro *it = _hash[hash_code (name) % _hash_count];
+ for (; it; it = it->next) {
+ if (it->name != name)
+ continue;
+ else if (it->hidden)
+ return 0;
+ else break;
+ }
+ return it;
+}
+
+unsigned Environment::hash_code (const QByteArray &s)
+{
+ unsigned hash_value = 0;
+
+ for (int i = 0; i < s.size (); ++i)
+ hash_value = (hash_value << 5) - hash_value + s.at (i);
+
+ return hash_value;
+}
+
+void Environment::rehash()
+{
+ if (_hash) {
+ free(_hash);
+ _hash_count <<= 1;
+ }
+
+ _hash = (Macro **) calloc(_hash_count, sizeof(Macro *));
+
+ for (Macro **it = firstMacro(); it != lastMacro(); ++it) {
+ Macro *m= *it;
+ const unsigned h = m->hashcode % _hash_count;
+ m->next = _hash[h];
+ _hash[h] = m;
+ }
+}
diff --git a/src/plugins/cpptools/rpp/pp-environment.h b/src/plugins/cpptools/rpp/pp-environment.h
new file mode 100644
index 0000000000..cdecf4de61
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-environment.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_ENVIRONMENT_H
+#define PP_ENVIRONMENT_H
+
+#include <QVector>
+#include <QByteArray>
+
+namespace rpp {
+
+struct Macro;
+
+class Environment
+{
+public:
+ Environment();
+ ~Environment();
+
+ unsigned macroCount() const;
+ Macro *macroAt(unsigned index) const;
+
+ Macro *bind(const Macro &macro);
+ void remove(const QByteArray &name);
+
+ Macro *resolve(const QByteArray &name) const;
+ bool isBuiltinMacro(const QByteArray &name) const;
+
+ const Macro *const *firstMacro() const
+ { return _macros; }
+
+ Macro **firstMacro()
+ { return _macros; }
+
+ const Macro *const *lastMacro() const
+ { return _macros + _macro_count + 1; }
+
+ Macro **lastMacro()
+ { return _macros + _macro_count + 1; }
+
+private:
+ static unsigned hash_code (const QByteArray &s);
+ void rehash();
+
+public:
+ QByteArray current_file;
+ unsigned currentLine;
+ bool hide_next;
+
+private:
+ Macro **_macros;
+ int _allocated_macros;
+ int _macro_count;
+ Macro **_hash;
+ int _hash_count;
+};
+
+} // namespace rpp
+
+#endif // PP_ENVIRONMENT_H
diff --git a/src/plugins/cpptools/rpp/pp-fwd.h b/src/plugins/cpptools/rpp/pp-fwd.h
new file mode 100644
index 0000000000..05b68774cf
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-fwd.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_FWD_H
+#define PP_FWD_H
+
+namespace rpp {
+
+} // namespace rpp
+
+#endif // PP_FWD_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/src/plugins/cpptools/rpp/pp-internal.h b/src/plugins/cpptools/rpp/pp-internal.h
new file mode 100644
index 0000000000..eed958372c
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-internal.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_INTERNAL_H
+#define PP_INTERNAL_H
+
+#include <QByteArray>
+
+namespace rpp {
+
+ namespace _PP_internal
+ {
+
+ inline void output_line(const QByteArray &__filename, int __line, QByteArray *__result)
+ {
+ QByteArray __msg;
+
+ __msg += "# ";
+
+ char __line_descr[16];
+ qsnprintf (__line_descr, 16, "%d", __line);
+ __msg += __line_descr;
+
+ __msg += " \"";
+
+ if (__filename.isEmpty ())
+ __msg += "<editor>";
+ else
+ __msg += __filename;
+
+ __msg += "\"\n";
+ __result->append(__msg);
+ }
+
+ inline 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 == '*');
+ }
+
+ } // _PP_internal
+
+} // namespace rpp
+
+#endif // PP_INTERNAL_H
diff --git a/src/plugins/cpptools/rpp/pp-macro-expander.cpp b/src/plugins/cpptools/rpp/pp-macro-expander.cpp
new file mode 100644
index 0000000000..658f2acc67
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-macro-expander.cpp
@@ -0,0 +1,362 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "pp.h"
+#include "pp-macro-expander.h"
+#include <QDateTime>
+
+using namespace rpp;
+
+MacroExpander::MacroExpander (Environment &env, pp_frame *frame)
+ : env (env), frame (frame),
+ lines (0), generated_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)
+{
+ generated_lines = 0;
+ __first = skip_blanks (__first, __last);
+ lines = skip_blanks.lines;
+
+ while (__first != __last)
+ {
+ if (*__first == '\n')
+ {
+ __result->append('\n');
+ __result->append('#');
+ __result->append(QByteArray::number(env.currentLine));
+ __result->append(' ');
+ __result->append('"');
+ __result->append(env.current_file);
+ __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
+ __result->append('#'); // ### 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 (_PP_internal::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;
+ 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);
+
+ if (const QByteArray *actual = resolve_formal (fast_name))
+ {
+ 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);
+ continue;
+ }
+
+ Macro *macro = env.resolve (fast_name);
+ if (! macro || macro->hidden || env.hide_next)
+ {
+ if (fast_name.size () == 7 && fast_name [0] == 'd' && fast_name == "defined")
+ env.hide_next = true;
+ else
+ env.hide_next = false;
+
+ if (fast_name.size () == 8 && fast_name [0] == '_' && fast_name [1] == '_')
+ {
+ if (fast_name == "__LINE__")
+ {
+ char buf [16];
+ const size_t count = qsnprintf (buf, 16, "%d", env.currentLine + lines);
+ __result->append(buf, count);
+ continue;
+ }
+
+ else if (fast_name == "__FILE__")
+ {
+ __result->append('"');
+ __result->append(env.current_file);
+ __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->function_like)
+ {
+ Macro *m = 0;
+
+ if (! macro->definition.isEmpty())
+ {
+ macro->hidden = true;
+
+ QByteArray __tmp;
+ __tmp.reserve (256);
+
+ MacroExpander expand_macro (env);
+ expand_macro (macro->definition.constBegin (), macro->definition.constEnd (), &__tmp);
+ generated_lines += expand_macro.lines;
+
+ 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->hidden = 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 (5);
+ ++arg_it; // skip '('
+
+ MacroExpander expand_actual (env, frame);
+
+ const char *arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
+ if (arg_it != arg_end)
+ {
+ const QByteArray actual (arg_it, arg_end - arg_it);
+ QByteArray expanded;
+ expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
+ actuals.push_back (expanded);
+ arg_it = arg_end;
+ }
+
+ while (arg_it != __last && *arg_end == ',')
+ {
+ ++arg_it; // skip ','
+
+ arg_end = skip_argument_variadics (actuals, macro, arg_it, __last);
+ const QByteArray actual (arg_it, arg_end - arg_it);
+ QByteArray expanded;
+ expand_actual (actual.constBegin (), actual.constEnd (), &expanded);
+ actuals.push_back (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->hidden = true;
+ expand_macro (macro->definition.constBegin (), macro->definition.constEnd (), __result);
+ macro->hidden = false;
+ generated_lines += expand_macro.lines;
+ }
+ 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->variadics && __first != arg_end && arg_end != __last && *arg_end == ','
+ && (__actuals.size () + 1) == __macro->formals.size ())
+ {
+ arg_end = skip_argument (++arg_end, __last);
+ }
+
+ return arg_end;
+}
diff --git a/src/plugins/cpptools/rpp/pp-macro-expander.h b/src/plugins/cpptools/rpp/pp-macro-expander.h
new file mode 100644
index 0000000000..bdf21a421b
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-macro-expander.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_MACRO_EXPANDER_H
+#define PP_MACRO_EXPANDER_H
+
+namespace rpp {
+
+ 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)
+ { }
+ };
+
+ class MacroExpander
+ {
+ Environment &env;
+ pp_frame *frame;
+
+ pp_skip_number skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_argument skip_argument;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ pp_skip_blanks skip_blanks;
+ pp_skip_whitespaces skip_whitespaces;
+
+ const QByteArray *resolve_formal (const QByteArray &name);
+
+ public:
+ MacroExpander (Environment &env, pp_frame *frame = 0);
+
+ const char *operator () (const char *first, const char *last,
+ QByteArray *result);
+
+ const char *skip_argument_variadics (const QVector<QByteArray> &actuals,
+ Macro *macro,
+ const char *first, const char *last);
+
+ public: // attributes
+ int lines;
+ int generated_lines;
+ };
+
+} // namespace rpp
+
+#endif // PP_MACRO_EXPANDER_H
+
diff --git a/src/plugins/cpptools/rpp/pp-macro.h b/src/plugins/cpptools/rpp/pp-macro.h
new file mode 100644
index 0000000000..b220168989
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-macro.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_MACRO_H
+#define PP_MACRO_H
+
+#include <QByteArray>
+#include <QVector>
+
+namespace rpp {
+
+ struct Macro
+ {
+ QByteArray name;
+ QByteArray definition;
+ QVector<QByteArray> formals;
+ QByteArray fileName;
+ int line;
+ int lines;
+ Macro *next;
+ unsigned hashcode;
+
+ union
+ {
+ unsigned state;
+
+ struct
+ {
+ unsigned hidden: 1;
+ unsigned function_like: 1;
+ unsigned variadics: 1;
+ };
+ };
+
+ inline Macro():
+ line(0),
+ lines(0),
+ next(0),
+ hashcode(0),
+ state(0)
+ { }
+ };
+
+} // namespace rpp
+
+#endif // PP_MACRO_H
diff --git a/src/plugins/cpptools/rpp/pp-scanner.h b/src/plugins/cpptools/rpp/pp-scanner.h
new file mode 100644
index 0000000000..d9036d8855
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-scanner.h
@@ -0,0 +1,380 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_SCANNER_H
+#define PP_SCANNER_H
+
+namespace rpp {
+
+struct pp_skip_blanks
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (*__first == '\\')
+ {
+ const char *__begin = __first;
+ ++__begin;
+
+ if (__begin != __last && *__begin == '\n')
+ ++__first;
+ else
+ break;
+ }
+ else if (*__first == '\n' || !pp_isspace (*__first))
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_whitespaces
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (! pp_isspace (*__first))
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_comment_or_divop
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ enum {
+ MAYBE_BEGIN,
+ BEGIN,
+ MAYBE_END,
+ END,
+ IN_COMMENT,
+ IN_CXX_COMMENT
+ } state (MAYBE_BEGIN);
+
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ switch (state)
+ {
+ default:
+ assert (0);
+ break;
+
+ case MAYBE_BEGIN:
+ if (*__first != '/')
+ return __first;
+
+ state = BEGIN;
+ break;
+
+ case BEGIN:
+ if (*__first == '*')
+ state = IN_COMMENT;
+ else if (*__first == '/')
+ state = IN_CXX_COMMENT;
+ else
+ return __first;
+ break;
+
+ case IN_COMMENT:
+ if (*__first == '*')
+ state = MAYBE_END;
+ break;
+
+ case IN_CXX_COMMENT:
+ if (*__first == '\n')
+ return __first;
+ break;
+
+ case MAYBE_END:
+ if (*__first == '/')
+ state = END;
+ else if (*__first != '*')
+ state = IN_COMMENT;
+ break;
+
+ case END:
+ return __first;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_identifier
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (! pp_isalnum (*__first) && *__first != '_')
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_number
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ if (! pp_isalnum (*__first) && *__first != '.')
+ break;
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_string_literal
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state (BEGIN);
+
+ lines = 0;
+
+ for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ switch (state)
+ {
+ default:
+ assert (0);
+ break;
+
+ case BEGIN:
+ if (*__first != '\"')
+ return __first;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ if (! (*__first != '\n'))
+ return __last;
+
+ if (*__first == '\"')
+ state = END;
+ else if (*__first == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+
+ case END:
+ return __first;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_char_literal
+{
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ enum {
+ BEGIN,
+ IN_STRING,
+ QUOTE,
+ END
+ } state (BEGIN);
+
+ lines = 0;
+
+ for (; state != END && __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first)
+ {
+ switch (state)
+ {
+ default:
+ assert (0);
+ break;
+
+ case BEGIN:
+ if (*__first != '\'')
+ return __first;
+ state = IN_STRING;
+ break;
+
+ case IN_STRING:
+ if (! (*__first != '\n'))
+ return __last;
+
+ if (*__first == '\'')
+ state = END;
+ else if (*__first == '\\')
+ state = QUOTE;
+ break;
+
+ case QUOTE:
+ state = IN_STRING;
+ break;
+ }
+ }
+
+ return __first;
+ }
+};
+
+struct pp_skip_argument
+{
+ pp_skip_identifier skip_number;
+ pp_skip_identifier skip_identifier;
+ pp_skip_string_literal skip_string_literal;
+ pp_skip_char_literal skip_char_literal;
+ pp_skip_comment_or_divop skip_comment_or_divop;
+ int lines;
+
+
+ const char *operator () (const char *__first, const char *__last)
+ {
+ int depth = 0;
+ lines = 0;
+
+ while (__first != __last)
+ {
+ if (!depth && (*__first == ')' || *__first == ','))
+ break;
+ else if (*__first == '(')
+ ++depth, ++__first;
+ else if (*__first == ')')
+ --depth, ++__first;
+ else if (*__first == '\"')
+ {
+ __first = skip_string_literal (__first, __last);
+ lines += skip_string_literal.lines;
+ }
+ else if (*__first == '\'')
+ {
+ __first = skip_char_literal (__first, __last);
+ lines += skip_char_literal.lines;
+ }
+ else if (*__first == '/')
+ {
+ __first = skip_comment_or_divop (__first, __last);
+ lines += skip_comment_or_divop.lines;
+ }
+ else if (pp_isalpha (*__first) || *__first == '_')
+ {
+ __first = skip_identifier (__first, __last);
+ lines += skip_identifier.lines;
+ }
+ else if (pp_isdigit (*__first))
+ {
+ __first = skip_number (__first, __last);
+ lines += skip_number.lines;
+ }
+ else if (*__first == '\n')
+ {
+ ++__first;
+ ++lines;
+ }
+ else
+ ++__first;
+ }
+
+ return __first;
+ }
+};
+
+} // namespace rpp
+
+#endif // PP_SCANNER_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/src/plugins/cpptools/rpp/pp-symbol.h b/src/plugins/cpptools/rpp/pp-symbol.h
new file mode 100644
index 0000000000..37e2a623e5
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp-symbol.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
diff --git a/src/plugins/cpptools/rpp/pp.h b/src/plugins/cpptools/rpp/pp.h
new file mode 100644
index 0000000000..52411f7624
--- /dev/null
+++ b/src/plugins/cpptools/rpp/pp.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/*
+ Copyright 2005 Roberto Raggi <roberto@kdevelop.org>
+
+ Permission to use, copy, modify, distribute, and sell this software and its
+ documentation for any purpose is hereby granted without fee, provided that
+ the above copyright notice appear in all copies and that both that
+ copyright notice and this permission notice appear in supporting
+ documentation.
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef PP_H
+#define PP_H
+
+#if defined(_WIN64) || defined(WIN64) || defined(__WIN64__) \
+ || defined(_WIN32) || defined(WIN32) || defined(__WIN32__)
+# define PP_OS_WIN
+#endif
+
+#include <cassert>
+#include <cstring>
+#include <cctype>
+
+#include "pp-fwd.h"
+#include "pp-cctype.h"
+#include "pp-symbol.h"
+#include "pp-internal.h"
+#include "pp-macro.h"
+#include "pp-environment.h"
+#include "pp-scanner.h"
+#include "pp-macro-expander.h"
+#include "pp-engine.h"
+#include "pp-client.h"
+
+#endif // PP_H
diff --git a/src/plugins/cpptools/rpp/rpp.pri b/src/plugins/cpptools/rpp/rpp.pri
new file mode 100644
index 0000000000..f47976e6fe
--- /dev/null
+++ b/src/plugins/cpptools/rpp/rpp.pri
@@ -0,0 +1,20 @@
+DEPENDPATH += $$PWD
+INCLUDEPATH += $$PWD
+
+HEADERS += $$PWD/pp-cctype.h \
+ $$PWD/pp-engine.h \
+ $$PWD/pp-environment.h \
+ $$PWD/pp-fwd.h \
+ $$PWD/pp-internal.h \
+ $$PWD/pp-macro-expander.h \
+ $$PWD/pp-macro.h \
+ $$PWD/pp-scanner.h \
+ $$PWD/pp-symbol.h \
+ $$PWD/pp.h \
+ $$PWD/pp-client.h
+
+SOURCES += $$PWD/pp-engine.cpp \
+ $$PWD/pp-environment.cpp \
+ $$PWD/pp-macro-expander.cpp
+
+