diff options
Diffstat (limited to 'src/plugins/cpptools/rpp')
-rw-r--r-- | src/plugins/cpptools/rpp/pp-cctype.h | 76 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-client.h | 69 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-engine.cpp | 1085 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-engine.h | 230 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-environment.cpp | 231 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-environment.h | 109 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-fwd.h | 62 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-internal.h | 102 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-macro-expander.cpp | 362 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-macro-expander.h | 103 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-macro.h | 95 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-scanner.h | 380 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp-symbol.h | 52 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/pp.h | 76 | ||||
-rw-r--r-- | src/plugins/cpptools/rpp/rpp.pri | 20 |
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 ¯oId, 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 ¯oId) 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 ¯o); + 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 + + |