diff options
author | Oswald Buddenhagen <oswald.buddenhagen@nokia.com> | 2011-05-16 10:53:42 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@nokia.com> | 2011-05-16 11:05:30 +0200 |
commit | 67704b8b41b053eddbd4119a04115fb0fb2c9237 (patch) | |
tree | 094fb9bc849f2467d6389267d5613574a48f478f /src/libs/3rdparty/cplusplus/TranslationUnit.cpp | |
parent | 5a39fba5805d34fbef16a50d20312b8a9de5bdfc (diff) |
move src/shared/cplusplus/ -> src/libs/3rdparty/cplusplus/
Approved-by: legal
Diffstat (limited to 'src/libs/3rdparty/cplusplus/TranslationUnit.cpp')
-rw-r--r-- | src/libs/3rdparty/cplusplus/TranslationUnit.cpp | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/src/libs/3rdparty/cplusplus/TranslationUnit.cpp b/src/libs/3rdparty/cplusplus/TranslationUnit.cpp new file mode 100644 index 0000000000..ba6572e7a2 --- /dev/null +++ b/src/libs/3rdparty/cplusplus/TranslationUnit.cpp @@ -0,0 +1,511 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at info@qt.nokia.com. +** +**************************************************************************/ +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// 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 +// AUTHORS OR COPYRIGHT HOLDERS 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 "TranslationUnit.h" +#include "Control.h" +#include "Parser.h" +#include "Lexer.h" +#include "MemoryPool.h" +#include "AST.h" +#include "Literals.h" +#include "DiagnosticClient.h" +#include <stack> +#include <cstdarg> +#include <algorithm> + +#ifdef _MSC_VER +# define va_copy(dst, src) ((dst) = (src)) +#elif defined(__INTEL_COMPILER) && !defined(va_copy) +# define va_copy __va_copy +#endif + +using namespace CPlusPlus; + +TranslationUnit::TranslationUnit(Control *control, const StringLiteral *fileId) + : _control(control), + _fileId(fileId), + _firstSourceChar(0), + _lastSourceChar(0), + _pool(0), + _ast(0), + _flags(0) +{ + _tokens = new std::vector<Token>(); + _previousTranslationUnit = control->switchTranslationUnit(this); + _pool = new MemoryPool(); +} + +TranslationUnit::~TranslationUnit() +{ + (void) _control->switchTranslationUnit(_previousTranslationUnit); + delete _tokens; + delete _pool; +} + +bool TranslationUnit::qtMocRunEnabled() const +{ return f._qtMocRunEnabled; } + +void TranslationUnit::setQtMocRunEnabled(bool onoff) +{ f._qtMocRunEnabled = onoff; } + +bool TranslationUnit::cxx0xEnabled() const +{ return f._cxx0xEnabled; } + +void TranslationUnit::setCxxOxEnabled(bool onoff) +{ f._cxx0xEnabled = onoff; } + +bool TranslationUnit::objCEnabled() const +{ return f._objCEnabled; } + +void TranslationUnit::setObjCEnabled(bool onoff) +{ f._objCEnabled = onoff; } + +Control *TranslationUnit::control() const +{ return _control; } + +const StringLiteral *TranslationUnit::fileId() const +{ return _fileId; } + +const char *TranslationUnit::fileName() const +{ return _fileId->chars(); } + +unsigned TranslationUnit::fileNameLength() const +{ return _fileId->size(); } + +const char *TranslationUnit::firstSourceChar() const +{ return _firstSourceChar; } + +const char *TranslationUnit::lastSourceChar() const +{ return _lastSourceChar; } + +unsigned TranslationUnit::sourceLength() const +{ return _lastSourceChar - _firstSourceChar; } + +void TranslationUnit::setSource(const char *source, unsigned size) +{ + _firstSourceChar = source; + _lastSourceChar = source + size; +} + +unsigned TranslationUnit::tokenCount() const +{ return _tokens->size(); } + +const Token &TranslationUnit::tokenAt(unsigned index) const +{ return _tokens->at(index); } + +int TranslationUnit::tokenKind(unsigned index) const +{ return _tokens->at(index).f.kind; } + +const char *TranslationUnit::spell(unsigned index) const +{ + if (! index) + return 0; + + return _tokens->at(index).spell(); +} + +const Identifier *TranslationUnit::identifier(unsigned index) const +{ return _tokens->at(index).identifier; } + +const Literal *TranslationUnit::literal(unsigned index) const +{ return _tokens->at(index).literal; } + +const StringLiteral *TranslationUnit::stringLiteral(unsigned index) const +{ return _tokens->at(index).string; } + +const NumericLiteral *TranslationUnit::numericLiteral(unsigned index) const +{ return _tokens->at(index).number; } + +unsigned TranslationUnit::matchingBrace(unsigned index) const +{ return _tokens->at(index).close_brace; } + +MemoryPool *TranslationUnit::memoryPool() const +{ return _pool; } + +AST *TranslationUnit::ast() const +{ return _ast; } + +bool TranslationUnit::isTokenized() const +{ return f._tokenized; } + +bool TranslationUnit::isParsed() const +{ return f._parsed; } + +void TranslationUnit::tokenize() +{ + if (isTokenized()) + return; + + f._tokenized = true; + + Lexer lex(this); + lex.setQtMocRunEnabled(f._qtMocRunEnabled); + lex.setCxxOxEnabled(f._cxx0xEnabled); + lex.setObjCEnabled(f._objCEnabled); + + std::stack<unsigned> braces; + _tokens->push_back(Token()); // the first token needs to be invalid! + + pushLineOffset(0); + pushPreprocessorLine(0, 1, fileId()); + + const Identifier *lineId = control()->identifier("line"); + const Identifier *genId = control()->identifier("gen"); + + bool generated = false; + Token tk; + do { + lex(&tk); + + _Lrecognize: + if (tk.is(T_POUND) && tk.newline()) { + unsigned offset = tk.offset; + lex(&tk); + + if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == genId) { + // it's a gen directive. + lex(&tk); + + if (! tk.f.newline && tk.is(T_TRUE)) { + lex(&tk); + generated = true; + } else { + generated = false; + } + } else { + if (! tk.f.newline && tk.is(T_IDENTIFIER) && tk.identifier == lineId) + lex(&tk); + if (! tk.f.newline && tk.is(T_NUMERIC_LITERAL)) { + unsigned line = (unsigned) strtoul(tk.spell(), 0, 0); + lex(&tk); + if (! tk.f.newline && tk.is(T_STRING_LITERAL)) { + const StringLiteral *fileName = control()->stringLiteral(tk.string->chars(), + tk.string->size()); + pushPreprocessorLine(offset, line, fileName); + lex(&tk); + } + } + } + while (tk.isNot(T_EOF_SYMBOL) && ! tk.f.newline) + lex(&tk); + goto _Lrecognize; + } else if (tk.f.kind == T_LBRACE) { + braces.push(_tokens->size()); + } else if (tk.f.kind == T_RBRACE && ! braces.empty()) { + const unsigned open_brace_index = braces.top(); + braces.pop(); + (*_tokens)[open_brace_index].close_brace = _tokens->size(); + } + tk.f.generated = generated; + _tokens->push_back(tk); + } while (tk.f.kind); + + for (; ! braces.empty(); braces.pop()) { + unsigned open_brace_index = braces.top(); + (*_tokens)[open_brace_index].close_brace = _tokens->size(); + } +} + +bool TranslationUnit::skipFunctionBody() const +{ return f._skipFunctionBody; } + +void TranslationUnit::setSkipFunctionBody(bool skipFunctionBody) +{ f._skipFunctionBody = skipFunctionBody; } + +bool TranslationUnit::parse(ParseMode mode) +{ + if (isParsed()) + return false; + + if (! isTokenized()) + tokenize(); + + f._parsed = true; + + Parser parser(this); + parser.setQtMocRunEnabled(f._qtMocRunEnabled); + parser.setCxxOxEnabled(f._cxx0xEnabled); + parser.setObjCEnabled(f._objCEnabled); + + bool parsed = false; + + switch (mode) { + case ParseTranlationUnit: { + TranslationUnitAST *node = 0; + parsed = parser.parseTranslationUnit(node); + _ast = node; + } break; + + case ParseDeclaration: { + DeclarationAST *node = 0; + parsed = parser.parseDeclaration(node); + _ast = node; + } break; + + case ParseExpression: { + ExpressionAST *node = 0; + parsed = parser.parseExpression(node); + _ast = node; + } break; + + case ParseDeclarator: { + DeclaratorAST *node = 0; + parsed = parser.parseDeclarator(node, /*decl_specifier_list =*/ 0); + _ast = node; + } break; + + case ParseStatement: { + StatementAST *node = 0; + parsed = parser.parseStatement(node); + _ast = node; + } break; + + default: + break; + } // switch + + return parsed; +} + +void TranslationUnit::pushLineOffset(unsigned offset) +{ _lineOffsets.push_back(offset); } + +void TranslationUnit::pushPreprocessorLine(unsigned offset, + unsigned line, + const StringLiteral *fileName) +{ _ppLines.push_back(PPLine(offset, line, fileName)); } + +unsigned TranslationUnit::findLineNumber(unsigned offset) const +{ + std::vector<unsigned>::const_iterator it = + std::lower_bound(_lineOffsets.begin(), _lineOffsets.end(), offset); + + if (it != _lineOffsets.begin()) + --it; + + return it - _lineOffsets.begin(); +} + +TranslationUnit::PPLine TranslationUnit::findPreprocessorLine(unsigned offset) const +{ + std::vector<PPLine>::const_iterator it = + std::lower_bound(_ppLines.begin(), _ppLines.end(), PPLine(offset)); + + if (it != _ppLines.begin()) + --it; + + return *it; +} + +unsigned TranslationUnit::findColumnNumber(unsigned offset, unsigned lineNumber) const +{ + if (! offset) + return 0; + + return offset - _lineOffsets[lineNumber]; +} + +void TranslationUnit::getTokenPosition(unsigned index, + unsigned *line, + unsigned *column, + const StringLiteral **fileName) const +{ return getPosition(tokenAt(index).offset, line, column, fileName); } + +void TranslationUnit::getTokenStartPosition(unsigned index, unsigned *line, + unsigned *column, + const StringLiteral **fileName) const +{ return getPosition(tokenAt(index).begin(), line, column, fileName); } + +void TranslationUnit::getTokenEndPosition(unsigned index, unsigned *line, + unsigned *column, + const StringLiteral **fileName) const +{ return getPosition(tokenAt(index).end(), line, column, fileName); } + +void TranslationUnit::getPosition(unsigned tokenOffset, + unsigned *line, + unsigned *column, + const StringLiteral **fileName) const +{ + unsigned lineNumber = findLineNumber(tokenOffset); + unsigned columnNumber = findColumnNumber(tokenOffset, lineNumber); + const PPLine ppLine = findPreprocessorLine(tokenOffset); + + lineNumber -= findLineNumber(ppLine.offset) + 1; + lineNumber += ppLine.line; + + if (line) + *line = lineNumber; + + if (column) + *column = columnNumber; + + if (fileName) + *fileName = ppLine.fileName; +} + +bool TranslationUnit::blockErrors(bool block) +{ + bool previous = f._blockErrors; + f._blockErrors = block; + return previous; +} + +void TranslationUnit::message(DiagnosticClient::Level level, unsigned index, const char *format, va_list args) +{ + if (f._blockErrors) + return; + + index = std::min(index, tokenCount() - 1); + + unsigned line = 0, column = 0; + const StringLiteral *fileName = 0; + getTokenPosition(index, &line, &column, &fileName); + + if (DiagnosticClient *client = control()->diagnosticClient()) { + client->report(level, fileName, line, column, format, args); + } else { + fprintf(stderr, "%s:%d: ", fileName->chars(), line); + const char *l = "error"; + if (level == DiagnosticClient::Warning) + l = "warning"; + else if (level == DiagnosticClient::Fatal) + l = "fatal"; + fprintf(stderr, "%s: ", l); + + vfprintf(stderr, format, args); + fputc('\n', stderr); + + showErrorLine(index, column, stderr); + } + + if (level == DiagnosticClient::Fatal) + exit(EXIT_FAILURE); +} + +void TranslationUnit::warning(unsigned index, const char *format, ...) +{ + if (f._blockErrors) + return; + + va_list args, ap; + va_start(args, format); + va_copy(ap, args); + message(DiagnosticClient::Warning, index, format, args); + va_end(ap); + va_end(args); +} + +void TranslationUnit::error(unsigned index, const char *format, ...) +{ + if (f._blockErrors) + return; + + va_list args, ap; + va_start(args, format); + va_copy(ap, args); + message(DiagnosticClient::Error, index, format, args); + va_end(ap); + va_end(args); +} + +void TranslationUnit::fatal(unsigned index, const char *format, ...) +{ + if (f._blockErrors) + return; + + va_list args, ap; + va_start(args, format); + va_copy(ap, args); + message(DiagnosticClient::Fatal, index, format, args); + va_end(ap); + va_end(args); +} + +unsigned TranslationUnit::findPreviousLineOffset(unsigned tokenIndex) const +{ + unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(tokenIndex).offset)]; + return lineOffset; +} + +void TranslationUnit::showErrorLine(unsigned index, unsigned column, FILE *out) +{ + unsigned lineOffset = _lineOffsets[findLineNumber(_tokens->at(index).offset)]; + for (const char *cp = _firstSourceChar + lineOffset + 1; *cp && *cp != '\n'; ++cp) { + fputc(*cp, out); + } + fputc('\n', out); + + const char *end = _firstSourceChar + lineOffset + 1 + column - 1; + for (const char *cp = _firstSourceChar + lineOffset + 1; cp != end; ++cp) { + if (*cp != '\t') + fputc(' ', out); + else + fputc('\t', out); + } + fputc('^', out); + fputc('\n', out); +} + +void TranslationUnit::resetAST() +{ + delete _pool; + _pool = 0; + _ast = 0; +} + +void TranslationUnit::release() +{ + resetAST(); + delete _tokens; + _tokens = 0; +} + + |