Index: src/cxa_demangle.cpp =================================================================== --- src/cxa_demangle.cpp +++ src/cxa_demangle.cpp @@ -1881,65 +1881,848 @@ struct Db { - // Name stack, this is used by the parser to hold temporary names that were - // parsed. The parser colapses multiple names into new nodes to construct - // the AST. Once the parser is finished, names.size() == 1. - PODSmallVector Names; - - // Substitution table. Itanium supports name substitutions as a means of - // compression. The string "S42_" refers to the 44nd entry (base-36) in this - // table. - PODSmallVector Subs; - - // Template parameter table. Like the above, but referenced like "T42_". - // This has a smaller size compared to Subs and Names because it can be - // stored on the stack. - PODSmallVector TemplateParams; - - Qualifiers CV = QualNone; - FunctionRefQual RefQuals = FrefQualNone; - unsigned EncodingDepth = 0; - bool ParsedCtorDtorCV = false; - bool TagTemplates = true; - bool FixForwardReferences = false; - bool TryToParseTemplateArgs = true; - - BumpPointerAllocator ASTAllocator; - - template T* make(Args&& ...args) - { - return new (ASTAllocator.allocate(sizeof(T))) - T(std::forward(args)...); - } + const char *First; + const char *Last; - template NodeArray makeNodeArray(It begin, It end) - { - size_t sz = static_cast(end - begin); - void* mem = ASTAllocator.allocate(sizeof(Node*) * sz); - Node** data = new (mem) Node*[sz]; - std::copy(begin, end, data); - return NodeArray(data, sz); + // Name stack, this is used by the parser to hold temporary names that were + // parsed. The parser colapses multiple names into new nodes to construct + // the AST. Once the parser is finished, names.size() == 1. + PODSmallVector Names; + + // Substitution table. Itanium supports name substitutions as a means of + // compression. The string "S42_" refers to the 44nd entry (base-36) in this + // table. + PODSmallVector Subs; + + // Template parameter table. Like the above, but referenced like "T42_". + // This has a smaller size compared to Subs and Names because it can be + // stored on the stack. + PODSmallVector TemplateParams; + + Qualifiers CV = QualNone; + FunctionRefQual RefQuals = FrefQualNone; + unsigned EncodingDepth = 0; + bool ParsedCtorDtorCV = false; + bool TagTemplates = true; + bool FixForwardReferences = false; + bool TryToParseTemplateArgs = true; + + BumpPointerAllocator ASTAllocator; + + template + T *make(Args &&...args) { + return new (ASTAllocator.allocate(sizeof(T))) + T(std::forward(args)...); + } + + template + NodeArray makeNodeArray(It begin, It end) { + size_t sz = static_cast(end - begin); + void *mem = ASTAllocator.allocate(sizeof(Node *) * sz); + Node **data = new (mem) Node*[sz]; + std::copy(begin, end, data); + return NodeArray(data, sz); + } + + NodeArray popTrailingNodeArray(size_t FromPosition) { + assert(FromPosition <= Names.size()); + NodeArray res = + makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); + Names.dropBack(FromPosition); + return res; + } + + bool consumeIf(StringView S) { + if (StringView(First, Last).startsWith(S)) { + First += S.size(); + return true; } + return false; + } - NodeArray popTrailingNodeArray(size_t FromPosition) - { - assert(FromPosition <= Names.size()); - NodeArray res = makeNodeArray( - Names.begin() + (long)FromPosition, Names.end()); - Names.dropBack(FromPosition); - return res; + bool consumeIf(char C) { + if (First != Last && *First == C) { + ++First; + return true; } + return false; + } + + char consume() { return First != Last ? *First++ : '\0'; } + + char look(unsigned Lookahead = 0) { + if (static_cast(Last - First) <= Lookahead) + return '\0'; + return First[Lookahead]; + } + + size_t numLeft() const { return static_cast(Last - First); } + + StringView parseNumber(bool AllowNegative = false); + Qualifiers parseCVQualifiers(); + + /// Parse the production. + Node *parseExpr(); + Node *parsePrefixExpr(StringView Kind); + Node *parseBinaryExpr(StringView Kind); + Node *parseIntegerLiteral(StringView Lit); + Node *parseExprPrimary(); + template + Node *parseFloatingLiteral(); + Node *parseFunctionParam(); + Node *parseNewExpr(); + Node *parseConversionExpr(); + + // FIXME: remove this when all the parse_* functions have been rewritten. + template + Node *legacyParse() { + size_t BeforeType = Names.size(); + const char *OrigFirst = First; + const char *T = parse_fn(First, Last, *this); + if (T == OrigFirst || BeforeType + 1 != Names.size()) + return nullptr; + First = T; + Node *R = Names.back(); + Names.pop_back(); + return R; + } }; +const char* +parse_expression(const char* first, const char* last, Db& db) +{ + db.First = first; + db.Last = last; + Node *R = db.parseExpr(); + if (R == nullptr) + return first; + db.Names.push_back(R); + return db.First; +} + +const char* +parse_expr_primary(const char* first, const char* last, Db& db) +{ + db.First = first; + db.Last = last; + Node *R = db.parseExprPrimary(); + if (R == nullptr) + return first; + db.Names.push_back(R); + return db.First; +} + const char* parse_type(const char* first, const char* last, Db& db); const char* parse_encoding(const char* first, const char* last, Db& db); const char* parse_name(const char* first, const char* last, Db& db, bool* ends_with_template_args = 0); -const char* parse_expression(const char* first, const char* last, Db& db); const char* parse_template_args(const char* first, const char* last, Db& db); +const char* parse_template_param(const char*, const char*, Db&); const char* parse_operator_name(const char* first, const char* last, Db& db); const char* parse_unqualified_name(const char* first, const char* last, Db& db); const char* parse_decltype(const char* first, const char* last, Db& db); +const char* parse_unresolved_name(const char*, const char*, Db&); + +// ::= [n] +StringView Db::parseNumber(bool AllowNegative) { + const char *Tmp = First; + if (AllowNegative) + consumeIf('n'); + if (numLeft() == 0 || !std::isdigit(*First)) + return StringView(); + while (numLeft() != 0 && std::isdigit(*First)) + ++First; + return StringView(Tmp, First); +} + +Node *Db::parsePrefixExpr(StringView Kind) { + Node *E = parseExpr(); + if (E == nullptr) + return nullptr; + return make(Kind, E); +} + +Node *Db::parseBinaryExpr(StringView Kind) { + Node *LHS = parseExpr(); + if (LHS == nullptr) + return nullptr; + Node *RHS = parseExpr(); + if (RHS == nullptr) + return nullptr; + return make(LHS, Kind, RHS); +} + +Node *Db::parseIntegerLiteral(StringView Lit) { + StringView Tmp = parseNumber(true); + if (!Tmp.empty() && consumeIf('E')) + return make(Lit, Tmp); + return nullptr; +} + +Qualifiers Db::parseCVQualifiers() { + Qualifiers CVR = QualNone; + if (consumeIf('r')) + addQualifiers(CVR, QualRestrict); + if (consumeIf('V')) + addQualifiers(CVR, QualVolatile); + if (consumeIf('K')) + addQualifiers(CVR, QualConst); + return CVR; +} + +// ::= fp _ # L == 0, first parameter +// ::= fp _ # L == 0, second and later parameters +// ::= fL p _ # L > 0, first parameter +// ::= fL p _ # L > 0, second and later parameters +Node *Db::parseFunctionParam() { + if (consumeIf("fp")) { + parseCVQualifiers(); + StringView Num = parseNumber(); + if (!consumeIf('_')) + return nullptr; + return make(Num); + } + if (consumeIf("fL")) { + if (parseNumber().empty()) + return nullptr; + if (!consumeIf('p')) + return nullptr; + parseCVQualifiers(); + StringView Num = parseNumber(); + if (!consumeIf('_')) + return nullptr; + return make(Num); + } + return nullptr; +} + +// [gs] nw * _ E # new (expr-list) type +// [gs] nw * _ # new (expr-list) type (init) +// [gs] na * _ E # new[] (expr-list) type +// [gs] na * _ # new[] (expr-list) type (init) +// ::= pi * E # parenthesized initialization +Node *Db::parseNewExpr() { + bool Global = consumeIf("gs"); + bool IsArray = look(1) == 'w'; + if (!consumeIf("nw") && !consumeIf("na")) + return nullptr; + size_t Exprs = Names.size(); + while (!consumeIf('_')) { + Node *Ex = parseExpr(); + if (Ex == nullptr) + return nullptr; + Names.push_back(Ex); + } + NodeArray ExprList = popTrailingNodeArray(Exprs); + Node *Ty = legacyParse(); + if (Ty == nullptr) + return Ty; + if (consumeIf("pi")) { + size_t InitsBegin = Names.size(); + while (!consumeIf('E')) { + Node *Init = parseExpr(); + if (Init == nullptr) + return Init; + Names.push_back(Init); + } + NodeArray Inits = popTrailingNodeArray(InitsBegin); + return make(ExprList, Ty, Inits, Global, IsArray); + } + return make(ExprList, Ty, NodeArray(), Global, IsArray); +} + +// cv # conversion with one argument +// cv _ * E # conversion with a different number of arguments +Node *Db::parseConversionExpr() { + if (!consumeIf("cv")) + return nullptr; + Node *Ty; + { + SwapAndRestore SaveTemp(TryToParseTemplateArgs, false); + Ty = legacyParse(); + } + + if (Ty == nullptr) + return nullptr; + + if (consumeIf('_')) { + size_t ExprsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = legacyParse(); + if (E == nullptr) + return E; + Names.push_back(E); + } + NodeArray Exprs = popTrailingNodeArray(ExprsBegin); + return make(Ty, Exprs); + } + + Node *E = parseExpr(); + if (E == nullptr) + return nullptr; + return make(Ty, makeNodeArray(&E, &E + 1)); +} + +// ::= L E # integer literal +// ::= L E # floating literal +// ::= L E # string literal +// ::= L E # nullptr literal (i.e., "LDnE") +// FIXME: ::= L _ E # complex floating point literal (C 2000) +// ::= L E # external name +Node *Db::parseExprPrimary() { + if (!consumeIf('L')) + return nullptr; + switch (look()) { + case 'w': + ++First; + return parseIntegerLiteral("wchar_t"); + case 'b': + if (consumeIf("b0E")) + return make(0); + if (consumeIf("b1E")) + return make(1); + return nullptr; + case 'c': + ++First; + return parseIntegerLiteral("char"); + case 'a': + ++First; + return parseIntegerLiteral("signed char"); + case 'h': + ++First; + return parseIntegerLiteral("unsigned char"); + case 's': + ++First; + return parseIntegerLiteral("short"); + case 't': + ++First; + return parseIntegerLiteral("unsigned short"); + case 'i': + ++First; + return parseIntegerLiteral(""); + case 'j': + ++First; + return parseIntegerLiteral("u"); + case 'l': + ++First; + return parseIntegerLiteral("l"); + case 'm': + ++First; + return parseIntegerLiteral("ul"); + case 'x': + ++First; + return parseIntegerLiteral("ll"); + case 'y': + ++First; + return parseIntegerLiteral("ull"); + case 'n': + ++First; + return parseIntegerLiteral("__int128"); + case 'o': + ++First; + return parseIntegerLiteral("unsigned __int128"); + case 'f': + ++First; + return parseFloatingLiteral(); + case 'd': + ++First; + return parseFloatingLiteral(); + case 'e': + ++First; + return parseFloatingLiteral(); + case '_': + if (consumeIf("_Z")) { + Node *R = legacyParse(); + if (R != nullptr && consumeIf('E')) + return R; + } + return nullptr; + case 'T': + // Invalid mangled name per + // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html + return nullptr; + default: { + // might be named type + Node *T = legacyParse(); + if (T == nullptr) + return nullptr; + StringView N = parseNumber(); + if (!N.empty()) { + if (!consumeIf('E')) + return nullptr; + return make(T, N); + } + if (consumeIf('E')) + return T; + return nullptr; + } + } +} + +// ::= +// ::= +// ::= +// ::= cl + E # call +// ::= cv # conversion with one argument +// ::= cv _ * E # conversion with a different number of arguments +// ::= [gs] nw * _ E # new (expr-list) type +// ::= [gs] nw * _ # new (expr-list) type (init) +// ::= [gs] na * _ E # new[] (expr-list) type +// ::= [gs] na * _ # new[] (expr-list) type (init) +// ::= [gs] dl # delete expression +// ::= [gs] da # delete[] expression +// ::= pp_ # prefix ++ +// ::= mm_ # prefix -- +// ::= ti # typeid (type) +// ::= te # typeid (expression) +// ::= dc # dynamic_cast (expression) +// ::= sc # static_cast (expression) +// ::= cc # const_cast (expression) +// ::= rc # reinterpret_cast (expression) +// ::= st # sizeof (a type) +// ::= sz # sizeof (an expression) +// ::= at # alignof (a type) +// ::= az # alignof (an expression) +// ::= nx # noexcept (expression) +// ::= +// ::= +// ::= dt # expr.name +// ::= pt # expr->name +// ::= ds # expr.*expr +// ::= sZ # size of a parameter pack +// ::= sZ # size of a function parameter pack +// ::= sp # pack expansion +// ::= tw # throw expression +// ::= tr # throw with no operand (rethrow) +// ::= # f(p), N::f(p), ::f(p), +// # freestanding dependent name (e.g., T::x), +// # objectless nonstatic member reference +// ::= fL +// ::= fR +// ::= fl +// ::= fr +// ::= +Node *Db::parseExpr() { + bool Global = consumeIf("gs"); + if (numLeft() < 2) + return nullptr; + + switch (*First) { + case 'L': return parseExprPrimary(); + case 'T': return legacyParse(); + case 'f': return parseFunctionParam(); + case 'a': + switch (First[1]) { + case 'a': + First += 2; + return parseBinaryExpr("&&"); + case 'd': + First += 2; + return parsePrefixExpr("&"); + case 'n': + First += 2; + return parseBinaryExpr("&"); + case 'N': + First += 2; + return parseBinaryExpr("&="); + case 'S': + First += 2; + return parseBinaryExpr("="); + case 't': { + First += 2; + Node *Ty = legacyParse(); + if (Ty == nullptr) + return nullptr; + return make("alignof (", Ty, ")"); + } + case 'z': { + First += 2; + Node *Ty = parseExpr(); + if (Ty == nullptr) + return nullptr; + return make("alignof (", Ty, ")"); + } + } + return nullptr; + case 'c': + switch (First[1]) { + // cc # const_cast (expression) + case 'c': { + First += 2; + Node *Ty = legacyParse(); + if (Ty == nullptr) + return Ty; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("const_cast", Ty, Ex); + } + // cl + E # call + case 'l': { + First += 2; + Node *Callee = parseExpr(); + if (Callee == nullptr) + return Callee; + size_t ExprsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = parseExpr(); + if (E == nullptr) + return E; + Names.push_back(E); + } + return make(Callee, popTrailingNodeArray(ExprsBegin)); + } + case 'm': + First += 2; + return parseBinaryExpr(","); + case 'o': + First += 2; + return parsePrefixExpr("~"); + case 'v': + return parseConversionExpr(); + } + return nullptr; + case 'd': + switch (First[1]) { + case 'a': { + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make(Ex, Global, /*is_array=*/true); + } + case 'c': { + First += 2; + Node *T = legacyParse(); + if (T == nullptr) + return T; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("dynamic_cast", T, Ex); + } + case 'e': + First += 2; + return parsePrefixExpr("*"); + case 'l': { + First += 2; + Node *E = parseExpr(); + if (E == nullptr) + return E; + return make(E, Global, /*is_array=*/false); + } + case 'n': { + First++; + return legacyParse(); + } + case 's': { + First += 2; + Node *LHS = parseExpr(); + if (LHS == nullptr) + return nullptr; + Node *RHS = parseExpr(); + if (RHS == nullptr) + return nullptr; + return make(LHS, ".*", RHS); + } + case 't': { + First += 2; + Node *LHS = parseExpr(); + if (LHS == nullptr) + return LHS; + Node *RHS = parseExpr(); + if (RHS == nullptr) + return nullptr; + return make(LHS, ".", RHS); + } + case 'v': + First += 2; + return parseBinaryExpr("/"); + case 'V': + First += 2; + return parseBinaryExpr("/="); + } + return nullptr; + case 'e': + switch (First[1]) { + case 'o': + First += 2; + return parseBinaryExpr("^"); + case 'O': + First += 2; + return parseBinaryExpr("^="); + case 'q': + First += 2; + return parseBinaryExpr("=="); + } + return nullptr; + case 'g': + switch (First[1]) { + case 'e': + First += 2; + return parseBinaryExpr(">="); + case 't': + First += 2; + return parseBinaryExpr(">"); + } + return nullptr; + case 'i': + if (First[1] == 'x') { + First += 2; + Node *Base = parseExpr(); + if (Base == nullptr) + return nullptr; + Node *Index = parseExpr(); + if (Index == nullptr) + return Index; + return make(Base, Index); + } + return nullptr; + case 'l': + switch (First[1]) { + case 'e': + First += 2; + return parseBinaryExpr("<="); + case 's': + First += 2; + return parseBinaryExpr("<<"); + case 'S': + First += 2; + return parseBinaryExpr("<<="); + case 't': + First += 2; + return parseBinaryExpr("<"); + } + return nullptr; + case 'm': + switch (First[1]) { + case 'i': + First += 2; + return parseBinaryExpr("-"); + case 'I': + First += 2; + return parseBinaryExpr("-="); + case 'l': + First += 2; + return parseBinaryExpr("*"); + case 'L': + First += 2; + return parseBinaryExpr("*="); + case 'm': + First += 2; + if (consumeIf('_')) + return parsePrefixExpr("--"); + Node *Ex = parseExpr(); + if (Ex == nullptr) + return nullptr; + return make(Ex, "--"); + } + return nullptr; + case 'n': + switch (First[1]) { + case 'a': + case 'w': + First += 2; + return parseNewExpr(); + case 'e': + First += 2; + return parseBinaryExpr("!="); + case 'g': + First += 2; + return parsePrefixExpr("-"); + case 't': + First += 2; + return parsePrefixExpr("!"); + case 'x': + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("noexcept (", Ex, ")"); + } + return nullptr; + case 'o': + switch (First[1]) { + case 'n': { + First += 2; + return legacyParse(); + } + case 'o': + First += 2; + return parseBinaryExpr("||"); + case 'r': + First += 2; + return parseBinaryExpr("|"); + case 'R': + First += 2; + return parseBinaryExpr("|="); + } + return nullptr; + case 'p': + switch (First[1]) { + case 'm': + First += 2; + return parseBinaryExpr("->*"); + case 'l': + First += 2; + return parseBinaryExpr("+"); + case 'L': + First += 2; + return parseBinaryExpr("+="); + case 'p': { + First += 2; + if (consumeIf('_')) + return parsePrefixExpr("++"); + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make(Ex, "++"); + } + case 's': + First += 2; + return parsePrefixExpr("+"); + case 't': { + First += 2; + Node *L = parseExpr(); + if (L == nullptr) + return nullptr; + Node *R = parseExpr(); + if (R == nullptr) + return nullptr; + return make(L, "->", R); + } + } + return nullptr; + case 'q': + if (First[1] == 'u') { + First += 2; + Node *Cond = parseExpr(); + Node *LHS = parseExpr(); + Node *RHS = parseExpr(); + if (Cond && LHS && RHS) + return make(Cond, LHS, RHS); + } + return nullptr; + case 'r': + switch (First[1]) { + case 'c': { + First += 2; + Node *T = legacyParse(); + if (T == nullptr) + return T; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("reinterpret_cast", T, Ex); + } + case 'm': + First += 2; + return parseBinaryExpr("%"); + case 'M': + First += 2; + return parseBinaryExpr("%="); + case 's': + First += 2; + return parseBinaryExpr(">>"); + case 'S': + First += 2; + return parseBinaryExpr(">>="); + } + return nullptr; + case 's': + switch (First[1]) { + case 'c': { + First += 2; + Node *T = legacyParse(); + if (T == nullptr) + return T; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("static_cast", T, Ex); + } + case 'p': { + First += 2; + Node *Child = parseExpr(); + if (Child == nullptr) + return nullptr; + return make(Child); + } + case 'r': { + return legacyParse(); + } + case 't': { + First += 2; + Node *Ty = legacyParse(); + if (Ty == nullptr) + return Ty; + return make("sizeof (", Ty, ")"); + } + case 'z': { + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("sizeof (", Ex, ")"); + } + case 'Z': + First += 2; + if (look() == 'T') { + Node *R = legacyParse(); + if (R == nullptr) + return nullptr; + return make(R); + } else if (look() == 'f') { + Node *FP = parseFunctionParam(); + if (FP == nullptr) + return nullptr; + return make("sizeof...", FP, ")"); + } + return nullptr; + } + return nullptr; + case 't': + switch (First[1]) { + case 'e': { + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make("typeid (", Ex, ")"); + } + case 'i': { + First += 2; + Node *Ty = legacyParse(); + if (Ty == nullptr) + return Ty; + return make("typeid(", Ty, ")"); + } + case 'r': + First += 2; + return make("throw"); + case 'w': { + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return nullptr; + return make(Ex); + } + } + return nullptr; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + return legacyParse(); + } + } + return nullptr; +} // ::= [n] @@ -2009,26 +2792,18 @@ constexpr const char* FloatData::spec; template -const char* -parse_floating_number(const char* first, const char* last, Db& db) -{ - const size_t N = FloatData::mangled_size; - if (static_cast(last - first) <= N) - return first; - last = first + N; - const char* t = first; - for (; t != last; ++t) - { - if (!isxdigit(*t)) - return first; - } - if (*t == 'E') - { - db.Names.push_back( - db.make>(StringView(first, t))); - first = t + 1; - } - return first; +Node *Db::parseFloatingLiteral() { + const size_t N = FloatData::mangled_size; + if (numLeft() <= N) + return nullptr; + StringView Data(First, First + N); + for (char C : Data) + if (!std::isxdigit(C)) + return nullptr; + First += N; + if (!consumeIf('E')) + return nullptr; + return make>(Data); } // ::= [0-9]* @@ -2449,326 +3224,6 @@ return first; } -// cc # const_cast (expression) - -const char* -parse_const_cast_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto from_expr = db.Names.back(); - db.Names.pop_back(); - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "const_cast", db.Names.back(), from_expr); - first = t1; - } - } - } - return first; -} - -// dc # dynamic_cast (expression) - -const char* -parse_dynamic_cast_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto from_expr = db.Names.back(); - db.Names.pop_back(); - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "dynamic_cast", db.Names.back(), from_expr); - first = t1; - } - } - } - return first; -} - -// rc # reinterpret_cast (expression) - -const char* -parse_reinterpret_cast_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto from_expr = db.Names.back(); - db.Names.pop_back(); - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "reinterpret_cast", db.Names.back(), from_expr); - first = t1; - } - } - } - return first; -} - -// sc # static_cast (expression) - -const char* -parse_static_cast_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'c') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto from_expr = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make( - "static_cast", db.Names.back(), from_expr); - first = t1; - } - } - } - return first; -} - -// sp # pack expansion - -const char* -parse_pack_expansion(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'p') - { - size_t before = db.Names.size(); - const char* t = parse_expression(first+2, last, db); - if (before + 1 != db.Names.size()) - return first; - if (t != first+2) - first = t; - db.Names.back() = db.make(db.Names.back()); - } - return first; -} - -// st # sizeof (a type) - -const char* -parse_sizeof_type_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 't') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "sizeof (", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// sz # sizeof (a expression) - -const char* -parse_sizeof_expr_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'z') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "sizeof (", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// sZ # size of a parameter pack - -const char* -parse_sizeof_param_pack_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') - { - size_t k0 = db.Names.size(); - const char* t = parse_template_param(first+2, last, db); - size_t k1 = db.Names.size(); - if (t != first+2 && k0 + 1 == k1) - { - db.Names.back() = db.make(db.Names.back()); - first = t; - } - } - return first; -} - -// ::= fp _ # L == 0, first parameter -// ::= fp _ # L == 0, second and later parameters -// ::= fL p _ # L > 0, first parameter -// ::= fL p _ # L > 0, second and later parameters - -const char* -parse_function_param(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && *first == 'f') - { - if (first[1] == 'p') - { - Qualifiers cv; - const char* t = parse_cv_qualifiers(first+2, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') - { - db.Names.push_back( - db.make(StringView(t, t1))); - first = t1+1; - } - } - else if (first[1] == 'L') - { - Qualifiers cv; - const char* t0 = parse_number(first+2, last); - if (t0 != last && *t0 == 'p') - { - ++t0; - const char* t = parse_cv_qualifiers(t0, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') - { - db.Names.push_back( - db.make(StringView(t, t1))); - first = t1+1; - } - } - } - } - return first; -} - -// sZ # size of a function parameter pack - -const char* -parse_sizeof_function_param_pack_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') - { - const char* t = parse_function_param(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "sizeof...(", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// te # typeid (expression) -// ti # typeid (type) - -const char* -parse_typeid_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) - { - const char* t; - if (first[1] == 'e') - t = parse_expression(first+2, last, db); - else - t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - "typeid(", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// tw # throw expression - -const char* -parse_throw_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 't' && first[1] == 'w') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make(db.Names.back()); - first = t; - } - } - return first; -} - -// ds # expr.*expr - -const char* -parse_dot_star_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 's') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto rhs_expr = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make( - db.Names.back(), ".*", rhs_expr); - first = t1; - } - } - } - return first; -} - // ::= [ ] const char* @@ -3127,216 +3582,6 @@ return first; } -// dt # expr.name - -const char* -parse_dot_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 't') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_unresolved_name(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto name = db.Names.back(); - db.Names.pop_back(); - if (db.Names.empty()) - return first; - db.Names.back() = db.make(db.Names.back(), ".", name); - first = t1; - } - } - } - return first; -} - -// cl + E # call - -const char* -parse_call_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') - { - const char* t = parse_expression(first+2, last, db); - if (t == last || t == first + 2 || db.Names.empty()) - return first; - Node* callee = db.Names.back(); - db.Names.pop_back(); - size_t args_begin = db.Names.size(); - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == last || t1 == t) - return first; - t = t1; - } - if (db.Names.size() < args_begin) - return first; - ++t; - CallExpr* the_call = db.make( - callee, db.popTrailingNodeArray(args_begin)); - db.Names.push_back(the_call); - first = t; - } - return first; -} - -// [gs] nw * _ E # new (expr-list) type -// [gs] nw * _ # new (expr-list) type (init) -// [gs] na * _ E # new[] (expr-list) type -// [gs] na * _ # new[] (expr-list) type (init) -// ::= pi * E # parenthesized initialization - -const char* -parse_new_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 4) - { - const char* t = first; - bool parsed_gs = false; - if (t[0] == 'g' && t[1] == 's') - { - t += 2; - parsed_gs = true; - } - if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a')) - { - bool is_array = t[1] == 'a'; - t += 2; - if (t == last) - return first; - size_t first_expr_in_list = db.Names.size(); - NodeArray ExprList, init_list; - while (*t != '_') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - } - if (first_expr_in_list > db.Names.size()) - return first; - ExprList = db.popTrailingNodeArray(first_expr_in_list); - ++t; - const char* t1 = parse_type(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - bool has_init = false; - if (last - t >= 3 && t[0] == 'p' && t[1] == 'i') - { - t += 2; - has_init = true; - size_t init_list_begin = db.Names.size(); - while (*t != 'E') - { - t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - } - if (init_list_begin > db.Names.size()) - return first; - init_list = db.popTrailingNodeArray(init_list_begin); - } - if (*t != 'E' || db.Names.empty()) - return first; - auto type = db.Names.back(); - db.Names.pop_back(); - db.Names.push_back( - db.make(ExprList, type, init_list, - parsed_gs, is_array)); - first = t+1; - } - } - return first; -} - -// cv # conversion with one argument -// cv _ * E # conversion with a different number of arguments - -const char* -parse_conversion_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') - { - bool TryToParseTemplateArgs = db.TryToParseTemplateArgs; - db.TryToParseTemplateArgs = false; - size_t type_index = db.Names.size(); - const char* t = parse_type(first+2, last, db); - db.TryToParseTemplateArgs = TryToParseTemplateArgs; - if (t != first+2 && t != last) - { - size_t expr_list_begin = db.Names.size(); - if (*t != '_') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t) - return first; - t = t1; - } - else - { - ++t; - if (t == last) - return first; - if (*t != 'E') - { - while (*t != 'E') - { - const char* t1 = parse_expression(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - } - } - ++t; - } - if (db.Names.size() < expr_list_begin || - type_index + 1 != expr_list_begin) - return first; - NodeArray expressions = db.makeNodeArray( - db.Names.begin() + (long)expr_list_begin, db.Names.end()); - auto* conv_expr = db.make( - db.Names[type_index], expressions); - db.Names.dropBack(type_index); - db.Names.push_back(conv_expr); - first = t; - } - } - return first; -} - -// pt # expr->name - -const char* -parse_arrow_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'p' && first[1] == 't') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto tmp = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make( - db.Names.back(), "->", tmp); - first = t1; - } - } - } - return first; -} - // ::= R # & ref-qualifier // ::= O # && ref-qualifier @@ -4317,213 +4562,6 @@ return first; } -const char* -parse_integer_literal(const char* first, const char* last, StringView lit, Db& db) -{ - const char* t = parse_number(first, last); - if (t != first && t != last && *t == 'E') - { - db.Names.push_back( - db.make(lit, StringView(first, t))); - first = t+1; - } - return first; -} - -// ::= L E # integer literal -// ::= L E # floating literal -// ::= L E # string literal -// ::= L E # nullptr literal (i.e., "LDnE") -// ::= L _ E # complex floating point literal (C 2000) -// ::= L E # external name - -const char* -parse_expr_primary(const char* first, const char* last, Db& db) -{ - if (last - first >= 4 && *first == 'L') - { - switch (first[1]) - { - case 'w': - { - const char* t = parse_integer_literal(first+2, last, "wchar_t", db); - if (t != first+2) - first = t; - } - break; - case 'b': - if (first[3] == 'E') - { - switch (first[2]) - { - case '0': - db.Names.push_back(db.make(0)); - first += 4; - break; - case '1': - db.Names.push_back(db.make(1)); - first += 4; - break; - } - } - break; - case 'c': - { - const char* t = parse_integer_literal(first+2, last, "char", db); - if (t != first+2) - first = t; - } - break; - case 'a': - { - const char* t = parse_integer_literal(first+2, last, "signed char", db); - if (t != first+2) - first = t; - } - break; - case 'h': - { - const char* t = parse_integer_literal(first+2, last, "unsigned char", db); - if (t != first+2) - first = t; - } - break; - case 's': - { - const char* t = parse_integer_literal(first+2, last, "short", db); - if (t != first+2) - first = t; - } - break; - case 't': - { - const char* t = parse_integer_literal(first+2, last, "unsigned short", db); - if (t != first+2) - first = t; - } - break; - case 'i': - { - const char* t = parse_integer_literal(first+2, last, "", db); - if (t != first+2) - first = t; - } - break; - case 'j': - { - const char* t = parse_integer_literal(first+2, last, "u", db); - if (t != first+2) - first = t; - } - break; - case 'l': - { - const char* t = parse_integer_literal(first+2, last, "l", db); - if (t != first+2) - first = t; - } - break; - case 'm': - { - const char* t = parse_integer_literal(first+2, last, "ul", db); - if (t != first+2) - first = t; - } - break; - case 'x': - { - const char* t = parse_integer_literal(first+2, last, "ll", db); - if (t != first+2) - first = t; - } - break; - case 'y': - { - const char* t = parse_integer_literal(first+2, last, "ull", db); - if (t != first+2) - first = t; - } - break; - case 'n': - { - const char* t = parse_integer_literal(first+2, last, "__int128", db); - if (t != first+2) - first = t; - } - break; - case 'o': - { - const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db); - if (t != first+2) - first = t; - } - break; - case 'f': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'd': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'e': - { - const char* t = parse_floating_number(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case '_': - if (first[2] == 'Z') - { - const char* t = parse_encoding(first+3, last, db); - if (t != first+3 && t != last && *t == 'E') - first = t+1; - } - break; - case 'T': - // Invalid mangled name per - // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html - break; - default: - { - // might be named type - const char* t = parse_type(first+1, last, db); - if (t != first+1 && t != last) - { - if (*t != 'E') - { - const char* n = t; - for (; n != last && isdigit(*n); ++n) - ; - if (n != t && n != last && *n == 'E') - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - db.Names.back(), StringView(t, n)); - first = n+1; - break; - } - } - else - { - first = t+1; - break; - } - } - } - } - } - return first; -} - Node* maybe_change_special_sub_name(Node* inp, Db& db) { if (inp->K != Node::KSpecialSubstitution) @@ -4762,631 +4800,6 @@ return first; } -// at # alignof (a type) - -const char* -parse_alignof_type(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'a' && first[1] == 't') - { - const char* t = parse_type(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make("alignof (", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// az # alignof (a expression) - -const char* -parse_alignof_expr(const char* first, const char* last, Db& db) -{ - if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') - { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make("alignof (", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -const char* -parse_noexcept_expression(const char* first, const char* last, Db& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make("noexcept (", db.Names.back(), ")"); - first = t1; - } - return first; -} - -const char* -parse_prefix_expression(const char* first, const char* last, StringView op, Db& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make(op, db.Names.back()); - first = t1; - } - return first; -} - -const char* -parse_binary_expression(const char* first, const char* last, StringView op, Db& db) -{ - const char* t1 = parse_expression(first, last, db); - if (t1 != first) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - if (db.Names.size() < 2) - return first; - auto op2 = db.Names.back(); - db.Names.pop_back(); - auto op1 = db.Names.back(); - db.Names.back() = db.make(op1, op, op2); - first = t2; - } - } - return first; -} - -// ::= -// ::= -// ::= -// ::= cl + E # call -// ::= cv # conversion with one argument -// ::= cv _ * E # conversion with a different number of arguments -// ::= [gs] nw * _ E # new (expr-list) type -// ::= [gs] nw * _ # new (expr-list) type (init) -// ::= [gs] na * _ E # new[] (expr-list) type -// ::= [gs] na * _ # new[] (expr-list) type (init) -// ::= [gs] dl # delete expression -// ::= [gs] da # delete[] expression -// ::= pp_ # prefix ++ -// ::= mm_ # prefix -- -// ::= ti # typeid (type) -// ::= te # typeid (expression) -// ::= dc # dynamic_cast (expression) -// ::= sc # static_cast (expression) -// ::= cc # const_cast (expression) -// ::= rc # reinterpret_cast (expression) -// ::= st # sizeof (a type) -// ::= sz # sizeof (an expression) -// ::= at # alignof (a type) -// ::= az # alignof (an expression) -// ::= nx # noexcept (expression) -// ::= -// ::= -// ::= dt # expr.name -// ::= pt # expr->name -// ::= ds # expr.*expr -// ::= sZ # size of a parameter pack -// ::= sZ # size of a function parameter pack -// ::= sp # pack expansion -// ::= tw # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= - -const char* -parse_expression(const char* first, const char* last, Db& db) -{ - if (last - first >= 2) - { - const char* t = first; - bool parsed_gs = false; - if (last - first >= 4 && t[0] == 'g' && t[1] == 's') - { - t += 2; - parsed_gs = true; - } - switch (*t) - { - case 'L': - first = parse_expr_primary(first, last, db); - break; - case 'T': - first = parse_template_param(first, last, db); - break; - case 'f': - first = parse_function_param(first, last, db); - break; - case 'a': - switch (t[1]) - { - case 'a': - t = parse_binary_expression(first+2, last, "&&", db); - if (t != first+2) - first = t; - break; - case 'd': - t = parse_prefix_expression(first+2, last, "&", db); - if (t != first+2) - first = t; - break; - case 'n': - t = parse_binary_expression(first+2, last, "&", db); - if (t != first+2) - first = t; - break; - case 'N': - t = parse_binary_expression(first+2, last, "&=", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, "=", db); - if (t != first+2) - first = t; - break; - case 't': - first = parse_alignof_type(first, last, db); - break; - case 'z': - first = parse_alignof_expr(first, last, db); - break; - } - break; - case 'c': - switch (t[1]) - { - case 'c': - first = parse_const_cast_expr(first, last, db); - break; - case 'l': - first = parse_call_expr(first, last, db); - break; - case 'm': - t = parse_binary_expression(first+2, last, ",", db); - if (t != first+2) - first = t; - break; - case 'o': - t = parse_prefix_expression(first+2, last, "~", db); - if (t != first+2) - first = t; - break; - case 'v': - first = parse_conversion_expr(first, last, db); - break; - } - break; - case 'd': - switch (t[1]) - { - case 'a': - { - const char* t1 = parse_expression(t+2, last, db); - if (t1 != t+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - db.Names.back(), parsed_gs, /*is_array=*/true); - first = t1; - } - } - break; - case 'c': - first = parse_dynamic_cast_expr(first, last, db); - break; - case 'e': - t = parse_prefix_expression(first+2, last, "*", db); - if (t != first+2) - first = t; - break; - case 'l': - { - const char* t1 = parse_expression(t+2, last, db); - if (t1 != t+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make( - db.Names.back(), parsed_gs, /*is_array=*/false); - first = t1; - } - } - break; - case 'n': - return parse_unresolved_name(first, last, db); - case 's': - first = parse_dot_star_expr(first, last, db); - break; - case 't': - first = parse_dot_expr(first, last, db); - break; - case 'v': - t = parse_binary_expression(first+2, last, "/", db); - if (t != first+2) - first = t; - break; - case 'V': - t = parse_binary_expression(first+2, last, "/=", db); - if (t != first+2) - first = t; - break; - } - break; - case 'e': - switch (t[1]) - { - case 'o': - t = parse_binary_expression(first+2, last, "^", db); - if (t != first+2) - first = t; - break; - case 'O': - t = parse_binary_expression(first+2, last, "^=", db); - if (t != first+2) - first = t; - break; - case 'q': - t = parse_binary_expression(first+2, last, "==", db); - if (t != first+2) - first = t; - break; - } - break; - case 'g': - switch (t[1]) - { - case 'e': - t = parse_binary_expression(first+2, last, ">=", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_binary_expression(first+2, last, ">", db); - if (t != first+2) - first = t; - break; - } - break; - case 'i': - if (t[1] == 'x') - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - if (db.Names.size() < 2) - return first; - auto op2 = db.Names.back(); - db.Names.pop_back(); - auto op1 = db.Names.back(); - db.Names.back() = - db.make(op1, op2); - first = t2; - } - else if (!db.Names.empty()) - db.Names.pop_back(); - } - } - break; - case 'l': - switch (t[1]) - { - case 'e': - t = parse_binary_expression(first+2, last, "<=", db); - if (t != first+2) - first = t; - break; - case 's': - t = parse_binary_expression(first+2, last, "<<", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, "<<=", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_binary_expression(first+2, last, "<", db); - if (t != first+2) - first = t; - break; - } - break; - case 'm': - switch (t[1]) - { - case 'i': - t = parse_binary_expression(first+2, last, "-", db); - if (t != first+2) - first = t; - break; - case 'I': - t = parse_binary_expression(first+2, last, "-=", db); - if (t != first+2) - first = t; - break; - case 'l': - t = parse_binary_expression(first+2, last, "*", db); - if (t != first+2) - first = t; - break; - case 'L': - t = parse_binary_expression(first+2, last, "*=", db); - if (t != first+2) - first = t; - break; - case 'm': - if (first+2 != last && first[2] == '_') - { - t = parse_prefix_expression(first+3, last, "--", db); - if (t != first+3) - first = t; - } - else - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make(db.Names.back(), "--"); - first = t1; - } - } - break; - } - break; - case 'n': - switch (t[1]) - { - case 'a': - case 'w': - first = parse_new_expr(first, last, db); - break; - case 'e': - t = parse_binary_expression(first+2, last, "!=", db); - if (t != first+2) - first = t; - break; - case 'g': - t = parse_prefix_expression(first+2, last, "-", db); - if (t != first+2) - first = t; - break; - case 't': - t = parse_prefix_expression(first+2, last, "!", db); - if (t != first+2) - first = t; - break; - case 'x': - t = parse_noexcept_expression(first+2, last, db); - if (t != first+2) - first = t; - break; - } - break; - case 'o': - switch (t[1]) - { - case 'n': - return parse_unresolved_name(first, last, db); - case 'o': - t = parse_binary_expression(first+2, last, "||", db); - if (t != first+2) - first = t; - break; - case 'r': - t = parse_binary_expression(first+2, last, "|", db); - if (t != first+2) - first = t; - break; - case 'R': - t = parse_binary_expression(first+2, last, "|=", db); - if (t != first+2) - first = t; - break; - } - break; - case 'p': - switch (t[1]) - { - case 'm': - t = parse_binary_expression(first+2, last, "->*", db); - if (t != first+2) - first = t; - break; - case 'l': - t = parse_binary_expression(first+2, last, "+", db); - if (t != first+2) - first = t; - break; - case 'L': - t = parse_binary_expression(first+2, last, "+=", db); - if (t != first+2) - first = t; - break; - case 'p': - if (first+2 != last && first[2] == '_') - { - t = parse_prefix_expression(first+3, last, "++", db); - if (t != first+3) - first = t; - } - else - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make(db.Names.back(), "++"); - first = t1; - } - } - break; - case 's': - t = parse_prefix_expression(first+2, last, "+", db); - if (t != first+2) - first = t; - break; - case 't': - first = parse_arrow_expr(first, last, db); - break; - } - break; - case 'q': - if (t[1] == 'u') - { - const char* t1 = parse_expression(first+2, last, db); - if (t1 != first+2) - { - const char* t2 = parse_expression(t1, last, db); - if (t2 != t1) - { - const char* t3 = parse_expression(t2, last, db); - if (t3 != t2) - { - if (db.Names.size() < 3) - return first; - auto op3 = db.Names.back(); - db.Names.pop_back(); - auto op2 = db.Names.back(); - db.Names.pop_back(); - auto op1 = db.Names.back(); - db.Names.back() = - db.make(op1, op2, op3); - first = t3; - } - else - { - if (db.Names.size() < 2) - return first; - db.Names.pop_back(); - db.Names.pop_back(); - } - } - else if (!db.Names.empty()) - db.Names.pop_back(); - } - } - break; - case 'r': - switch (t[1]) - { - case 'c': - first = parse_reinterpret_cast_expr(first, last, db); - break; - case 'm': - t = parse_binary_expression(first+2, last, "%", db); - if (t != first+2) - first = t; - break; - case 'M': - t = parse_binary_expression(first+2, last, "%=", db); - if (t != first+2) - first = t; - break; - case 's': - t = parse_binary_expression(first+2, last, ">>", db); - if (t != first+2) - first = t; - break; - case 'S': - t = parse_binary_expression(first+2, last, ">>=", db); - if (t != first+2) - first = t; - break; - } - break; - case 's': - switch (t[1]) - { - case 'c': - first = parse_static_cast_expr(first, last, db); - break; - case 'p': - first = parse_pack_expansion(first, last, db); - break; - case 'r': - return parse_unresolved_name(first, last, db); - case 't': - first = parse_sizeof_type_expr(first, last, db); - break; - case 'z': - first = parse_sizeof_expr_expr(first, last, db); - break; - case 'Z': - if (last - t >= 3) - { - switch (t[2]) - { - case 'T': - first = parse_sizeof_param_pack_expr(first, last, db); - break; - case 'f': - first = parse_sizeof_function_param_pack_expr(first, last, db); - break; - } - } - break; - } - break; - case 't': - switch (t[1]) - { - case 'e': - case 'i': - first = parse_typeid_expr(first, last, db); - break; - case 'r': - db.Names.push_back(db.make("throw")); - first += 2; - break; - case 'w': - first = parse_throw_expr(first, last, db); - break; - } - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return parse_unresolved_name(first, last, db); - } - } - return first; -} - // ::= # type or template // ::= X E # expression // ::= # simple expressions