diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index 8be327c79cb8110c6843335ccb7e38519d6dd108..d0582de05d16c598af41f138722432c7922f3444 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -265,7 +265,9 @@ QtcPlugin { "namedemangler/namedemangler.h", "namedemangler/parsetreenodes.cpp", "namedemangler/parsetreenodes.h", - "namedemangler/demanglerexceptions.h" + "namedemangler/demanglerexceptions.h", + "namedemangler/globalparsestate.h", + "namedemangler/globalparsestate.cpp" ] Group { diff --git a/src/plugins/debugger/namedemangler/globalparsestate.cpp b/src/plugins/debugger/namedemangler/globalparsestate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c1123962205833ca5cd8907163a822b1b9556ac --- /dev/null +++ b/src/plugins/debugger/namedemangler/globalparsestate.cpp @@ -0,0 +1,77 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ +#include "globalparsestate.h" + +#include "demanglerexceptions.h" +#include "parsetreenodes.h" + +namespace Debugger { +namespace Internal { + +char GlobalParseState::peek(int ahead) +{ + Q_ASSERT(m_pos >= 0); + if (m_pos + ahead < m_mangledName.size()) + return m_mangledName[m_pos + ahead]; + return eoi; +} + +char GlobalParseState::advance(int steps) +{ + Q_ASSERT(steps > 0); + if (m_pos + steps > m_mangledName.size()) + throw ParseException(QLatin1String("Unexpected end of input")); + + const char c = m_mangledName[m_pos]; + m_pos += steps; + return c; +} + +QByteArray GlobalParseState::readAhead(int charCount) const +{ + QByteArray str; + if (m_pos + charCount <= m_mangledName.size()) + str = m_mangledName.mid(m_pos, charCount); + else + str.fill(eoi, charCount); + return str; +} + +void GlobalParseState::addSubstitution(const ParseTreeNode *node) +{ + const QByteArray symbol = node->toByteArray(); + if (!symbol.isEmpty() && !m_substitutions.contains(symbol)) + m_substitutions.append(symbol); +} + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/namedemangler/globalparsestate.h b/src/plugins/debugger/namedemangler/globalparsestate.h new file mode 100644 index 0000000000000000000000000000000000000000..796681c22abb3c18188f670f36ba09e72af0cb25 --- /dev/null +++ b/src/plugins/debugger/namedemangler/globalparsestate.h @@ -0,0 +1,84 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ +#ifndef GLOBAL_PARSE_STATE_H +#define GLOBAL_PARSE_STATE_H + +#include +#include + +namespace Debugger { +namespace Internal { +class NameDemanglerPrivate; +class ParseTreeNode; + +class GlobalParseState +{ + friend class NameDemanglerPrivate; +public: + char peek(int ahead = 0); + char advance(int steps = 1); + QByteArray readAhead(int charCount) const; + + int stackElementCount() const { return m_parseStack.count(); } + ParseTreeNode *stackTop() const { return m_parseStack.top(); } + ParseTreeNode *stackElementAt(int index) const { return m_parseStack.at(index); } + void pushToStack(ParseTreeNode *node) { m_parseStack.push(node); } + ParseTreeNode *popFromStack() { return m_parseStack.pop(); } + + int substitutionCount() const { return m_substitutions.count(); } + QByteArray substitutionAt(int index) const { return m_substitutions.at(index); } + void addSubstitution(const ParseTreeNode *node); + + int templateParamCount() const { return m_templateParams.count(); } + ParseTreeNode *templateParamAt(int index) const { return m_templateParams.at(index); } + void addTemplateParam(ParseTreeNode *node) { m_templateParams << node; } + void clearTemplateParams() { m_templateParams.clear(); } + + // TODO: Can we get rid of this by analyzing the stack? + bool isConversionOperator() const { return m_isConversionOperator; } + void setIsConversionOperator(bool is) { m_isConversionOperator = is; } + +private: + int m_pos; + QByteArray m_mangledName; + QList m_substitutions; + QList m_templateParams; + bool m_isConversionOperator; + QStack m_parseStack; + + static const char eoi = '$'; +}; + +} // namespace Internal +} // namespace Debugger + +#endif // GLOBAL_PARSE_STATE_H diff --git a/src/plugins/debugger/namedemangler/namedemangler.cpp b/src/plugins/debugger/namedemangler/namedemangler.cpp index e3f79dadc890e2444531a159078cb2e6257bd7dc..b0c41886a1266d238c0e7d59d05b4df7547e9891 100644 --- a/src/plugins/debugger/namedemangler/namedemangler.cpp +++ b/src/plugins/debugger/namedemangler/namedemangler.cpp @@ -35,36 +35,8 @@ #include "demanglerexceptions.h" #include "parsetreenodes.h" -#include -#include -#include -#include -#include -#include - -#include #include -#define PARSE_RULE_AND_ADD_RESULT_AS_CHILD(rule, parentNode) \ - do { \ - parse##rule(); \ - DEMANGLER_ASSERT(!m_parseStack.isEmpty()); \ - DEMANGLER_ASSERT(dynamic_cast(m_parseStack.top())); \ - popNodeFromStackAndAddAsChild(parentNode); \ - } while (0) - -// Debugging facility. -//#define DO_TRACE -#ifdef DO_TRACE -#define FUNC_START() \ - qDebug("Function %s has started, input is at position %d.", Q_FUNC_INFO, m_pos) -#define FUNC_END() \ - qDebug("Function %s has finished, input is at position %d..", m_pos) -#else -#define FUNC_START() -#define FUNC_END() -#endif // DO_TRACE - namespace Debugger { namespace Internal { @@ -76,74 +48,9 @@ public: const QString &demangledName() const { return m_demangledName; } private: - char peek(int ahead = 0); - char advance(int steps = 1); - const QByteArray readAhead(int charCount); - - void addSubstitution(const ParseTreeNode *node); - - // One parse function per Non-terminal. - void parseArrayType(); - void parseBareFunctionType(); - void parseBuiltinType(); - void parseCallOffset(); - void parseClassEnumType(); - void parseCtorDtorName(); - void parseCvQualifiers(); - void parseDigit(); - void parseDiscriminator(); - void parseEncoding(); - void parseExpression(); - void parseExprPrimary(); - void parseFloatValue(); - void parseFunctionType(); - void parseLocalName(); - void parseMangledName(); - void parseName(); - void parseNestedName(); - void parseNonNegativeNumber(int base = 10); - void parseNumber(int base = 10); - void parseNvOffset(); - void parseOperatorName(); - void parsePointerToMemberType(); - void parsePrefix(); - void parsePrefix2(); - void parseSpecialName(); - void parseSourceName(); - void parseSubstitution(); - void parseTemplateArg(); - void parseTemplateArgs(); - int parseTemplateParam(); - void parseType(); - void parseUnqualifiedName(); - void parseUnscopedName(); - void parseVOffset(); - - const QByteArray getIdentifier(int len); - int getNonNegativeNumber(int base = 10); - - template T *allocateNodeAndAddToStack() - { - T * const node = new T; - m_parseStack.push(node); - return node; - } - - void popNodeFromStackAndAddAsChild(ParseTreeNode *parentNode) - { - parentNode->addChild(m_parseStack.pop()); - } - - static const char eoi = '$'; - - int m_pos; - QByteArray m_mangledName; + GlobalParseState m_parseState; QString m_errorString; QString m_demangledName; - QList m_substitutions; - QList m_templateParams; - bool m_isConversionOperator; - QStack m_parseStack; }; @@ -151,29 +58,28 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName) { bool success; try { - m_mangledName = mangledName.toAscii(); - m_pos = 0; - m_isConversionOperator = false; + m_parseState.m_mangledName = mangledName.toAscii(); + m_parseState.m_pos = 0; + m_parseState.m_isConversionOperator = false; m_demangledName.clear(); - if (!MangledNameNode::mangledRepresentationStartsWith(peek())) { - m_demangledName = m_mangledName; + if (!MangledNameNode::mangledRepresentationStartsWith(m_parseState.peek())) { + m_demangledName = m_parseState.m_mangledName; return true; } - parseMangledName(); - if (m_pos != m_mangledName.size()) + ParseTreeNode::parseRule(&m_parseState); + if (m_parseState.m_pos != m_parseState.m_mangledName.size()) throw ParseException(QLatin1String("Unconsumed input")); - if (m_parseStack.count() != 1) { + if (m_parseState.m_parseStack.count() != 1) { throw ParseException(QString::fromLocal8Bit("There are %1 elements on the parse stack; " - "expected one.").arg(m_parseStack.count())); + "expected one.").arg(m_parseState.m_parseStack.count())); } - m_demangledName = m_parseStack.top()->toByteArray(); - + m_demangledName = m_parseState.m_parseStack.top()->toByteArray(); success = true; } catch (const ParseException &p) { m_errorString = QString::fromLocal8Bit("Parse error at index %1 of mangled name '%2': %3.") - .arg(m_pos).arg(mangledName, p.error); + .arg(m_parseState.m_pos).arg(mangledName, p.error); success = false; } catch (const InternalDemanglerException &e) { m_errorString = QString::fromLocal8Bit("Internal demangler error at function %1, file %2, " @@ -181,1547 +87,11 @@ bool NameDemanglerPrivate::demangle(const QString &mangledName) success = false; } - qDeleteAll(m_parseStack); - m_parseStack.clear(); - m_substitutions.clear(); - m_templateParams.clear(); - return success; -} - -/* - * Grammar: http://www.codesourcery.com/public/cxx-abi/abi.html#mangling - * The grammar as given there is not LL(k), so a number of transformations - * were necessary, which we will document at the respective parsing function. - * ::= _Z - */ -void NameDemanglerPrivate::parseMangledName() -{ - FUNC_START(); - - MangledNameNode * const node = allocateNodeAndAddToStack(); - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Encoding, node); - - FUNC_END(); -} - -/* - * ::= - * ::= - * ::= - */ -void NameDemanglerPrivate::parseEncoding() -{ - FUNC_START(); - - EncodingNode * const encodingNode = allocateNodeAndAddToStack(); - const char next = peek(); - if (NameNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Name, encodingNode); - if (BareFunctionTypeNode::mangledRepresentationStartsWith(peek())) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(BareFunctionType, encodingNode); - addSubstitution(encodingNode); - m_templateParams.clear(); - m_isConversionOperator = false; - } else if (SpecialNameNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SpecialName, encodingNode); - } else { - throw ParseException(QString::fromLatin1("Invalid encoding")); - } - - FUNC_END(); -} - - -/* - * ::= - * ::= - * ::= - * ::= # See Scope Encoding below - * - * We can't use this rule directly, because - * can expand to . We therefore integrate it directly - * into the production for : - * ::= [] - * ::= - * - * Secondly, shares an expansion ("St") with , - * so we have to look further ahead to see which one matches. - */ -void NameDemanglerPrivate::parseName() -{ - FUNC_START(); - - NameNode * const node = allocateNodeAndAddToStack(); - - if ((readAhead(2) == "St" && UnqualifiedNameNode::mangledRepresentationStartsWith(peek(2))) - || UnscopedNameNode::mangledRepresentationStartsWith(peek())) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnscopedName, node); - if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { - addSubstitution(node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); - } - } else { - const char next = peek(); - if (NestedNameNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NestedName, node); - } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Substitution, node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); - } else if (LocalNameNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(LocalName, node); - } else { - throw ParseException(QString::fromLatin1("Invalid name")); - } - } - - FUNC_END(); -} - -/* - * ::= N [] E - * ::= N [] E - * ::= - * ::= - * ::= - * - * The rule leads to an indirect recursion with , so - * we integrate it into : - * ::= N [] - * [] E - * ::= N [] E - * ::= N [] E - * - * The occurrence of in the first expansion makes this rule - * completely unmanageable, because 's first and follow sets are - * not distinct and it also shares elements of its first set with - * and . However, can expand - * to both the non-terminals it is followed by as well as the two competing - * non-terminal sequences in the other rules, so we can just write: - * ::= N [] E - * - * That's not all, though: Both and can start - * with an 'r', so we have to do a two-character-look-ahead for that case. - */ -void NameDemanglerPrivate::parseNestedName() -{ - FUNC_START(); - - if (!NestedNameNode::mangledRepresentationStartsWith(advance())) - throw ParseException(QString::fromLatin1("Invalid nested-name")); - - NestedNameNode * const node = allocateNodeAndAddToStack(); - - if (CvQualifiersNode::mangledRepresentationStartsWith(peek()) && peek(1) != 'm' - && peek(1) != 'M' && peek(1) != 's' && peek(1) != 'S') { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CvQualifiers, node); - } - - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Prefix, node); - - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid nested-name")); - - FUNC_END(); -} - -/* - * ::= - * ::= - * ::= - * ::= # empty - * ::= - * - * We have to eliminate the left-recursion and the template-prefix rule - * and end up with this: - * ::= [] - * ::= [] - * ::= - */ -void NameDemanglerPrivate::parsePrefix() -{ - FUNC_START(); - - PrefixNode * const node = allocateNodeAndAddToStack(); - - const char next = peek(); - if (TemplateParamNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParam, node); - if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { - addSubstitution(node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); - } - if (UnqualifiedNameNode::mangledRepresentationStartsWith(peek())) { - addSubstitution(node); - parsePrefix2(); // Pops itself to child list. - } - } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Substitution, node); - if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); - if (UnqualifiedNameNode::mangledRepresentationStartsWith(peek())) - addSubstitution(node); - } - parsePrefix2(); // Pops itself to child list. - } else { - parsePrefix2(); // Pops itself to child list. - } - - FUNC_END(); -} - -/* - * ::= [] - * ::= # empty - */ -void NameDemanglerPrivate::parsePrefix2() -{ - FUNC_START(); - - // We need to do this so we can correctly add all substitutions, which always start - // with the representation of the prefix node. - ParseTreeNode * const prefixNode = m_parseStack.top(); - Prefix2Node * const node = allocateNodeAndAddToStack(); - prefixNode->addChild(node); - - bool firstRun = true; - while (UnqualifiedNameNode::mangledRepresentationStartsWith(peek())) { - if (!firstRun) - addSubstitution(prefixNode); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedName, node); - if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { - addSubstitution(prefixNode); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); - } - firstRun = false; - } - - m_parseStack.pop(); - FUNC_END(); -} - -/* - * ::= I + E - */ -void NameDemanglerPrivate::parseTemplateArgs() -{ - FUNC_START(); - - TemplateArgsNode * const node = allocateNodeAndAddToStack(); - - if (!TemplateArgsNode::mangledRepresentationStartsWith(advance())) - throw ParseException(QString::fromLatin1("Invalid template args")); - - do - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArg, node); - while (TemplateArgNode::mangledRepresentationStartsWith(peek())); - - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid template args")); - - FUNC_END(); -} - -/* - * ::= T_ # first template parameter - * ::= T _ - */ -int NameDemanglerPrivate::parseTemplateParam() -{ - FUNC_START(); - - if (!TemplateParamNode::mangledRepresentationStartsWith(advance())) - throw ParseException(QString::fromLatin1("Invalid template-param")); - - TemplateParamNode * const node = allocateNodeAndAddToStack(); - - int index; - if (peek() == '_') - index = 0; - else - index = getNonNegativeNumber() + 1; - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid template-param")); - if (index >= m_templateParams.count()) { - if (!m_isConversionOperator) { - throw ParseException(QString::fromLocal8Bit("Invalid template parameter index %1") - .arg(index)); - } - } else { - node->addChild(m_templateParams.at(index)); - } - - FUNC_END(); - return index; -} - -/* ::= [r] [V] [K] # restrict (C99), volatile, const */ -void NameDemanglerPrivate::parseCvQualifiers() -{ - FUNC_START(); - - CvQualifiersNode * const node = allocateNodeAndAddToStack(); - node->m_hasConst = false; - node->m_hasVolatile = false; - - while (true) { - if (peek() == 'V') { - if (node->m_hasConst || node->m_hasVolatile) - throw ParseException(QLatin1String("Invalid qualifiers: unexpected 'volatile'")); - node->m_hasVolatile = true; - advance(); - } else if (peek() == 'K') { - if (node->m_hasConst) - throw ParseException(QLatin1String("Invalid qualifiers: 'const' appears twice")); - node->m_hasConst = true; - advance(); - } else { - break; - } - } - - FUNC_END(); -} - -/* ::= [n] */ -void NameDemanglerPrivate::parseNumber(int base) -{ - FUNC_START(); - - const char next = peek(); - if (!NumberNode::mangledRepresentationStartsWith(next, base)) - throw ParseException("Invalid number"); - - NumberNode * const node = allocateNodeAndAddToStack(); - - if (next == 'n') { - node->m_isNegative = true; - advance(); - } else { - node->m_isNegative = false; - } - - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NonNegativeNumber, node); - - FUNC_END(); -} - - -void NameDemanglerPrivate::parseNonNegativeNumber(int base) -{ - FUNC_START(); - - NonNegativeNumberNode * const node = allocateNodeAndAddToStack(); - - int startPos = m_pos; - while (NonNegativeNumberNode::mangledRepresentationStartsWith(peek(), base)) - advance(); - if (m_pos == startPos) - throw ParseException(QString::fromLatin1("Invalid non-negative number")); - node->m_number = m_mangledName.mid(startPos, m_pos - startPos).toULongLong(0, base); - - FUNC_END(); -} - -/* - * Floating-point literals are encoded using a fixed-length lowercase - * hexadecimal string corresponding to the internal representation - * (IEEE on Itanium), high-order bytes first, without leading zeroes. - * For example: "Lf bf800000 E" is -1.0f on Itanium. - */ -void NameDemanglerPrivate::parseFloatValue() -{ - FUNC_START(); - - FloatValueNode * const node = allocateNodeAndAddToStack(); - node->m_value = 0; - - while (FloatValueNode::mangledRepresentationStartsWith(peek())) { - // TODO: Construct value; - advance(); - } - - FUNC_END(); -} - -/* - * ::= # type or template - * ::= X E # expression - * ::= # simple expressions - * ::= J * E # argument pack - * ::= sp # pack expansion of (C++0x) - */ -void NameDemanglerPrivate::parseTemplateArg() -{ - FUNC_START(); - - TemplateArgNode * const node = allocateNodeAndAddToStack(); - node->m_isTemplateArgumentPack = false; - - char next = peek(); - if (readAhead(2) == "sp") { - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); - } else if (TypeNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else if (ExprPrimaryNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExprPrimary, node); - } else if (next == 'X') { - advance(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid template-arg")); - } else if (next == 'J') { - advance(); - while (TemplateArgNode::mangledRepresentationStartsWith(peek())) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArg, node); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid template-arg")); - } else { - throw ParseException(QString::fromLatin1("Invalid template-arg")); - } - - m_templateParams.append(node); - FUNC_END(); -} - -/* - * ::= - * ::= - * ::= - * ::= cl * E # call - * ::= cv expression # conversion with one argument - * ::= cv _ * E # conversion with a different number of arguments - * ::= st # sizeof (a type) - * ::= at # alignof (a type) - * ::= - * ::= - * ::= sr # dependent name - * ::= sr # dependent template-id - * ::= sZ # size of a parameter pack - * ::= - * - * Note that the grammar is missing the definition of . This - * has not been a problem in the test cases so far. - * TODO: is now defined and should therefore be supported - */ -void NameDemanglerPrivate::parseExpression() -{ - FUNC_START(); - - ExpressionNode * const node = allocateNodeAndAddToStack(); - node->m_type = ExpressionNode::OtherType; - - /* - * Some of the terminals in the productions of - * also appear in the productions of . We assume the direct - * productions to have higher precedence and check them first to prevent - * them being parsed by parseOperatorName(). - */ - QByteArray str = readAhead(2); - if (str == "cl") { - advance(2); - while (ExpressionNode::mangledRepresentationStartsWith(peek())) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid expression")); - } else if (str == "cv") { - node->m_type = ExpressionNode::ConversionType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - if (peek() == '_') { - advance(); - while (ExpressionNode::mangledRepresentationStartsWith(peek())) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid expression")); - } else { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); - } - } else if (str == "st") { - node->m_type = ExpressionNode::SizeofType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else if (str == "at") { - node->m_type = ExpressionNode::AlignofType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else if (str == "sr") { // TODO: Which syntax to use here? - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedName, node); - if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); - } else if (str == "sZ") { - node->m_type = ExpressionNode::ParameterPackSizeType; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParam, node); - } else { - const char next = peek(); - if (OperatorNameNode::mangledRepresentationStartsWith(next)) { - node->m_type = ExpressionNode::OperatorType; - parseOperatorName(); - OperatorNameNode * const opNode = DEMANGLER_CAST(OperatorNameNode, m_parseStack.pop()); - node->addChild(opNode); - - int expressionCount; - switch (opNode->m_type) { - case OperatorNameNode::TernaryType: - expressionCount = 3; - break; - case OperatorNameNode::ArrayNewType: - case OperatorNameNode::BinaryPlusType: - case OperatorNameNode::BinaryMinusType: - case OperatorNameNode::MultType: - case OperatorNameNode::DivType: - case OperatorNameNode::ModuloType: - case OperatorNameNode::BitwiseAndType: - case OperatorNameNode::BitwiseOrType: - case OperatorNameNode::XorType: - case OperatorNameNode::AssignType: - case OperatorNameNode::IncrementAndAssignType: - case OperatorNameNode::DecrementAndAssignType: - case OperatorNameNode::MultAndAssignType: - case OperatorNameNode::DivAndAssignType: - case OperatorNameNode::ModuloAndAssignType: - case OperatorNameNode::BitwiseAndAndAssignType: - case OperatorNameNode::BitwiseOrAndAssignType: - case OperatorNameNode::XorAndAssignType: - case OperatorNameNode::LeftShiftType: - case OperatorNameNode::RightShiftType: - case OperatorNameNode::LeftShiftAndAssignType: - case OperatorNameNode::RightShiftAndAssignType: - case OperatorNameNode::EqualsType: - case OperatorNameNode::NotEqualsType: - case OperatorNameNode::LessType: - case OperatorNameNode::GreaterType: - case OperatorNameNode::LessEqualType: - case OperatorNameNode::GreaterEqualType: - case OperatorNameNode::LogicalAndType: - case OperatorNameNode::LogicalOrType: - case OperatorNameNode::CommaType: - case OperatorNameNode::ArrowStarType: - case OperatorNameNode::ArrowType: - case OperatorNameNode::IndexType: - expressionCount = 2; - break; - default: - expressionCount = 1; - } - - for (int i = 0; i < expressionCount; ++i) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); - - } else if (TemplateParamNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParam, node); - -#if 0 - } else if (FunctionParamNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(FunctionParam, node); -#endif - } else if (ExprPrimaryNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExprPrimary, node); - } else { - throw ParseException(QString::fromLatin1("Invalid expression")); - } - } - - FUNC_END(); -} - -/* - * ::= L E # integer literal - * ::= L E # floating literal - * ::= L E # external name - */ - // TODO: This has been updated in the spec. Needs to be adapted. (nullptr etc.) -void NameDemanglerPrivate::parseExprPrimary() -{ - FUNC_START(); - - ExprPrimaryNode * const node = allocateNodeAndAddToStack(); - - if (!ExprPrimaryNode::mangledRepresentationStartsWith(advance())) - throw ParseException(QString::fromLatin1("Invalid primary expression")); - const char next = peek(); - if (TypeNode::mangledRepresentationStartsWith(next)) { - parseType(); - const ParseTreeNode * const topLevelTypeNode = m_parseStack.top(); - BuiltinTypeNode * const typeNode = topLevelTypeNode->childCount() == 0 - ? 0 : dynamic_cast(CHILD_AT(topLevelTypeNode, 0)); - if (!typeNode) - throw ParseException(QLatin1String("Invalid type in expr-primary")); - PredefinedBuiltinTypeNode * const predefTypeNode - = dynamic_cast(CHILD_AT(typeNode, 0)); - if (!predefTypeNode) - throw ParseException(QLatin1String("Invalid type in expr-primary")); - - // TODO: Of which type can a literal actually be? - switch (predefTypeNode->m_type) { - case PredefinedBuiltinTypeNode::SignedIntType: - case PredefinedBuiltinTypeNode::UnsignedIntType: - case PredefinedBuiltinTypeNode::UnsignedLongType: - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Number, node); - break; - case PredefinedBuiltinTypeNode::FloatType: case PredefinedBuiltinTypeNode::DoubleType: - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(FloatValue, node); - break; - default: - throw ParseException(QString::fromLatin1("Invalid type in expr-primary")); - } - delete m_parseStack.pop(); // No need to keep the type node in the tree. - } else if (MangledNameNode::mangledRepresentationStartsWith(next)) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(MangledName, node); - } else { - throw ParseException(QString::fromLatin1("Invalid expr-primary")); - } - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid expr-primary")); - - FUNC_END(); -} - -/* - * ::= - * ::= - * ::= - * ::= - * ::= - * ::= - * ::= - * ::= # See Compression below - * ::= - * ::= P # pointer-to - * ::= R # reference-to - * ::= O # rvalue reference-to (C++0x) - * ::= C # complex pair (C 2000) - * ::= G # imaginary (C 2000) - * ::= U # vendor extended type qualifier - * ::= Dp # pack expansion of (C++0x) - * ::= Dt E # decltype of an id-expression or class member access (C++0x) - * ::= DT E # decltype of an expression (C++0x) - * - * Because can expand to , we have to - * do a slight transformation: We get rid of and - * integrate its rhs into 's rhs. This leads to the following - * identical prefixes: - * ::= - * ::= - * ::= - * ::= - * - * Also, the first set of has some overlap with - * direct productions of , so these have to be worked around as well. - */ -void NameDemanglerPrivate::parseType() -{ - FUNC_START(); - - TypeNode * const node = allocateNodeAndAddToStack(); - - QByteArray str = readAhead(2); - if (str == "Dp") { - node->m_type = TypeNode::PackExpansionType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else if (str == "Dt") { - node->m_type = TypeNode::DeclType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid type")); - } else if (str == "DT") { - node->m_type = TypeNode::DeclType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid type")); - } else { - const char next = peek(); - if (str == "Dd" || str == "De" || str == "Df" || str == "Dh" || str == "Di" || str == "Ds" - || (next != 'D' && BuiltinTypeNode::mangledRepresentationStartsWith(next))) { - node->m_type = TypeNode::OtherType; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(BuiltinType, node); - } else if (FunctionTypeNode::mangledRepresentationStartsWith(next)) { - node->m_type = TypeNode::OtherType; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(FunctionType, node); - addSubstitution(node); - } else if (ClassEnumTypeNode::mangledRepresentationStartsWith(next)) { - node->m_type = TypeNode::OtherType; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ClassEnumType, node); - addSubstitution(node); - } else if (ArrayTypeNode::mangledRepresentationStartsWith(next)) { - node->m_type = TypeNode::OtherType; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ArrayType, node); - } else if (PointerToMemberTypeNode::mangledRepresentationStartsWith(next)) { - node->m_type = TypeNode::OtherType; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(PointerToMemberType, node); - } else if (TemplateParamNode::mangledRepresentationStartsWith(next)) { - node->m_type = TypeNode::OtherType; - const int templateIndex = parseTemplateParam(); - popNodeFromStackAndAddAsChild(node); - // The type is now a substitution candidate, but the child node may contain a forward - // reference, so we delay the substitution until it is resolved. - // TODO: Check whether this is really safe, i.e. whether the following parse function - // might indirectly expect this substitution to already exist. - - if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); - // Substitution delayed, see above. - } - - // Resolve forward reference, if necessary. - ParseTreeNode * const templateParamNode = CHILD_AT(node, 0); - if (templateParamNode->childCount() == 0) { - if (templateIndex >= m_templateParams.count()) { - throw ParseException(QString::fromLocal8Bit("Invalid template parameter " - "index %1 in forwarding").arg(templateIndex)); - } - templateParamNode->addChild(m_templateParams.at(templateIndex)); - } - - // Delayed substitutions from above. - addSubstitution(templateParamNode); - if (node->childCount() > 1) - addSubstitution(node); - } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { - node->m_type = TypeNode::OtherType; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Substitution, node); - if (TemplateArgsNode::mangledRepresentationStartsWith(peek())) { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgs, node); - addSubstitution(node); - } - } else if (CvQualifiersNode::mangledRepresentationStartsWith(next)) { - node->m_type = TypeNode::QualifiedType; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CvQualifiers, node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - const CvQualifiersNode * const cvNode - = DEMANGLER_CAST(CvQualifiersNode, CHILD_AT(node, 0)); - if (cvNode->m_hasConst || cvNode->m_hasVolatile) - addSubstitution(node); - } else if (next == 'P') { - node->m_type = TypeNode::PointerType; - advance(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - addSubstitution(node); - } else if (next == 'R') { - node->m_type = TypeNode::ReferenceType; - advance(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - addSubstitution(node); - } else if (next == 'O') { - node->m_type = TypeNode::RValueType; - advance(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - addSubstitution(node); - } else if (next == 'C') { - node->m_type = TypeNode::OtherType; - advance(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - addSubstitution(node); - } else if (next == 'G') { - node->m_type = TypeNode::OtherType; - advance(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - addSubstitution(node); - } else if (next == 'U') { - node->m_type = TypeNode::VendorType; - advance(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceName, node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else { - throw ParseException(QString::fromLatin1("Invalid type")); - } - } - - FUNC_END(); -} - -/* ::= */ -void NameDemanglerPrivate::parseSourceName() -{ - FUNC_START(); - - SourceNameNode * const node = allocateNodeAndAddToStack(); - - const int idLen = getNonNegativeNumber(); - node->m_name = getIdentifier(idLen); - - FUNC_END(); -} - -/* - * ::= v # void - * ::= w # wchar_t - * ::= b # bool - * ::= c # char - * ::= a # signed char - * ::= h # unsigned char - * ::= s # short - * ::= t # unsigned short - * ::= i # int - * ::= j # unsigned int - * ::= l # long - * ::= m # unsigned long - * ::= x # long long, __int64 - * ::= y # unsigned long long, __int64 - * ::= n # __int128 - * ::= o # unsigned __int128 - * ::= f # float - * ::= d # double - * ::= e # long double, __float80 - * ::= g # __float128 - * ::= z # ellipsis - * ::= Dd # IEEE 754r decimal floating point (64 bits) - * ::= De # IEEE 754r decimal floating point (128 bits) - * ::= Df # IEEE 754r decimal floating point (32 bits) - * ::= Dh # IEEE 754r half-precision floating point (16 bits) - * ::= Di # char32_t - * ::= Ds # char16_t - * ::= u # vendor extended type - */ -void NameDemanglerPrivate::parseBuiltinType() -{ - FUNC_START(); - - BuiltinTypeNode * const typeNode = allocateNodeAndAddToStack(); - const char next = advance(); - if (next == 'u') { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceName, typeNode); - } else { - PredefinedBuiltinTypeNode * const fixedTypeNode = new PredefinedBuiltinTypeNode; - typeNode->addChild(fixedTypeNode); - - switch (next) { - case 'v': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::VoidType; break; - case 'w': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::WCharType; break; - case 'b': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::BoolType; break; - case 'c': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::PlainCharType; break; - case 'a': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedCharType; break; - case 'h': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedCharType; break; - case 's': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedShortType; break; - case 't': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedShortType; break; - case 'i': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedIntType; break; - case 'j': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedIntType; break; - case 'l': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedLongType; break; - case 'm': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedLongType; break; - case 'x': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedLongLongType; break; - case 'y': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedLongLongType; break; - case 'n': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedInt128Type; break; - case 'o': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedInt128Type; break; - case 'f': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::FloatType; break; - case 'd': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DoubleType; break; - case 'e': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::LongDoubleType; break; - case 'g': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::Float128Type; break; - case 'z': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::EllipsisType; break; - case 'D': - switch (advance()) { - case 'd': - fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType64; - break; - case 'e': - fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType128; - break; - case 'f': - fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType32; - break; - case 'h': - fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType16; break; - case 'i': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::Char32Type; break; - case 's': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::Char16Type; break; - default: throw ParseException(QString::fromLatin1("Invalid built-in type")); - } - break; - default: - DEMANGLER_ASSERT(false); - } - } - - FUNC_END(); -} - -/* ::= F [Y] E */ -void NameDemanglerPrivate::parseFunctionType() -{ - FUNC_START(); - - if (!FunctionTypeNode::mangledRepresentationStartsWith(advance())) - throw ParseException(QString::fromLatin1("Invalid function type")); - - FunctionTypeNode * const node = allocateNodeAndAddToStack(); - - if (peek() == 'Y') { - advance(); - node->m_isExternC = true; - } else { - node->m_isExternC = false; - } - - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(BareFunctionType, node); - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid function type")); - FUNC_END(); -} - -/* ::= + */ -void NameDemanglerPrivate::parseBareFunctionType() -{ - FUNC_START(); - - BareFunctionTypeNode * const node = allocateNodeAndAddToStack(); - - /* - * The following is verbatim from the spec: - * Whether the mangling of a function type includes the return type depends on the context - * and the nature of the function. The rules for deciding whether the return type is included - * are: - * (1) Template functions (names or types) have return types encoded, with the exceptions - * listed below. - * (2) Function types not appearing as part of a function name mangling, e.g. parameters, - * pointer types, etc., have return type encoded, with the exceptions listed below. - * (3) Non-template function names do not have return types encoded. - * The exceptions mentioned in (1) and (2) above, for which the return type is never included, - * are constructors, destructors and conversion operator functions, e.g. operator int. - */ - const EncodingNode * const encodingNode - = dynamic_cast(m_parseStack.at(m_parseStack.count() - 2)); - if (encodingNode) { // Case 1: Function name. - const NameNode * const nameNode = DEMANGLER_CAST(NameNode, CHILD_AT(encodingNode, 0)); - node->m_hasReturnType = nameNode->isTemplate() - && !nameNode->isConstructorOrDestructorOrConversionOperator(); - } else { // Case 2: function type. - // TODO: What do the exceptions look like for this case? - node->m_hasReturnType = true; - } - - do - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - while (TypeNode::mangledRepresentationStartsWith(peek())); - - - FUNC_END(); -} - -/* ::= */ -void NameDemanglerPrivate::parseClassEnumType() -{ - FUNC_START(); - - ClassEnumTypeNode * const node = allocateNodeAndAddToStack(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Name, node); - - FUNC_END(); -} - -/* - * ::= - * ::= - * ::= - */ -void NameDemanglerPrivate::parseUnqualifiedName() -{ - FUNC_START(); - - UnqualifiedNameNode * const node = allocateNodeAndAddToStack(); - - const char next = peek(); - if (OperatorNameNode::mangledRepresentationStartsWith(next)) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(OperatorName, node); - else if (CtorDtorNameNode::mangledRepresentationStartsWith(next)) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CtorDtorName, node); - else if (SourceNameNode::mangledRepresentationStartsWith(next)) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceName, node); - else - throw ParseException(QString::fromLatin1("Invalid unqualified-name")); - - FUNC_END(); -} - -/* - * ::= nw # new - * ::= na # new[] - * ::= dl # delete - * ::= da # delete[] - * ::= ps # + (unary) - * ::= ng # - (unary) - * ::= ad # & (unary) - * ::= de # * (unary) - * ::= co # ~ - * ::= pl # + - * ::= mi # - - * ::= ml # * - * ::= dv # / - * ::= rm # % - * ::= an # & - * ::= or # | - * ::= eo # ^ - * ::= aS # = - * ::= pL # += - * ::= mI # -= - * ::= mL # *= - * ::= dV # /= - * ::= rM # %= - * ::= aN # &= - * ::= oR # |= - * ::= eO # ^= - * ::= ls # << - * ::= rs # >> - * ::= lS # <<= - * ::= rS # >>= - * ::= eq # == - * ::= ne # != - * ::= lt # < - * ::= gt # > - * ::= le # <= - * ::= ge # >= - * ::= nt # ! - * ::= aa # && - * ::= oo # || - * ::= pp # ++ - * ::= mm # -- - * ::= cm # , - * ::= pm # ->* - * ::= pt # -> - * ::= cl # () - * ::= ix # [] - * ::= qu # ? - * ::= st # sizeof (a type) - * ::= sz # sizeof (an expression) - * ::= at # alignof (a type) - * ::= az # alignof (an expression) - * ::= cv # (cast) - * ::= v # vendor extended operator - */ -void NameDemanglerPrivate::parseOperatorName() -{ - FUNC_START(); - - OperatorNameNode * const node = allocateNodeAndAddToStack(); - - if (peek() == 'v') { - node->m_type = OperatorNameNode::VendorType; - advance(); - parseDigit(); - popNodeFromStackAndAddAsChild(node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceName, node); - } else { - const QByteArray id = readAhead(2); - advance(2); - if (id == "cv") { - m_isConversionOperator = true; - node->m_type = OperatorNameNode::CastType; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else if (id == "nw") { - node->m_type = OperatorNameNode::NewType; - } else if (id == "na") { - node->m_type = OperatorNameNode::ArrayNewType; - } else if (id == "dl") { - node->m_type = OperatorNameNode::DeleteType; - } else if (id == "da") { - node->m_type = OperatorNameNode::ArrayDeleteType; - } else if (id == "ps") { - node->m_type = OperatorNameNode::UnaryPlusType; - } else if (id == "ng") { - node->m_type = OperatorNameNode::UnaryMinusType; - } else if (id == "ad") { - node->m_type = OperatorNameNode::UnaryAmpersandType; - } else if (id == "de") { - node->m_type = OperatorNameNode::UnaryStarType; - } else if (id == "co") { - node->m_type = OperatorNameNode::BitwiseNotType; - } else if (id == "pl") { - node->m_type = OperatorNameNode::BinaryPlusType; - } else if (id == "mi") { - node->m_type = OperatorNameNode::BinaryMinusType; - } else if (id == "ml") { - node->m_type = OperatorNameNode::MultType; - } else if (id == "dv") { - node->m_type = OperatorNameNode::DivType; - } else if (id == "rm") { - node->m_type = OperatorNameNode::ModuloType; - } else if (id == "an") { - node->m_type = OperatorNameNode::BitwiseAndType; - } else if (id == "or") { - node->m_type = OperatorNameNode::BitwiseOrType; - } else if (id == "eo") { - node->m_type = OperatorNameNode::XorType; - } else if (id == "aS") { - node->m_type = OperatorNameNode::AssignType; - } else if (id == "pL") { - node->m_type = OperatorNameNode::IncrementAndAssignType; - } else if (id == "mI") { - node->m_type = OperatorNameNode::DecrementAndAssignType; - } else if (id == "mL") { - node->m_type = OperatorNameNode::MultAndAssignType; - } else if (id == "dV") { - node->m_type = OperatorNameNode::DivAndAssignType; - } else if (id == "rM") { - node->m_type = OperatorNameNode::ModuloAndAssignType; - } else if (id == "aN") { - node->m_type = OperatorNameNode::BitwiseAndAndAssignType; - } else if (id == "oR") { - node->m_type = OperatorNameNode::BitwiseOrAndAssignType; - } else if (id == "eO") { - node->m_type = OperatorNameNode::XorAndAssignType; - } else if (id == "ls") { - node->m_type = OperatorNameNode::LeftShiftType; - } else if (id == "rs") { - node->m_type = OperatorNameNode::RightShiftType; - } else if (id == "lS") { - node->m_type = OperatorNameNode::LeftShiftAndAssignType; - } else if (id == "rS") { - node->m_type = OperatorNameNode::RightShiftAndAssignType; - } else if (id == "eq") { - node->m_type = OperatorNameNode::EqualsType; - } else if (id == "ne") { - node->m_type = OperatorNameNode::NotEqualsType; - } else if (id == "lt") { - node->m_type = OperatorNameNode::LessType; - } else if (id == "gt") { - node->m_type = OperatorNameNode::GreaterType; - } else if (id == "le") { - node->m_type = OperatorNameNode::LessEqualType; - } else if (id == "ge") { - node->m_type = OperatorNameNode::GreaterEqualType; - } else if (id == "nt") { - node->m_type = OperatorNameNode::LogicalNotType; - } else if (id == "aa") { - node->m_type = OperatorNameNode::LogicalAndType; - } else if (id == "oo") { - node->m_type = OperatorNameNode::LogicalOrType; - } else if (id == "pp") { - node->m_type = OperatorNameNode::IncrementType; - } else if (id == "mm") { - node->m_type = OperatorNameNode::DecrementType; - } else if (id == "cm") { - node->m_type = OperatorNameNode::CommaType; - } else if (id == "pm") { - node->m_type = OperatorNameNode::ArrowStarType; - } else if (id == "pt") { - node->m_type = OperatorNameNode::ArrowType; - } else if (id == "cl") { - node->m_type = OperatorNameNode::CallType; - } else if (id == "ix") { - node->m_type = OperatorNameNode::IndexType; - } else if (id == "qu") { - node->m_type = OperatorNameNode::TernaryType; - } else if (id == "st") { - node->m_type = OperatorNameNode::SizeofTypeType; - } else if (id == "sz") { - node->m_type = OperatorNameNode::SizeofExprType; - } else if (id == "at") { - node->m_type = OperatorNameNode::AlignofTypeType; - } else if (id == "az") { - node->m_type = OperatorNameNode::AlignofExprType; - } else { - throw ParseException(QString::fromLocal8Bit("Invalid operator encoding '%1'") - .arg(QString::fromLocal8Bit(id))); - } - } - - FUNC_END(); -} - -/* - * ::= A _ - * ::= A [] _ - */ -void NameDemanglerPrivate::parseArrayType() -{ - FUNC_START(); - - if (!ArrayTypeNode::mangledRepresentationStartsWith(advance())) - throw ParseException(QString::fromLatin1("Invalid array-type")); - - ArrayTypeNode * const node = allocateNodeAndAddToStack(); - - const char next = peek(); - if (NonNegativeNumberNode::mangledRepresentationStartsWith(next)) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NonNegativeNumber, node); - else if (ExpressionNode::mangledRepresentationStartsWith(next)) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Expression, node); - - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid array-type")); - - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - - FUNC_END(); -} - -/* ::= M */ -void NameDemanglerPrivate::parsePointerToMemberType() -{ - FUNC_START(); - - if (!PointerToMemberTypeNode::mangledRepresentationStartsWith(advance())) - throw ParseException(QString::fromLatin1("Invalid pointer-to-member-type")); - - PointerToMemberTypeNode * const node = allocateNodeAndAddToStack(); - - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); // Class type. - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); // Member type. - - FUNC_END(); -} - -/* - * ::= S _ # 36-bit number - * ::= S_ - * ::= St # ::std:: - * ::= Sa # ::std::allocator - * ::= Sb # ::std::basic_string - * ::= Ss # ::std::basic_string < char, - * ::std::char_traits, - * ::std::allocator > - * ::= Si # ::std::basic_istream > - * ::= So # ::std::basic_ostream > - * ::= Sd # ::std::basic_iostream > - */ -void NameDemanglerPrivate::parseSubstitution() -{ - FUNC_START(); - - if (!SubstitutionNode::mangledRepresentationStartsWith(advance())) - throw ParseException(QString::fromLatin1("Invalid substitution")); - - SubstitutionNode * const node = allocateNodeAndAddToStack(); - - if (NonNegativeNumberNode::mangledRepresentationStartsWith(peek(), 36)) { - const int substIndex = getNonNegativeNumber(36) + 1; - if (substIndex >= m_substitutions.size()) { - throw ParseException(QString::fromLatin1("Invalid substitution: substitution %1 " - "was requested, but there are only %2"). - arg(substIndex + 1).arg(m_substitutions.size())); - } - node->m_type = SubstitutionNode::ActualSubstitutionType; - node->m_substValue = m_substitutions.at(substIndex); - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid substitution")); - } else { - switch (advance()) { - case '_': - if (m_substitutions.isEmpty()) - throw ParseException(QString::fromLatin1("Invalid substitution: " - "There are no substitutions")); - node->m_type = SubstitutionNode::ActualSubstitutionType; - node->m_substValue = m_substitutions.first(); - break; - case 't': - node->m_type = SubstitutionNode::StdType; - break; - case 'a': - node->m_type = SubstitutionNode::StdAllocType; - break; - case 'b': - node->m_type = SubstitutionNode::StdBasicStringType; - break; - case 's': - node->m_type = SubstitutionNode::FullStdBasicStringType; - break; - case 'i': - node->m_type = SubstitutionNode::StdBasicIStreamType; - break; - case 'o': - node->m_type = SubstitutionNode::StdBasicOStreamType; - break; - case 'd': - node->m_type = SubstitutionNode::StdBasicIoStreamType; - break; - default: - throw ParseException(QString::fromLatin1("Invalid substitution")); - } - } - - FUNC_END(); -} - -/* - * ::= TV # virtual table - * ::= TT # VTT structure (construction vtable index) - * ::= TI # typeinfo structure - * ::= TS # typeinfo name (null-terminated byte string) - * ::= GV # Guard variable for one-time initialization - * ::= T - * ::= Tc - * # base is the nominal target function of thunk - * # first call-offset is 'this' adjustment - * # second call-offset is result adjustment - */ -void NameDemanglerPrivate::parseSpecialName() -{ - FUNC_START(); - - SpecialNameNode * const node = allocateNodeAndAddToStack(); - - QByteArray str = readAhead(2); - if (str == "TV") { - node->m_type = SpecialNameNode::VirtualTableType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else if (str == "TT") { - node->m_type = SpecialNameNode::VttStructType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else if (str == "TI") { - node->m_type = SpecialNameNode::TypeInfoType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else if (str == "TS") { - node->m_type = SpecialNameNode::TypeInfoNameType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Type, node); - } else if (str == "GV") { - node->m_type = SpecialNameNode::GuardVarType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Name, node); - } else if (str == "Tc") { - node->m_type = SpecialNameNode::DoubleCallOffsetType; - advance(2); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CallOffset, node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CallOffset, node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Encoding, node); - } else if (advance() == 'T') { - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CallOffset, node); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Encoding, node); - } else { - throw ParseException(QString::fromLatin1("Invalid special-name")); - } - - FUNC_END(); -} - -/* - * ::= - * ::= St # ::std:: - */ -void NameDemanglerPrivate::parseUnscopedName() -{ - FUNC_START(); - - UnscopedNameNode * const node = allocateNodeAndAddToStack(); - - if (readAhead(2) == "St") { - node->m_inStdNamespace = true; - advance(2); - } else { - node->m_inStdNamespace = false; - } - - if (!UnqualifiedNameNode::mangledRepresentationStartsWith(peek())) - throw ParseException(QString::fromLatin1("Invalid unscoped-name")); - - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedName, node); - - FUNC_END(); -} - - -/* - * := Z E [] - * := Z E s [] - * - * Note that can start with 's', so we need to do read-ahead. - */ -void NameDemanglerPrivate::parseLocalName() -{ - FUNC_START(); - - if (!LocalNameNode::mangledRepresentationStartsWith(advance())) - throw ParseException(QString::fromLatin1("Invalid local-name")); - - LocalNameNode * const node = allocateNodeAndAddToStack(); - - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Encoding, node); - - if (advance() != 'E') - throw ParseException(QString::fromLatin1("Invalid local-name")); - - QByteArray str = readAhead(2); - char next = peek(); - if (str == "sp" || str == "sr" || str == "st" || str == "sz" || str == "sZ" - || (next != 's' && NameNode::mangledRepresentationStartsWith(next))) { - node->m_isStringLiteral = false; - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Name, node); - } else if (next == 's') { - node->m_isStringLiteral = true; - advance(); - } else { - throw ParseException(QString::fromLatin1("Invalid local-name")); - } - if (DiscriminatorNode::mangledRepresentationStartsWith(peek())) - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Discriminator, node); - - FUNC_END(); -} - -/* := _ */ -void NameDemanglerPrivate::parseDiscriminator() -{ - FUNC_START(); - - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid discriminator")); - - DiscriminatorNode * const node = allocateNodeAndAddToStack(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NonNegativeNumber, node); - - FUNC_END(); -} - -/* - * ::= C1 # complete object constructor - * ::= C2 # base object constructor - * ::= C3 # complete object allocating constructor - * ::= D0 # deleting destructor - * ::= D1 # complete object destructor - * ::= D2 # base object destructor - */ -void NameDemanglerPrivate::parseCtorDtorName() -{ - FUNC_START(); - - CtorDtorNameNode * const node = allocateNodeAndAddToStack(); - - switch (advance()) { - case 'C': - switch (advance()) { - case '1': case '2': case '3': node->m_isDestructor = false; break; - default: throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); - } - break; - case 'D': - switch (advance()) { - case '0': case '1': case '2': node->m_isDestructor = true; break; - default: throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); - } - break; - default: - throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); - } - - node->m_representation = m_substitutions.last(); - - FUNC_END(); -} - -const QByteArray NameDemanglerPrivate::getIdentifier(int len) -{ - FUNC_START(); - - const QByteArray id = m_mangledName.mid(m_pos, len); - advance(len); - - FUNC_END(); - return id; -} - -/* - * ::= h _ - * ::= v _ - */ -void NameDemanglerPrivate::parseCallOffset() -{ - FUNC_START(); - - CallOffsetNode * const node = allocateNodeAndAddToStack(); - switch (advance()) { - case 'h': PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NvOffset, node); break; - case 'v': PARSE_RULE_AND_ADD_RESULT_AS_CHILD(VOffset, node); break; - default: DEMANGLER_ASSERT(false); - } - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid call-offset")); - - FUNC_END(); -} - -/* ::= # non-virtual base override */ -void NameDemanglerPrivate::parseNvOffset() -{ - FUNC_START(); - - NvOffsetNode * const node = allocateNodeAndAddToStack(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Number, node); - - FUNC_END(); -} - -/* - * ::= _ - * # virtual base override, with vcall offset - */ -void NameDemanglerPrivate::parseVOffset() -{ - FUNC_START(); - - VOffsetNode * const node = allocateNodeAndAddToStack(); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Number, node); - if (advance() != '_') - throw ParseException(QString::fromLatin1("Invalid v-offset")); - PARSE_RULE_AND_ADD_RESULT_AS_CHILD(Number, node); - - FUNC_END(); -} - -int NameDemanglerPrivate::getNonNegativeNumber(int base) -{ - parseNonNegativeNumber(base); - NonNegativeNumberNode * const numberNode - = DEMANGLER_CAST(NonNegativeNumberNode, m_parseStack.pop()); - const int value = static_cast(numberNode->m_number); - delete numberNode; - return value; -} - -void NameDemanglerPrivate::parseDigit() -{ - FUNC_START(); - - NonNegativeNumberNode * const node = allocateNodeAndAddToStack(); - - const int digit = advance(); - if (!std::isdigit(digit)) - throw ParseException(QString::fromLatin1("Invalid digit")); - node->m_number = digit - 0x30; - - FUNC_END(); -} - -char NameDemanglerPrivate::peek(int ahead) -{ - Q_ASSERT(m_pos >= 0); - - if (m_pos + ahead < m_mangledName.size()) - return m_mangledName[m_pos + ahead]; - return eoi; -} - -char NameDemanglerPrivate::advance(int steps) -{ - Q_ASSERT(steps > 0); - if (m_pos + steps > m_mangledName.size()) - throw ParseException(QLatin1String("Unexpected end of input")); - - const char c = m_mangledName[m_pos]; - m_pos += steps; - return c; -} - -const QByteArray NameDemanglerPrivate::readAhead(int charCount) -{ - QByteArray str; - if (m_pos + charCount < m_mangledName.size()) - str = m_mangledName.mid(m_pos, charCount); - else - str.fill(eoi, charCount); - return str; -} - -void NameDemanglerPrivate::addSubstitution(const ParseTreeNode *node) -{ - const QByteArray symbol = node->toByteArray(); - if (!symbol.isEmpty() && !m_substitutions.contains(symbol)) - m_substitutions.append(symbol); + qDeleteAll(m_parseState.m_parseStack); + m_parseState.m_parseStack.clear(); + m_parseState.m_substitutions.clear(); + m_parseState.clearTemplateParams(); + return success; } diff --git a/src/plugins/debugger/namedemangler/namedemangler.pri b/src/plugins/debugger/namedemangler/namedemangler.pri index 9f5965a26ddfadea35b1c9ca533760590ca4fd55..92083e82148b4e4313359504472216077726b9ad 100644 --- a/src/plugins/debugger/namedemangler/namedemangler.pri +++ b/src/plugins/debugger/namedemangler/namedemangler.pri @@ -1,8 +1,10 @@ HEADERS += \ $$PWD/namedemangler.h \ $$PWD/parsetreenodes.h \ - namedemangler/demanglerexceptions.h + $$PWD/demanglerexceptions.h \ + $$PWD/globalparsestate.h SOURCES += \ $$PWD/namedemangler.cpp \ - $$PWD/parsetreenodes.cpp + $$PWD/parsetreenodes.cpp \ + $$PWD/globalparsestate.cpp diff --git a/src/plugins/debugger/namedemangler/parsetreenodes.cpp b/src/plugins/debugger/namedemangler/parsetreenodes.cpp index 371a99f90864b7f2cb9876a9a8e14d7577947cb6..6855f1969907bcf8a6f7a0dd37c80faf62f1fb62 100644 --- a/src/plugins/debugger/namedemangler/parsetreenodes.cpp +++ b/src/plugins/debugger/namedemangler/parsetreenodes.cpp @@ -33,14 +33,38 @@ #include "demanglerexceptions.h" +#include #include +#define PEEK() (parseState()->peek()) +#define ADVANCE() (parseState()->advance()) + +#define PARSE_RULE_AND_ADD_RESULT_AS_CHILD(nodeType) \ + do { \ + parseRule(parseState()); \ + DEMANGLER_ASSERT(parseState()->stackElementCount() > 0); \ + DEMANGLER_ASSERT(dynamic_cast(parseState()->stackTop())); \ + addChild(parseState()->popFromStack()); \ + } while (0) + +#define CHILD_AT(obj, index) obj->childAt(index, Q_FUNC_INFO, __FILE__, __LINE__) #define MY_CHILD_AT(index) CHILD_AT(this, index) -#define CHILD_TO_BYTEARRAY(index) CHILD_AT(this, index)->toByteArray() +#define CHILD_TO_BYTEARRAY(index) MY_CHILD_AT(index)->toByteArray() namespace Debugger { namespace Internal { +template static int getNonNegativeNumber(GlobalParseState *parseState) +{ + ParseTreeNode::parseRule >(parseState); + NonNegativeNumberNode * const numberNode + = DEMANGLER_CAST(NonNegativeNumberNode, parseState->popFromStack()); + const int value = static_cast(numberNode->number()); + delete numberNode; + return value; +} + + ParseTreeNode::~ParseTreeNode() { qDeleteAll(m_children); @@ -68,6 +92,27 @@ bool ArrayTypeNode::mangledRepresentationStartsWith(char c) return c == 'A'; } +/* + * ::= A _ + * ::= A [] _ + */ +void ArrayTypeNode::parse() +{ + if (!ArrayTypeNode::mangledRepresentationStartsWith(ADVANCE())) + throw ParseException(QString::fromLatin1("Invalid array-type")); + + const char next = PEEK(); + if (NonNegativeNumberNode<10>::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NonNegativeNumberNode<10>); + else if (ExpressionNode::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExpressionNode); + + if (ADVANCE() != '_') + throw ParseException(QString::fromLatin1("Invalid array-type")); + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); +} + QByteArray ArrayTypeNode::toByteArray() const { return CHILD_TO_BYTEARRAY(1) + '[' + CHILD_TO_BYTEARRAY(0) + ']'; @@ -79,6 +124,38 @@ bool BareFunctionTypeNode::mangledRepresentationStartsWith(char c) return TypeNode::mangledRepresentationStartsWith(c); } +/* ::= + */ +void BareFunctionTypeNode::parse() +{ + /* + * The following is verbatim from the spec: + * Whether the mangling of a function type includes the return type depends on the context + * and the nature of the function. The rules for deciding whether the return type is included + * are: + * (1) Template functions (names or types) have return types encoded, with the exceptions + * listed below. + * (2) Function types not appearing as part of a function name mangling, e.g. parameters, + * pointer types, etc., have return type encoded, with the exceptions listed below. + * (3) Non-template function names do not have return types encoded. + * The exceptions mentioned in (1) and (2) above, for which the return type is never included, + * are constructors, destructors and conversion operator functions, e.g. operator int. + */ + const EncodingNode * const encodingNode = dynamic_cast(parseState() + ->stackElementAt(parseState()->stackElementCount() - 2)); + if (encodingNode) { // Case 1: Function name. + const NameNode * const nameNode = DEMANGLER_CAST(NameNode, CHILD_AT(encodingNode, 0)); + m_hasReturnType = nameNode->isTemplate() + && !nameNode->isConstructorOrDestructorOrConversionOperator(); + } else { // Case 2: function type. + // TODO: What do the exceptions look like for this case? + m_hasReturnType = true; + } + + do + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + while (TypeNode::mangledRepresentationStartsWith(PEEK())); +} + QByteArray BareFunctionTypeNode::toByteArray() const { // This is only the parameter list, including parentheses. Where the return type is placed @@ -100,6 +177,93 @@ bool BuiltinTypeNode::mangledRepresentationStartsWith(char c) return strchr("vwbcahstijlmxynofgedzDu", c); } +/* + * ::= v # void + * ::= w # wchar_t + * ::= b # bool + * ::= c # char + * ::= a # signed char + * ::= h # unsigned char + * ::= s # short + * ::= t # unsigned short + * ::= i # int + * ::= j # unsigned int + * ::= l # long + * ::= m # unsigned long + * ::= x # long long, __int64 + * ::= y # unsigned long long, __int64 + * ::= n # __int128 + * ::= o # unsigned __int128 + * ::= f # float + * ::= d # double + * ::= e # long double, __float80 + * ::= g # __float128 + * ::= z # ellipsis + * ::= Dd # IEEE 754r decimal floating point (64 bits) + * ::= De # IEEE 754r decimal floating point (128 bits) + * ::= Df # IEEE 754r decimal floating point (32 bits) + * ::= Dh # IEEE 754r half-precision floating point (16 bits) + * ::= Di # char32_t + * ::= Ds # char16_t + * ::= u # vendor extended type + */ +void BuiltinTypeNode::parse() +{ + const char next = ADVANCE(); + if (next == 'u') { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceNameNode); + } else { + // TODO: This seems silly. Why not integrate the type into this node and have + // an additional one "VendorType" that indicates that there's a child node? + PredefinedBuiltinTypeNode * const fixedTypeNode = new PredefinedBuiltinTypeNode; + addChild(fixedTypeNode); + + switch (next) { + case 'v': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::VoidType; break; + case 'w': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::WCharType; break; + case 'b': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::BoolType; break; + case 'c': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::PlainCharType; break; + case 'a': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedCharType; break; + case 'h': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedCharType; break; + case 's': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedShortType; break; + case 't': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedShortType; break; + case 'i': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedIntType; break; + case 'j': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedIntType; break; + case 'l': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedLongType; break; + case 'm': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedLongType; break; + case 'x': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedLongLongType; break; + case 'y': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedLongLongType; break; + case 'n': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::SignedInt128Type; break; + case 'o': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::UnsignedInt128Type; break; + case 'f': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::FloatType; break; + case 'd': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DoubleType; break; + case 'e': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::LongDoubleType; break; + case 'g': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::Float128Type; break; + case 'z': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::EllipsisType; break; + case 'D': + switch (ADVANCE()) { + case 'd': + fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType64; + break; + case 'e': + fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType128; + break; + case 'f': + fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType32; + break; + case 'h': + fixedTypeNode->m_type = PredefinedBuiltinTypeNode::DecimalFloatingType16; break; + case 'i': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::Char32Type; break; + case 's': fixedTypeNode->m_type = PredefinedBuiltinTypeNode::Char16Type; break; + default: throw ParseException(QString::fromLatin1("Invalid built-in type")); + } + break; + default: + DEMANGLER_ASSERT(false); + } + } +} + QByteArray BuiltinTypeNode::toByteArray() const { return CHILD_TO_BYTEARRAY(0); @@ -111,6 +275,21 @@ bool CallOffsetNode::mangledRepresentationStartsWith(char c) return c == 'h' || c == 'v'; } +/* + * ::= h _ + * ::= v _ + */ +void CallOffsetNode::parse() +{ + switch (ADVANCE()) { + case 'h': PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NvOffsetNode); break; + case 'v': PARSE_RULE_AND_ADD_RESULT_AS_CHILD(VOffsetNode); break; + default: DEMANGLER_ASSERT(false); + } + if (ADVANCE() != '_') + throw ParseException(QString::fromLatin1("Invalid call-offset")); +} + QByteArray CallOffsetNode::toByteArray() const { return CHILD_TO_BYTEARRAY(0); @@ -124,10 +303,16 @@ bool ClassEnumTypeNode::mangledRepresentationStartsWith(char c) * the grammar claims. * firstSetClassEnumType = firstSetName; */ - return NonNegativeNumberNode::mangledRepresentationStartsWith(c) + return NonNegativeNumberNode<10>::mangledRepresentationStartsWith(c) || c == 'N' || c == 'D' || c == 'Z'; } +/* ::= */ +void ClassEnumTypeNode::parse() +{ + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NameNode); +} + QByteArray ClassEnumTypeNode::toByteArray() const { return CHILD_TO_BYTEARRAY(0); @@ -139,6 +324,14 @@ bool DiscriminatorNode::mangledRepresentationStartsWith(char c) return c == '_'; } +/* := _ */ +void DiscriminatorNode::parse() +{ + if (ADVANCE() != '_') + throw ParseException(QString::fromLatin1("Invalid discriminator")); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NonNegativeNumberNode<10>); +} + QByteArray DiscriminatorNode::toByteArray() const { return CHILD_TO_BYTEARRAY(0); @@ -150,6 +343,36 @@ bool CtorDtorNameNode::mangledRepresentationStartsWith(char c) return c == 'C' || c == 'D'; } +/* + * ::= C1 # complete object constructor + * ::= C2 # base object constructor + * ::= C3 # complete object allocating constructor + * ::= D0 # deleting destructor + * ::= D1 # complete object destructor + * ::= D2 # base object destructor + */ +void CtorDtorNameNode::parse() +{ + switch (ADVANCE()) { + case 'C': + switch (ADVANCE()) { + case '1': case '2': case '3': m_isDestructor = false; break; + default: throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); + } + break; + case 'D': + switch (ADVANCE()) { + case '0': case '1': case '2': m_isDestructor = true; break; + default: throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); + } + break; + default: + throw ParseException(QString::fromLatin1("Invalid ctor-dtor-name")); + } + + m_representation = parseState()->substitutionAt(parseState()->substitutionCount() - 1); +} + QByteArray CtorDtorNameNode::toByteArray() const { QByteArray repr = m_representation; @@ -170,6 +393,29 @@ bool CvQualifiersNode::mangledRepresentationStartsWith(char c) return c == 'K' || c == 'V' || c == 'r'; } +/* ::= [r] [V] [K] # restrict (C99), volatile, const */ +void CvQualifiersNode::parse() +{ + m_hasConst = false; + m_hasVolatile = false; + + while (true) { + if (PEEK() == 'V') { + if (hasQualifiers()) + throw ParseException(QLatin1String("Invalid qualifiers: unexpected 'volatile'")); + m_hasVolatile = true; + ADVANCE(); + } else if (PEEK() == 'K') { + if (m_hasConst) + throw ParseException(QLatin1String("Invalid qualifiers: 'const' appears twice")); + m_hasConst = true; + ADVANCE(); + } else { + break; + } + } +} + QByteArray CvQualifiersNode::toByteArray() const { QByteArray repr; @@ -190,6 +436,28 @@ bool EncodingNode::mangledRepresentationStartsWith(char c) || SpecialNameNode::mangledRepresentationStartsWith(c); } +/* + * ::= + * ::= + * ::= + */ +void EncodingNode::parse() +{ + const char next = PEEK(); + if (NameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NameNode); + if (BareFunctionTypeNode::mangledRepresentationStartsWith(PEEK())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(BareFunctionTypeNode); + parseState()->addSubstitution(this); + parseState()->clearTemplateParams(); + parseState()->setIsConversionOperator(false); + } else if (SpecialNameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SpecialNameNode); + } else { + throw ParseException(QString::fromLatin1("Invalid encoding")); + } +} + QByteArray EncodingNode::toByteArray() const { if (childCount() == 1) @@ -204,7 +472,7 @@ QByteArray EncodingNode::toByteArray() const QByteArray repr; const BareFunctionTypeNode * const funcNode = DEMANGLER_CAST(BareFunctionTypeNode, MY_CHILD_AT(1)); - if (funcNode->m_hasReturnType) + if (funcNode->hasReturnType()) repr = CHILD_AT(funcNode, 0)->toByteArray() + ' '; if (cvQualifiersNode) { return repr + CHILD_AT(nestedNameNode, 1)->toByteArray() + funcNode->toByteArray() + ' ' @@ -223,6 +491,143 @@ bool ExpressionNode::mangledRepresentationStartsWith(char c) || c == 'c' || c == 's' || c == 'a'; } +/* + * ::= + * ::= + * ::= + * ::= cl * E # call + * ::= cv expression # conversion with one argument + * ::= cv _ * E # conversion with a different number of arguments + * ::= st # sizeof (a type) + * ::= at # alignof (a type) + * ::= + * ::= + * ::= sr # dependent name + * ::= sr # dependent template-id + * ::= sZ # size of a parameter pack + * ::= + * + * Note that the grammar is missing the definition of . This + * has not been a problem in the test cases so far. + * TODO: is now defined and should therefore be supported + */ +void ExpressionNode::parse() +{ + m_type = OtherType; + + /* + * Some of the terminals in the productions of + * also appear in the productions of . We assume the direct + * productions to have higher precedence and check them first to prevent + * them being parsed by parseOperatorName(). + */ + QByteArray str = parseState()->readAhead(2); + if (str == "cl") { + parseState()->advance(2); + while (ExpressionNode::mangledRepresentationStartsWith(PEEK())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExpressionNode); + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid expression")); + } else if (str == "cv") { + m_type = ConversionType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + if (PEEK() == '_') { + ADVANCE(); + while (ExpressionNode::mangledRepresentationStartsWith(PEEK())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExpressionNode); + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid expression")); + } else { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExpressionNode); + } + } else if (str == "st") { + m_type = SizeofType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else if (str == "at") { + m_type = AlignofType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else if (str == "sr") { // TODO: Which syntax to use here? + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedNameNode); + if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); + } else if (str == "sZ") { + m_type = ParameterPackSizeType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParamNode); + } else { + const char next = PEEK(); + if (OperatorNameNode::mangledRepresentationStartsWith(next)) { + m_type = OperatorType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(OperatorNameNode); + OperatorNameNode * const opNode + = DEMANGLER_CAST(OperatorNameNode, MY_CHILD_AT(childCount() - 1)); + + int expressionCount; + switch (opNode->type()) { + case OperatorNameNode::TernaryType: + expressionCount = 3; + break; + case OperatorNameNode::ArrayNewType: + case OperatorNameNode::BinaryPlusType: + case OperatorNameNode::BinaryMinusType: + case OperatorNameNode::MultType: + case OperatorNameNode::DivType: + case OperatorNameNode::ModuloType: + case OperatorNameNode::BitwiseAndType: + case OperatorNameNode::BitwiseOrType: + case OperatorNameNode::XorType: + case OperatorNameNode::AssignType: + case OperatorNameNode::IncrementAndAssignType: + case OperatorNameNode::DecrementAndAssignType: + case OperatorNameNode::MultAndAssignType: + case OperatorNameNode::DivAndAssignType: + case OperatorNameNode::ModuloAndAssignType: + case OperatorNameNode::BitwiseAndAndAssignType: + case OperatorNameNode::BitwiseOrAndAssignType: + case OperatorNameNode::XorAndAssignType: + case OperatorNameNode::LeftShiftType: + case OperatorNameNode::RightShiftType: + case OperatorNameNode::LeftShiftAndAssignType: + case OperatorNameNode::RightShiftAndAssignType: + case OperatorNameNode::EqualsType: + case OperatorNameNode::NotEqualsType: + case OperatorNameNode::LessType: + case OperatorNameNode::GreaterType: + case OperatorNameNode::LessEqualType: + case OperatorNameNode::GreaterEqualType: + case OperatorNameNode::LogicalAndType: + case OperatorNameNode::LogicalOrType: + case OperatorNameNode::CommaType: + case OperatorNameNode::ArrowStarType: + case OperatorNameNode::ArrowType: + case OperatorNameNode::IndexType: + expressionCount = 2; + break; + default: + expressionCount = 1; + } + + for (int i = 0; i < expressionCount; ++i) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExpressionNode); + } else if (TemplateParamNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParamNode); + +#if 0 + } else if (FunctionParamNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(FunctionParamNode); +#endif + } else if (ExprPrimaryNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExprPrimaryNode); + } else { + throw ParseException(QString::fromLatin1("Invalid expression")); + } + } +} + QByteArray ExpressionNode::toByteArray() const { QByteArray repr; @@ -244,7 +649,7 @@ QByteArray ExpressionNode::toByteArray() const repr = CHILD_TO_BYTEARRAY(0); // TODO: What does this look like? case OperatorType: { const OperatorNameNode * const opNode = DEMANGLER_CAST(OperatorNameNode, MY_CHILD_AT(0)); - switch (opNode->m_type) { + switch (opNode->type()) { case OperatorNameNode::CallType: repr = CHILD_TO_BYTEARRAY(1) + opNode->toByteArray(); break; @@ -318,6 +723,187 @@ bool OperatorNameNode::mangledRepresentationStartsWith(char c) return strchr("ndpacmroelgiqsv", c); } +/* + * ::= nw # new + * ::= na # new[] + * ::= dl # delete + * ::= da # delete[] + * ::= ps # + (unary) + * ::= ng # - (unary) + * ::= ad # & (unary) + * ::= de # * (unary) + * ::= co # ~ + * ::= pl # + + * ::= mi # - + * ::= ml # * + * ::= dv # / + * ::= rm # % + * ::= an # & + * ::= or # | + * ::= eo # ^ + * ::= aS # = + * ::= pL # += + * ::= mI # -= + * ::= mL # *= + * ::= dV # /= + * ::= rM # %= + * ::= aN # &= + * ::= oR # |= + * ::= eO # ^= + * ::= ls # << + * ::= rs # >> + * ::= lS # <<= + * ::= rS # >>= + * ::= eq # == + * ::= ne # != + * ::= lt # < + * ::= gt # > + * ::= le # <= + * ::= ge # >= + * ::= nt # ! + * ::= aa # && + * ::= oo # || + * ::= pp # ++ + * ::= mm # -- + * ::= cm # , + * ::= pm # ->* + * ::= pt # -> + * ::= cl # () + * ::= ix # [] + * ::= qu # ? + * ::= st # sizeof (a type) + * ::= sz # sizeof (an expression) + * ::= at # alignof (a type) + * ::= az # alignof (an expression) + * ::= cv # (cast) + * ::= v # vendor extended operator + */ +void OperatorNameNode::parse() +{ + if (PEEK() == 'v') { + m_type = VendorType; + ADVANCE(); + const int digit = ADVANCE(); + if (!std::isdigit(digit)) + throw ParseException(QString::fromLatin1("Invalid digit")); + // Throw away digit for now; we don't know what to do with it anyway. + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceNameNode); + } else { + const QByteArray id = parseState()->readAhead(2); + parseState()->advance(2); + if (id == "cv") { + parseState()->setIsConversionOperator(true); + m_type = CastType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else if (id == "nw") { + m_type = NewType; + } else if (id == "na") { + m_type = ArrayNewType; + } else if (id == "dl") { + m_type = DeleteType; + } else if (id == "da") { + m_type = ArrayDeleteType; + } else if (id == "ps") { + m_type = UnaryPlusType; + } else if (id == "ng") { + m_type = UnaryMinusType; + } else if (id == "ad") { + m_type = UnaryAmpersandType; + } else if (id == "de") { + m_type = UnaryStarType; + } else if (id == "co") { + m_type = BitwiseNotType; + } else if (id == "pl") { + m_type = BinaryPlusType; + } else if (id == "mi") { + m_type = BinaryMinusType; + } else if (id == "ml") { + m_type = MultType; + } else if (id == "dv") { + m_type = DivType; + } else if (id == "rm") { + m_type = ModuloType; + } else if (id == "an") { + m_type = BitwiseAndType; + } else if (id == "or") { + m_type = BitwiseOrType; + } else if (id == "eo") { + m_type = XorType; + } else if (id == "aS") { + m_type = AssignType; + } else if (id == "pL") { + m_type = IncrementAndAssignType; + } else if (id == "mI") { + m_type = DecrementAndAssignType; + } else if (id == "mL") { + m_type = MultAndAssignType; + } else if (id == "dV") { + m_type = DivAndAssignType; + } else if (id == "rM") { + m_type = ModuloAndAssignType; + } else if (id == "aN") { + m_type = BitwiseAndAndAssignType; + } else if (id == "oR") { + m_type = BitwiseOrAndAssignType; + } else if (id == "eO") { + m_type = XorAndAssignType; + } else if (id == "ls") { + m_type = LeftShiftType; + } else if (id == "rs") { + m_type = RightShiftType; + } else if (id == "lS") { + m_type = LeftShiftAndAssignType; + } else if (id == "rS") { + m_type = RightShiftAndAssignType; + } else if (id == "eq") { + m_type = EqualsType; + } else if (id == "ne") { + m_type = NotEqualsType; + } else if (id == "lt") { + m_type = LessType; + } else if (id == "gt") { + m_type = GreaterType; + } else if (id == "le") { + m_type = LessEqualType; + } else if (id == "ge") { + m_type = GreaterEqualType; + } else if (id == "nt") { + m_type = LogicalNotType; + } else if (id == "aa") { + m_type = LogicalAndType; + } else if (id == "oo") { + m_type = LogicalOrType; + } else if (id == "pp") { + m_type = IncrementType; + } else if (id == "mm") { + m_type = DecrementType; + } else if (id == "cm") { + m_type = CommaType; + } else if (id == "pm") { + m_type = ArrowStarType; + } else if (id == "pt") { + m_type = ArrowType; + } else if (id == "cl") { + m_type = CallType; + } else if (id == "ix") { + m_type = IndexType; + } else if (id == "qu") { + m_type = TernaryType; + } else if (id == "st") { + m_type = SizeofTypeType; + } else if (id == "sz") { + m_type = SizeofExprType; + } else if (id == "at") { + m_type = AlignofTypeType; + } else if (id == "az") { + m_type = AlignofExprType; + } else { + throw ParseException(QString::fromLocal8Bit("Invalid operator encoding '%1'") + .arg(QString::fromLocal8Bit(id))); + } + } +} + QByteArray OperatorNameNode::toByteArray() const { switch (m_type) { @@ -417,6 +1003,51 @@ bool ExprPrimaryNode::mangledRepresentationStartsWith(char c) return c == 'L'; } +/* + * ::= L E # integer literal + * ::= L E # floating literal + * ::= L E # external name + */ + // TODO: This has been updated in the spec. Needs to be adapted. (nullptr etc.) +void ExprPrimaryNode::parse() +{ + if (!ExprPrimaryNode::mangledRepresentationStartsWith(ADVANCE())) + throw ParseException(QString::fromLatin1("Invalid primary expression")); + const char next = PEEK(); + if (TypeNode::mangledRepresentationStartsWith(next)) { + const ParseTreeNode * const topLevelTypeNode = parseRule(parseState()); + BuiltinTypeNode * const typeNode = topLevelTypeNode->childCount() == 0 + ? 0 : dynamic_cast(CHILD_AT(topLevelTypeNode, 0)); + if (!typeNode) + throw ParseException(QLatin1String("Invalid type in expr-primary")); + PredefinedBuiltinTypeNode * const predefTypeNode + = dynamic_cast(CHILD_AT(typeNode, 0)); + if (!predefTypeNode) + throw ParseException(QLatin1String("Invalid type in expr-primary")); + + // TODO: Of which type can a literal actually be? + switch (predefTypeNode->m_type) { + case PredefinedBuiltinTypeNode::SignedIntType: + case PredefinedBuiltinTypeNode::UnsignedIntType: + case PredefinedBuiltinTypeNode::UnsignedLongType: + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NumberNode); + break; + case PredefinedBuiltinTypeNode::FloatType: case PredefinedBuiltinTypeNode::DoubleType: + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(FloatValueNode); + break; + default: + throw ParseException(QString::fromLatin1("Invalid type in expr-primary")); + } + delete parseState()->popFromStack(); // No need to keep the type node in the tree. + } else if (MangledNameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(MangledNameNode); + } else { + throw ParseException(QString::fromLatin1("Invalid expr-primary")); + } + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid expr-primary")); +} + QByteArray ExprPrimaryNode::toByteArray() const { return CHILD_TO_BYTEARRAY(0); @@ -427,6 +1058,24 @@ bool FunctionTypeNode::mangledRepresentationStartsWith(char c) return c == 'F'; } +/* ::= F [Y] E */ +void FunctionTypeNode::parse() +{ + if (!mangledRepresentationStartsWith(ADVANCE())) + throw ParseException(QString::fromLatin1("Invalid function type")); + + if (PEEK() == 'Y') { + ADVANCE(); + m_isExternC = true; + } else { + m_isExternC = false; + } + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(BareFunctionTypeNode); + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid function type")); +} + QByteArray FunctionTypeNode::toByteArray() const { return QByteArray(); // Not enough knowledge here to generate a string representation. @@ -438,6 +1087,38 @@ bool LocalNameNode::mangledRepresentationStartsWith(char c) return c == 'Z'; } +/* + * := Z E [] + * := Z E s [] + * + * Note that can start with 's', so we need to do read-ahead. + */ +void LocalNameNode::parse() +{ + if (!mangledRepresentationStartsWith(ADVANCE())) + throw ParseException(QString::fromLatin1("Invalid local-name")); + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(EncodingNode); + + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid local-name")); + + QByteArray str = parseState()->readAhead(2); + char next = PEEK(); + if (str == "sp" || str == "sr" || str == "st" || str == "sz" || str == "sZ" + || (next != 's' && NameNode::mangledRepresentationStartsWith(next))) { + m_isStringLiteral = false; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NameNode); + } else if (next == 's') { + m_isStringLiteral = true; + ADVANCE(); + } else { + throw ParseException(QString::fromLatin1("Invalid local-name")); + } + if (DiscriminatorNode::mangledRepresentationStartsWith(PEEK())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(DiscriminatorNode); +} + QByteArray LocalNameNode::toByteArray() const { QByteArray name; @@ -463,6 +1144,18 @@ bool MangledNameNode::mangledRepresentationStartsWith(char c) return c == '_'; } +/* + * Grammar: http://www.codesourcery.com/public/cxx-abi/abi.html#mangling + * The grammar as given there is not LL(k), so a number of transformations + * were necessary, which we will document at the respective parsing function. + * ::= _Z + */ +void MangledNameNode::parse() +{ + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(EncodingNode); +} + QByteArray MangledNameNode::toByteArray() const { return pasteAllChildren(); @@ -474,6 +1167,14 @@ bool SourceNameNode::mangledRepresentationStartsWith(char c) return strchr("123456789", c); } +/* ::= */ +void SourceNameNode::parse() +{ + const int idLen = getNonNegativeNumber<10>(parseState()); + m_name = parseState()->readAhead(idLen); + parseState()->advance(idLen); +} + bool UnqualifiedNameNode::mangledRepresentationStartsWith(char c) { @@ -495,7 +1196,25 @@ bool UnqualifiedNameNode::isConstructorOrDestructorOrConversionOperator() const if (dynamic_cast(MY_CHILD_AT(0))) return true; const OperatorNameNode * const opNode = dynamic_cast(MY_CHILD_AT(0)); - return opNode && opNode->m_type == OperatorNameNode::CastType; + return opNode && opNode->type() == OperatorNameNode::CastType; +} + +/* + * ::= + * ::= + * ::= + */ +void UnqualifiedNameNode::parse() +{ + const char next = PEEK(); + if (OperatorNameNode::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(OperatorNameNode); + else if (CtorDtorNameNode::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CtorDtorNameNode); + else if (SourceNameNode::mangledRepresentationStartsWith(next)) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceNameNode); + else + throw ParseException(QString::fromLatin1("Invalid unqualified-name")); } @@ -519,6 +1238,25 @@ bool UnscopedNameNode::isConstructorOrDestructorOrConversionOperator() const return childNode->isConstructorOrDestructorOrConversionOperator(); } +/* + * ::= + * ::= St # ::std:: + */ +void UnscopedNameNode::parse() +{ + if (parseState()->readAhead(2) == "St") { + m_inStdNamespace = true; + parseState()->advance(2); + } else { + m_inStdNamespace = false; + } + + if (!UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) + throw ParseException(QString::fromLatin1("Invalid unscoped-name")); + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedNameNode); +} + bool NestedNameNode::mangledRepresentationStartsWith(char c) { @@ -545,12 +1283,104 @@ bool NestedNameNode::isConstructorOrDestructorOrConversionOperator() const return childNode->isConstructorOrDestructorOrConversionOperator(); } +/* + * ::= N [] E + * ::= N [] E + * ::= + * ::= + * ::= + * + * The rule leads to an indirect recursion with , so + * we integrate it into : + * ::= N [] + * [] E + * ::= N [] E + * ::= N [] E + * + * The occurrence of in the first expansion makes this rule + * completely unmanageable, because 's first and follow sets are + * not distinct and it also shares elements of its first set with + * and . However, can expand + * to both the non-terminals it is followed by as well as the two competing + * non-terminal sequences in the other rules, so we can just write: + * ::= N [] E + * + * That's not all, though: Both and can start + * with an 'r', so we have to do a two-character-look-ahead for that case. + */ +void NestedNameNode::parse() +{ + if (!mangledRepresentationStartsWith(ADVANCE())) + throw ParseException(QString::fromLatin1("Invalid nested-name")); + + if (CvQualifiersNode::mangledRepresentationStartsWith(PEEK()) && parseState()->peek(1) != 'm' + && parseState()->peek(1) != 'M' && parseState()->peek(1) != 's' + && parseState()->peek(1) != 'S') { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CvQualifiersNode); + } + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(PrefixNode); + + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid nested-name")); +} + bool SubstitutionNode::mangledRepresentationStartsWith(char c) { return c == 'S'; } +/* + * ::= S _ # 36-bit number + * ::= S_ + * ::= St # ::std:: + * ::= Sa # ::std::allocator + * ::= Sb # ::std::basic_string + * ::= Ss # ::std::basic_string < char, + * ::std::char_traits, + * ::std::allocator > + * ::= Si # ::std::basic_istream > + * ::= So # ::std::basic_ostream > + * ::= Sd # ::std::basic_iostream > + */ +void SubstitutionNode::parse() +{ + if (!mangledRepresentationStartsWith(ADVANCE())) + throw ParseException(QString::fromLatin1("Invalid substitution")); + + if (NonNegativeNumberNode<36>::mangledRepresentationStartsWith(PEEK())) { + const int substIndex = getNonNegativeNumber<36>(parseState()) + 1; + if (substIndex >= parseState()->substitutionCount()) { + throw ParseException(QString::fromLatin1("Invalid substitution: substitution %1 " + "was requested, but there are only %2"). + arg(substIndex + 1).arg(parseState()->substitutionCount())); + } + m_type = ActualSubstitutionType; + m_substValue = parseState()->substitutionAt(substIndex); + if (ADVANCE() != '_') + throw ParseException(QString::fromLatin1("Invalid substitution")); + } else { + switch (ADVANCE()) { + case '_': + if (parseState()->substitutionCount() == 0) + throw ParseException(QString::fromLatin1("Invalid substitution: " + "There are no substitutions")); + m_type = ActualSubstitutionType; + m_substValue = parseState()->substitutionAt(0); + break; + case 't': m_type = StdType; break; + case 'a': m_type = StdAllocType; break; + case 'b': m_type = StdBasicStringType; break; + case 's': m_type = FullStdBasicStringType; break; + case 'i': m_type = StdBasicIStreamType; break; + case 'o': m_type = StdBasicOStreamType; break; + case 'd': m_type = StdBasicIoStreamType; break; + default: throw ParseException(QString::fromLatin1("Invalid substitution")); + } + } +} + QByteArray SubstitutionNode::toByteArray() const { switch (m_type) { @@ -575,16 +1405,26 @@ bool PointerToMemberTypeNode::mangledRepresentationStartsWith(char c) return c == 'M'; } +/* ::= M */ +void PointerToMemberTypeNode::parse() +{ + if (!mangledRepresentationStartsWith(ADVANCE())) + throw ParseException(QString::fromLatin1("Invalid pointer-to-member-type")); + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); // Class type. + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); // Member type. +} + QByteArray PointerToMemberTypeNode::toByteArray() const { // Gather all qualifiers first, because we have to move them to the end en bloc // . QByteArray qualRepr; const TypeNode *memberTypeNode = DEMANGLER_CAST(TypeNode, MY_CHILD_AT(1)); - while (memberTypeNode->m_type == TypeNode::QualifiedType) { + while (memberTypeNode->type() == TypeNode::QualifiedType) { const CvQualifiersNode * const cvNode = DEMANGLER_CAST(CvQualifiersNode, CHILD_AT(memberTypeNode, 0)); - if (cvNode->m_hasConst || cvNode->m_hasVolatile) { + if (cvNode->hasQualifiers()) { if (!qualRepr.isEmpty()) qualRepr += ' '; qualRepr += cvNode->toByteArray(); @@ -599,9 +1439,9 @@ QByteArray PointerToMemberTypeNode::toByteArray() const if (functionNode) { const BareFunctionTypeNode * const bareFunctionNode = DEMANGLER_CAST(BareFunctionTypeNode, CHILD_AT(functionNode, 0)); - if (functionNode->m_isExternC) + if (functionNode->isExternC()) repr += "extern \"C\" "; - if (bareFunctionNode->m_hasReturnType) + if (bareFunctionNode->hasReturnType()) repr += CHILD_AT(bareFunctionNode, 0)->toByteArray() + ' '; repr += '(' + classTypeRepr + "::*)" + bareFunctionNode->toByteArray(); if (!qualRepr.isEmpty()) @@ -626,6 +1466,31 @@ bool TemplateParamNode::mangledRepresentationStartsWith(char c) return c == 'T'; } +/* + * ::= T_ # first template parameter + * ::= T _ + */ +void TemplateParamNode::parse() +{ + if (!mangledRepresentationStartsWith(ADVANCE())) + throw ParseException(QString::fromLatin1("Invalid template-param")); + + if (PEEK() == '_') + m_index = 0; + else + m_index = getNonNegativeNumber<10>(parseState()) + 1; + if (ADVANCE() != '_') + throw ParseException(QString::fromLatin1("Invalid template-param")); + if (m_index >= parseState()->templateParamCount()) { + if (!parseState()->isConversionOperator()) { + throw ParseException(QString::fromLocal8Bit("Invalid template parameter index %1") + .arg(m_index)); + } + } else { + addChild(parseState()->templateParamAt(m_index)); + } +} + QByteArray TemplateParamNode::toByteArray() const { return CHILD_TO_BYTEARRAY(0); @@ -637,6 +1502,22 @@ bool TemplateArgsNode::mangledRepresentationStartsWith(char c) return c == 'I'; } +/* + * ::= I + E + */ +void TemplateArgsNode::parse() +{ + if (!mangledRepresentationStartsWith(ADVANCE())) + throw ParseException(QString::fromLatin1("Invalid template args")); + + do + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgNode); + while (TemplateArgNode::mangledRepresentationStartsWith(PEEK())); + + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid template args")); +} + QByteArray TemplateArgsNode::toByteArray() const { QByteArray repr = "<"; @@ -654,6 +1535,55 @@ bool SpecialNameNode::mangledRepresentationStartsWith(char c) return c == 'T' || c == 'G'; } +/* + * ::= TV # virtual table + * ::= TT # VTT structure (construction vtable index) + * ::= TI # typeinfo structure + * ::= TS # typeinfo name (null-terminated byte string) + * ::= GV # Guard variable for one-time initialization + * ::= T + * ::= Tc + * # base is the nominal target function of thunk + * # first call-offset is 'this' adjustment + * # second call-offset is result adjustment + */ +void SpecialNameNode::parse() +{ + QByteArray str = parseState()->readAhead(2); + if (str == "TV") { + m_type = VirtualTableType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else if (str == "TT") { + m_type = VttStructType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else if (str == "TI") { + m_type = TypeInfoType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else if (str == "TS") { + m_type = TypeInfoNameType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else if (str == "GV") { + m_type = GuardVarType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NameNode); + } else if (str == "Tc") { + m_type = DoubleCallOffsetType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CallOffsetNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CallOffsetNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(EncodingNode); + } else if (ADVANCE() == 'T') { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CallOffsetNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(EncodingNode); + } else { + throw ParseException(QString::fromLatin1("Invalid special-name")); + } +} + QByteArray SpecialNameNode::toByteArray() const { switch (m_type) { @@ -679,9 +1609,26 @@ QByteArray SpecialNameNode::toByteArray() const } -bool NumberNode::mangledRepresentationStartsWith(char c, int base) +bool NumberNode::mangledRepresentationStartsWith(char c) { - return NonNegativeNumberNode::mangledRepresentationStartsWith(c, base) || c == 'n'; + return NonNegativeNumberNode<10>::mangledRepresentationStartsWith(c) || c == 'n'; +} + +/* ::= [n] */ +void NumberNode::parse() +{ + const char next = PEEK(); + if (!mangledRepresentationStartsWith(next)) + throw ParseException("Invalid number"); + + if (next == 'n') { + m_isNegative = true; + ADVANCE(); + } else { + m_isNegative = false; + } + + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NonNegativeNumberNode<10>); } QByteArray NumberNode::toByteArray() const @@ -693,7 +1640,7 @@ QByteArray NumberNode::toByteArray() const } -bool NonNegativeNumberNode::mangledRepresentationStartsWith(char c, int base) +template bool NonNegativeNumberNode::mangledRepresentationStartsWith(char c) { // Base can only be 10 or 36. if (base == 10) @@ -702,7 +1649,17 @@ bool NonNegativeNumberNode::mangledRepresentationStartsWith(char c, int base) return strchr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", c); } -QByteArray NonNegativeNumberNode::toByteArray() const +template void NonNegativeNumberNode::parse() +{ + QByteArray numberRepr; + while (mangledRepresentationStartsWith(PEEK())) + numberRepr += ADVANCE(); + if (numberRepr.count() == 0) + throw ParseException(QString::fromLatin1("Invalid non-negative number")); + m_number = numberRepr.toULongLong(0, base); +} + +template QByteArray NonNegativeNumberNode::toByteArray() const { return QByteArray::number(m_number); } @@ -743,6 +1700,46 @@ bool NameNode::isConstructorOrDestructorOrConversionOperator() const return false; } +/* + * ::= + * ::= + * ::= + * ::= # See Scope Encoding below + * + * We can't use this rule directly, because + * can expand to . We therefore integrate it directly + * into the production for : + * ::= [] + * ::= + * + * Secondly, shares an expansion ("St") with , + * so we have to look further ahead to see which one matches. + */ +void NameNode::parse() +{ + if ((parseState()->readAhead(2) == "St" + && UnqualifiedNameNode::mangledRepresentationStartsWith(parseState()->peek(2))) + || UnscopedNameNode::mangledRepresentationStartsWith(PEEK())) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnscopedNameNode); + if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) { + parseState()->addSubstitution(this); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); + } + } else { + const char next = PEEK(); + if (NestedNameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NestedNameNode); + } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SubstitutionNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); + } else if (LocalNameNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(LocalNameNode); + } else { + throw ParseException(QString::fromLatin1("Invalid name")); + } + } +} + bool TemplateArgNode::mangledRepresentationStartsWith(char c) { @@ -751,6 +1748,43 @@ bool TemplateArgNode::mangledRepresentationStartsWith(char c) || c == 'X' || c == 'I' || c == 's'; } +/* + * ::= # type or template + * ::= X E # expression + * ::= # simple expressions + * ::= J * E # argument pack + * ::= sp # pack expansion of (C++0x) + */ +void TemplateArgNode::parse() +{ + m_isTemplateArgumentPack = false; + + char next = PEEK(); + if (parseState()->readAhead(2) == "sp") { + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExpressionNode); + } else if (TypeNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else if (ExprPrimaryNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExprPrimaryNode); + } else if (next == 'X') { + ADVANCE(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExpressionNode); + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid template-arg")); + } else if (next == 'J') { + ADVANCE(); + while (TemplateArgNode::mangledRepresentationStartsWith(PEEK())) + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgNode); + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid template-arg")); + } else { + throw ParseException(QString::fromLatin1("Invalid template-arg")); + } + + parseState()->addTemplateParam(this); +} + QByteArray TemplateArgNode::toByteArray() const { if (m_isTemplateArgumentPack) { @@ -799,6 +1833,34 @@ bool Prefix2Node::isConstructorOrDestructorOrConversionOperator() const return false; } +/* + * ::= [] + * ::= # empty + */ +void Prefix2Node::parse() +{ + // We need to do this so we can correctly add all substitutions, which always start + // with the representation of the prefix node. + // Note that this breaks the invariant that a node is on the stack while it is being parsed; + // it does not seem that this matters in practice for this particular node. + ParseTreeNode * const prefixNode + = parseState()->stackElementAt(parseState()->stackElementCount() - 2); + prefixNode->addChild(this); + parseState()->popFromStack(); + + bool firstRun = true; + while (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) { + if (!firstRun) + parseState()->addSubstitution(prefixNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(UnqualifiedNameNode); + if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) { + parseState()->addSubstitution(prefixNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); + } + firstRun = false; + } +} + bool PrefixNode::mangledRepresentationStartsWith(char c) { @@ -834,6 +1896,45 @@ bool PrefixNode::isConstructorOrDestructorOrConversionOperator() const return childNode->isConstructorOrDestructorOrConversionOperator(); } +/* + * ::= + * ::= + * ::= + * ::= # empty + * ::= + * + * We have to eliminate the left-recursion and the template-prefix rule + * and end up with this: + * ::= [] + * ::= [] + * ::= + */ +void PrefixNode::parse() +{ + const char next = PEEK(); + if (TemplateParamNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParamNode); + if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) { + parseState()->addSubstitution(this); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); + } + if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) { + parseState()->addSubstitution(this); + parseRule(parseState()); // Pops itself to child list. + } + } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SubstitutionNode); + if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); + if (UnqualifiedNameNode::mangledRepresentationStartsWith(PEEK())) + parseState()->addSubstitution(this); + } + parseRule(parseState()); // Pops itself to child list. + } else { + parseRule(parseState()); // Pops itself to child list. + } +} + bool TypeNode::mangledRepresentationStartsWith(char c) { @@ -849,6 +1950,157 @@ bool TypeNode::mangledRepresentationStartsWith(char c) } +/* + * ::= + * ::= + * ::= + * ::= + * ::= + * ::= + * ::= + * ::= # See Compression below + * ::= + * ::= P # pointer-to + * ::= R # reference-to + * ::= O # rvalue reference-to (C++0x) + * ::= C # complex pair (C 2000) + * ::= G # imaginary (C 2000) + * ::= U # vendor extended type qualifier + * ::= Dp # pack expansion of (C++0x) + * ::= Dt E # decltype of an id-expression or class member access (C++0x) + * ::= DT E # decltype of an expression (C++0x) + * + * Because can expand to , we have to + * do a slight transformation: We get rid of and + * integrate its rhs into 's rhs. This leads to the following + * identical prefixes: + * ::= + * ::= + * ::= + * ::= + * + * Also, the first set of has some overlap with + * direct productions of , so these have to be worked around as well. + */ +void TypeNode::parse() +{ + QByteArray str = parseState()->readAhead(2); + if (str == "Dp") { + m_type = PackExpansionType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else if (str == "Dt") { + m_type = DeclType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExpressionNode); + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid type")); + } else if (str == "DT") { + m_type = DeclType; + parseState()->advance(2); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ExpressionNode); + if (ADVANCE() != 'E') + throw ParseException(QString::fromLatin1("Invalid type")); + } else { + const char next = PEEK(); + if (str == "Dd" || str == "De" || str == "Df" || str == "Dh" || str == "Di" || str == "Ds" + || (next != 'D' && BuiltinTypeNode::mangledRepresentationStartsWith(next))) { + m_type = OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(BuiltinTypeNode); + } else if (FunctionTypeNode::mangledRepresentationStartsWith(next)) { + m_type = OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(FunctionTypeNode); + parseState()->addSubstitution(this); + } else if (ClassEnumTypeNode::mangledRepresentationStartsWith(next)) { + m_type = OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ClassEnumTypeNode); + parseState()->addSubstitution(this); + } else if (ArrayTypeNode::mangledRepresentationStartsWith(next)) { + m_type = OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(ArrayTypeNode); + } else if (PointerToMemberTypeNode::mangledRepresentationStartsWith(next)) { + m_type = OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(PointerToMemberTypeNode); + } else if (TemplateParamNode::mangledRepresentationStartsWith(next)) { + m_type = OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateParamNode); + // The type is now a substitution candidate, but the child node may contain a forward + // reference, so we delay the substitution until it is resolved. + // TODO: Check whether this is really safe, i.e. whether the following parse function + // might indirectly expect this substitution to already exist. + + if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); + // Substitution delayed, see above. + } + + // Resolve forward reference, if necessary. + TemplateParamNode * const templateParamNode + = DEMANGLER_CAST(TemplateParamNode, MY_CHILD_AT(0)); + if (templateParamNode->childCount() == 0) { + if (templateParamNode->index() >= parseState()->templateParamCount()) { + throw ParseException(QString::fromLocal8Bit("Invalid template parameter " + "index %1 in forwarding").arg(templateParamNode->index())); + } + templateParamNode->addChild(parseState() + ->templateParamAt(templateParamNode->index())); + } + + // Delayed substitutions from above. + parseState()->addSubstitution(templateParamNode); + if (childCount() > 1) + parseState()->addSubstitution(this); + } else if (SubstitutionNode::mangledRepresentationStartsWith(next)) { + m_type = OtherType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SubstitutionNode); + if (TemplateArgsNode::mangledRepresentationStartsWith(PEEK())) { + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TemplateArgsNode); + parseState()->addSubstitution(this); + } + } else if (CvQualifiersNode::mangledRepresentationStartsWith(next)) { + m_type = QualifiedType; + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(CvQualifiersNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + const CvQualifiersNode * const cvNode + = DEMANGLER_CAST(CvQualifiersNode, MY_CHILD_AT(0)); + if (cvNode->hasQualifiers()) + parseState()->addSubstitution(this); + } else if (next == 'P') { + m_type = PointerType; + ADVANCE(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + parseState()->addSubstitution(this); + } else if (next == 'R') { + m_type = ReferenceType; + ADVANCE(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + parseState()->addSubstitution(this); + } else if (next == 'O') { + m_type = RValueType; + ADVANCE(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + parseState()->addSubstitution(this); + } else if (next == 'C') { + m_type = OtherType; + ADVANCE(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + parseState()->addSubstitution(this); + } else if (next == 'G') { + m_type = OtherType; + ADVANCE(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + parseState()->addSubstitution(this); + } else if (next == 'U') { + m_type = VendorType; + ADVANCE(); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(SourceNameNode); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(TypeNode); + } else { + throw ParseException(QString::fromLatin1("Invalid type")); + } + } +} + QByteArray TypeNode::toByteArray() const { // A pure top-down approach is not possible to due to the weird function pointer syntax, @@ -865,7 +2117,7 @@ QByteArray TypeNode::toByteArray() const case QualifiedType: { const CvQualifiersNode * const cvNode = DEMANGLER_CAST(CvQualifiersNode, CHILD_AT(currentNode, 0)); - if (cvNode->m_hasConst || cvNode->m_hasVolatile) + if (cvNode->hasQualifiers()) qualPtrRefList << cvNode; currentNode = DEMANGLER_CAST(TypeNode, CHILD_AT(currentNode, 1)); break; @@ -902,9 +2154,9 @@ QByteArray TypeNode::toByteArrayQualPointerRef(const TypeNode *typeNode, const BareFunctionTypeNode * const bareFunctionNode = DEMANGLER_CAST(BareFunctionTypeNode, CHILD_AT(functionNode, 0)); QByteArray repr; - if (functionNode->m_isExternC) + if (functionNode->isExternC()) repr += "extern \"C\" "; - if (bareFunctionNode->m_hasReturnType) + if (bareFunctionNode->hasReturnType()) repr += CHILD_AT(bareFunctionNode, 0)->toByteArray() + ' '; return repr += '(' + qualPtrRef + ')' + bareFunctionNode->toByteArray(); } @@ -954,10 +2206,44 @@ bool FloatValueNode::mangledRepresentationStartsWith(char c) return strchr("0123456789abcdef", c); } +/* + * Floating-point literals are encoded using a fixed-length lowercase + * hexadecimal string corresponding to the internal representation + * (IEEE on Itanium), high-order bytes first, without leading zeroes. + * For example: "Lf bf800000 E" is -1.0f on Itanium. + */ +void FloatValueNode::parse() +{ + m_value = 0; + while (mangledRepresentationStartsWith(PEEK())) { + // TODO: Construct value; + ADVANCE(); + } +} + QByteArray FloatValueNode::toByteArray() const { return QByteArray::number(m_value); } + +/* ::= # non-virtual base override */ +void NvOffsetNode::parse() +{ + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NumberNode); +} + +/* + * ::= _ + * # virtual base override, with vcall offset + */ +void VOffsetNode::parse() +{ + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NumberNode); + if (ADVANCE() != '_') + throw ParseException(QString::fromLatin1("Invalid v-offset")); + PARSE_RULE_AND_ADD_RESULT_AS_CHILD(NumberNode); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/namedemangler/parsetreenodes.h b/src/plugins/debugger/namedemangler/parsetreenodes.h index c8730092a2cf930c91ab0fdae06b8a0a0f5d7333..3ac415a9b37de304c0a496aa8dfc0206da0fac01 100644 --- a/src/plugins/debugger/namedemangler/parsetreenodes.h +++ b/src/plugins/debugger/namedemangler/parsetreenodes.h @@ -32,11 +32,15 @@ #ifndef PARSETREENODES_H #define PARSETREENODES_H +#include "globalparsestate.h" + #include #include #include -#define CHILD_AT(obj, index) obj->childAt(index, Q_FUNC_INFO, __FILE__, __LINE__) +// TODO: Get the number of node objects in a tree down by only creating sub-nodes if there is really a need +// or things would get more complicated without them. +// Example for an unnecessary object: The parent type node of a function type node -- it holds zero information! namespace Debugger { namespace Internal { @@ -52,11 +56,25 @@ public: ParseTreeNode *childAt(int i, const QString &func, const QString &file, int line) const; QByteArray pasteAllChildren() const; + template static T *parseRule(GlobalParseState *parseState) + { + T * const node = new T; + node->m_parseState = parseState; + parseState->pushToStack(node); + parseState->stackTop()->parse(); + return node; + } + protected: + GlobalParseState *parseState() const { return m_parseState; } + void clearChildList() { m_children.clear(); } private: + virtual void parse() = 0; + QList m_children; // Convention: Children are inserted in parse order. + GlobalParseState *m_parseState; }; class ArrayTypeNode : public ParseTreeNode @@ -65,6 +83,9 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; class BareFunctionTypeNode : public ParseTreeNode @@ -72,8 +93,13 @@ class BareFunctionTypeNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); + bool hasReturnType() const { return m_hasReturnType; } + QByteArray toByteArray() const; +private: + void parse(); + bool m_hasReturnType; }; @@ -83,13 +109,19 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; +// TODO: DIE!!! class PredefinedBuiltinTypeNode : public ParseTreeNode { public: QByteArray toByteArray() const; + void parse() {} + enum Type { VoidType, WCharType, BoolType, PlainCharType, SignedCharType, UnsignedCharType, SignedShortType, UnsignedShortType, @@ -107,18 +139,27 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; class NvOffsetNode : public ParseTreeNode { public: QByteArray toByteArray() const { return QByteArray(); } // TODO: How to encode this? + +private: + void parse(); }; class VOffsetNode : public ParseTreeNode { public: QByteArray toByteArray() const { return QByteArray(); } // TODO: How to encode this? + +private: + void parse(); }; class ClassEnumTypeNode : public ParseTreeNode @@ -127,6 +168,9 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; class DiscriminatorNode : public ParseTreeNode @@ -135,6 +179,9 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; class CtorDtorNameNode : public ParseTreeNode @@ -144,6 +191,9 @@ public: QByteArray toByteArray() const; +private: + void parse(); + bool m_isDestructor; QByteArray m_representation; }; @@ -153,7 +203,11 @@ class CvQualifiersNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); + bool hasQualifiers() const { return m_hasConst || m_hasVolatile; } + QByteArray toByteArray() const; +private: + void parse(); bool m_hasVolatile; bool m_hasConst; @@ -165,6 +219,9 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; class ExpressionNode : public ParseTreeNode @@ -174,6 +231,9 @@ public: QByteArray toByteArray() const; +private: + void parse(); + enum Type { ConversionType, SizeofType, AlignofType, OperatorType, OtherType, ParameterPackSizeType } m_type; @@ -184,8 +244,6 @@ class OperatorNameNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); - QByteArray toByteArray() const; - enum Type { NewType, ArrayNewType, DeleteType, ArrayDeleteType, UnaryPlusType, UnaryMinusType, UnaryAmpersandType, UnaryStarType, BitwiseNotType, BinaryPlusType, BinaryMinusType, @@ -197,8 +255,15 @@ public: LogicalAndType, LogicalOrType, IncrementType, DecrementType, CommaType, ArrowStarType, ArrowType, CallType, IndexType, TernaryType, SizeofTypeType, SizeofExprType, AlignofTypeType, AlignofExprType, CastType, VendorType - } m_type; + }; + Type type() const { return m_type; } + + QByteArray toByteArray() const; + +private: + void parse(); + Type m_type; }; class ExprPrimaryNode : public ParseTreeNode @@ -207,6 +272,9 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; class FunctionTypeNode : public ParseTreeNode @@ -214,8 +282,13 @@ class FunctionTypeNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); + bool isExternC() const { return m_isExternC; } + QByteArray toByteArray() const; +private: + void parse(); + bool m_isExternC; }; @@ -226,6 +299,9 @@ public: QByteArray toByteArray() const; +private: + void parse(); + bool m_isStringLiteral; }; @@ -235,15 +311,21 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; class NumberNode : public ParseTreeNode { public: - static bool mangledRepresentationStartsWith(char c, int base = 10); + static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; +private: + void parse(); + bool m_isNegative; }; @@ -254,6 +336,9 @@ public: QByteArray toByteArray() const { return m_name; } +private: + void parse(); + QByteArray m_name; }; @@ -262,9 +347,12 @@ class UnqualifiedNameNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); + bool isConstructorOrDestructorOrConversionOperator() const; + QByteArray toByteArray() const; - bool isConstructorOrDestructorOrConversionOperator() const; +private: + void parse(); }; class UnscopedNameNode : public ParseTreeNode @@ -272,9 +360,12 @@ class UnscopedNameNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); + bool isConstructorOrDestructorOrConversionOperator() const; + QByteArray toByteArray() const; - bool isConstructorOrDestructorOrConversionOperator() const; +private: + void parse(); bool m_inStdNamespace; }; @@ -284,10 +375,13 @@ class NestedNameNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); - QByteArray toByteArray() const; - bool isTemplate() const; bool isConstructorOrDestructorOrConversionOperator() const; + + QByteArray toByteArray() const; + +private: + void parse(); }; class SubstitutionNode : public ParseTreeNode @@ -297,6 +391,9 @@ public: QByteArray toByteArray() const; +private: + void parse(); + enum Type { ActualSubstitutionType, StdType, StdAllocType, StdBasicStringType, FullStdBasicStringType, StdBasicIStreamType, StdBasicOStreamType, StdBasicIoStreamType @@ -310,6 +407,9 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; class TemplateParamNode : public ParseTreeNode @@ -319,7 +419,14 @@ public: static bool mangledRepresentationStartsWith(char c); + int index() const { return m_index; } + QByteArray toByteArray() const; + +private: + void parse(); + + int m_index; }; class TemplateArgsNode : public ParseTreeNode @@ -328,6 +435,9 @@ public: static bool mangledRepresentationStartsWith(char c); QByteArray toByteArray() const; + +private: + void parse(); }; class SpecialNameNode : public ParseTreeNode @@ -337,19 +447,27 @@ public: QByteArray toByteArray() const; +private: + void parse(); + enum Type { VirtualTableType, VttStructType, TypeInfoType, TypeInfoNameType, GuardVarType, SingleCallOffsetType, DoubleCallOffsetType } m_type; }; -class NonNegativeNumberNode : public ParseTreeNode +template class NonNegativeNumberNode : public ParseTreeNode { public: - static bool mangledRepresentationStartsWith(char c, int base = 10); + static bool mangledRepresentationStartsWith(char c); + + quint64 number() const { return m_number; } QByteArray toByteArray() const; +private: + void parse(); + quint64 m_number; }; @@ -358,10 +476,13 @@ class NameNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); - QByteArray toByteArray() const; - bool isTemplate() const; bool isConstructorOrDestructorOrConversionOperator() const; + + QByteArray toByteArray() const; + +private: + void parse(); }; class TemplateArgNode : public ParseTreeNode @@ -371,6 +492,9 @@ public: QByteArray toByteArray() const; +private: + void parse(); + bool m_isTemplateArgumentPack; }; @@ -379,10 +503,13 @@ class Prefix2Node : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); - QByteArray toByteArray() const; - bool isTemplate() const; bool isConstructorOrDestructorOrConversionOperator() const; + + QByteArray toByteArray() const; + +private: + void parse(); }; class PrefixNode : public ParseTreeNode @@ -390,10 +517,13 @@ class PrefixNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); - QByteArray toByteArray() const; - bool isTemplate() const; bool isConstructorOrDestructorOrConversionOperator() const; + + QByteArray toByteArray() const; + +private: + void parse(); }; class TypeNode : public ParseTreeNode @@ -401,16 +531,22 @@ class TypeNode : public ParseTreeNode public: static bool mangledRepresentationStartsWith(char c); + enum Type { + QualifiedType, PointerType, ReferenceType, RValueType, VendorType, PackExpansionType, + DeclType, OtherType + }; + Type type() const { return m_type; } + QByteArray toByteArray() const; +private: + void parse(); + QByteArray toByteArrayQualPointerRef(const TypeNode *typeNode, const QByteArray &qualPtrRef) const; QByteArray qualPtrRefListToByteArray(const QList &nodeList) const; - enum Type { - QualifiedType, PointerType, ReferenceType, RValueType, VendorType, PackExpansionType, - DeclType, OtherType - } m_type; + Type m_type; }; class FloatValueNode : public ParseTreeNode @@ -420,6 +556,9 @@ public: QByteArray toByteArray() const; +private: + void parse(); + double m_value; }; diff --git a/tests/auto/debugger/namedemangler.pro b/tests/auto/debugger/namedemangler.pro index 663743b3af165aa3ace59a77aeaebc22687a71b8..d175689fcabedcaadd667293ceb5a56a08da725c 100644 --- a/tests/auto/debugger/namedemangler.pro +++ b/tests/auto/debugger/namedemangler.pro @@ -1,15 +1,10 @@ include(../qttest.pri) -APPSOURCEDIR = $$CREATORSOURCEDIR/src/plugins/qt4projectmanager/wizards LIBS *= -L$$IDE_LIBRARY_PATH -lUtils DEBUGGERDIR = $$IDE_SOURCE_TREE/src/plugins/debugger INCLUDEPATH += $$DEBUGGERDIR -HEADERS += \ - $$DEBUGGERDIR/namedemangler/namedemangler.h \ - $$DEBUGGERDIR/namedemangler/parsetreenodes.h -SOURCES += \ - tst_namedemangler.cpp \ - $$DEBUGGERDIR/namedemangler/namedemangler.cpp \ - $$DEBUGGERDIR/namedemangler/parsetreenodes.cpp +SOURCES = tst_namedemangler.cpp +include($$DEBUGGERDIR/namedemangler/namedemangler.pri) + diff --git a/tests/auto/debugger/tst_namedemangler.cpp b/tests/auto/debugger/tst_namedemangler.cpp index 0516df52d6e2e3d15fa353a4157c8cf0d20a399a..7cdb5a0823ac348944de067ca5a03a81df508801 100644 --- a/tests/auto/debugger/tst_namedemangler.cpp +++ b/tests/auto/debugger/tst_namedemangler.cpp @@ -49,7 +49,7 @@ class NameDemanglerAutoTest : public QObject private slots: void testUnmangledName(); void testDisjunctFirstSets(); - void TEST_CORRECTLY_MANGLED_NAMEs(); + void testCorrectlyMangledNames(); void testIncorrectlyMangledNames(); private: @@ -62,7 +62,7 @@ void NameDemanglerAutoTest::testUnmangledName() QVERIFY(demangler.demangle("f") && demangler.demangledName() == "f"); } -void NameDemanglerAutoTest::TEST_CORRECTLY_MANGLED_NAMEs() +void NameDemanglerAutoTest::testCorrectlyMangledNames() { TEST_CORRECTLY_MANGLED_NAME("_Z1fv", "f()"); TEST_CORRECTLY_MANGLED_NAME("_Z1fi", "f(int)"); @@ -313,7 +313,7 @@ void NameDemanglerAutoTest::testDisjunctFirstSets() || !SourceNameNode::mangledRepresentationStartsWith(c)); // - QVERIFY(!NonNegativeNumberNode::mangledRepresentationStartsWith(c) + QVERIFY(!NonNegativeNumberNode<10>::mangledRepresentationStartsWith(c) || !ExpressionNode::mangledRepresentationStartsWith(c)); } @@ -399,18 +399,18 @@ void NameDemanglerAutoTest::testDisjunctFirstSets() && !CvQualifiersNode::mangledRepresentationStartsWith('D')); // - QVERIFY(!NonNegativeNumberNode::mangledRepresentationStartsWith('_')); + QVERIFY(!NonNegativeNumberNode<10>::mangledRepresentationStartsWith('_')); QVERIFY(!ExpressionNode::mangledRepresentationStartsWith('_')); // - QVERIFY(!NonNegativeNumberNode::mangledRepresentationStartsWith('_', 36) - && !NonNegativeNumberNode::mangledRepresentationStartsWith('t', 36) - && !NonNegativeNumberNode::mangledRepresentationStartsWith('a', 36) - && !NonNegativeNumberNode::mangledRepresentationStartsWith('b', 36) - && !NonNegativeNumberNode::mangledRepresentationStartsWith('s', 36) - && !NonNegativeNumberNode::mangledRepresentationStartsWith('i', 36) - && !NonNegativeNumberNode::mangledRepresentationStartsWith('o', 36) - && !NonNegativeNumberNode::mangledRepresentationStartsWith('d', 36)); + QVERIFY(!NonNegativeNumberNode<36>::mangledRepresentationStartsWith('_') + && !NonNegativeNumberNode<36>::mangledRepresentationStartsWith('t') + && !NonNegativeNumberNode<36>::mangledRepresentationStartsWith('a') + && !NonNegativeNumberNode<36>::mangledRepresentationStartsWith('b') + && !NonNegativeNumberNode<36>::mangledRepresentationStartsWith('s') + && !NonNegativeNumberNode<36>::mangledRepresentationStartsWith('i') + && !NonNegativeNumberNode<36>::mangledRepresentationStartsWith('o') + && !NonNegativeNumberNode<36>::mangledRepresentationStartsWith('d')); // QVERIFY(!CallOffsetNode::mangledRepresentationStartsWith('V')