erik.pilkington created this revision. erik.pilkington added reviewers: EricWF, mclow.lists, dexonsmith.
As of https://reviews.llvm.org/D41885, every parse_* function now either returns a single Node* or fails. I'm using this new rule to clean up the parsing for the demangler, and also update it to use LLVM coding conventions. This patch updates the expression parser. The expression grammer is pretty simple, so this patch is a pretty mechanical transformation. In the new parser: - The position in the mangled name is held in Db, and is accessed by Db::look() and Db::consume() functions - Parse functions now return a Node* directly instead of pushing a node onto the Name stack and having their caller immediately pop it off. - Failed to parse mean the parse functions returns nullptr. - LLVM style. Thanks for taking a look! Erik Repository: rCXXA libc++abi https://reviews.llvm.org/D41887 Files: src/cxa_demangle.cpp
Index: src/cxa_demangle.cpp =================================================================== --- src/cxa_demangle.cpp +++ src/cxa_demangle.cpp @@ -2062,65 +2062,850 @@ 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<Node*, 32> 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<Node*, 32> 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<Node *, 8> 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 <class T, class... Args> T* make(Args&& ...args) - { - return new (ASTAllocator.allocate(sizeof(T))) - T(std::forward<Args>(args)...); - } + const char *First; + const char *Last; - template <class It> NodeArray makeNodeArray(It begin, It end) - { - size_t sz = static_cast<size_t>(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<Node*, 32> 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<Node*, 32> 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<Node *, 8> 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 <class T, class... Args> T* make(Args&& ...args) + { + return new (ASTAllocator.allocate(sizeof(T))) + T(std::forward<Args>(args)...); + } + + template <class It> NodeArray makeNodeArray(It begin, It end) + { + size_t sz = static_cast<size_t>(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<size_t>(Last - First) <= Lookahead) + return '\0'; + return First[Lookahead]; + } + + size_t numLeft() const { return static_cast<size_t>(Last - First); } + + StringView parseNumber(bool AllowNegative = false); + Qualifiers parseCVQualifiers(); + + /// Parse the <expr> production. + Node *parseExpr(); + Node *parsePrefixExpr(StringView Kind); + Node *parseBinaryExpr(StringView Kind); + Node *parseIntegerLiteral(StringView Lit); + Node *parseExprPrimary(); + template <class Float> + Node *parseFloatingLiteral(); + Node *parseFunctionParam(); + Node *parseNewExpr(); + Node *parseConversionExpr(); + + // FIXME: remove this when all the parse_* functions have been rewritten. + template <const char *(*parse_fn)(const char *, const char *, Db &)> + 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&); + +// <number> ::= [n] <non-negative decimal integer> +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<PrefixExpr>(Kind, E); + // FIXME inline this +} + +Node *Db::parseBinaryExpr(StringView Kind) { + Node *LHS = parseExpr(); + if (LHS == nullptr) + return nullptr; + Node *RHS = parseExpr(); + if (RHS == nullptr) + return nullptr; + return make<BinaryExpr>(LHS, Kind, RHS); +} + +Node *Db::parseIntegerLiteral(StringView Lit) { + StringView Tmp = parseNumber(true); + if (!Tmp.empty() && consumeIf('E')) + return make<IntegerExpr>(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; +} + +// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter +// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters +// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter +// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters +Node *Db::parseFunctionParam() { + if (consumeIf("fp")) { + parseCVQualifiers(); + StringView Num = parseNumber(); + if (!consumeIf('_')) + return nullptr; + return make<FunctionParam>(Num); + } + if (consumeIf("fL")) { + if (parseNumber().empty()) + return nullptr; + if (!consumeIf('p')) + return nullptr; + parseCVQualifiers(); + StringView Num = parseNumber(); + if (!consumeIf('_')) + return nullptr; + return make<FunctionParam>(Num); + } + return nullptr; +} + +// [gs] nw <expression>* _ <type> E # new (expr-list) type +// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) +// [gs] na <expression>* _ <type> E # new[] (expr-list) type +// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) +// <initializer> ::= pi <expression>* 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<parse_type>(); + 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<NewExpr>(ExprList, Ty, Inits, Global, IsArray); + } + return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray); +} + +// cv <type> <expression> # conversion with one argument +// cv <type> _ <expression>* E # conversion with a different number of arguments +Node *Db::parseConversionExpr() { + if (!consumeIf("cv")) + return nullptr; + Node *Ty; + { + SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false); + Ty = legacyParse<parse_type>(); + } + + if (Ty == nullptr) + return nullptr; + + if (consumeIf('_')) { + size_t ExprsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = legacyParse<parse_type>(); + if (E == nullptr) + return E; + Names.push_back(E); + } + NodeArray Exprs = popTrailingNodeArray(ExprsBegin); + return make<ConversionExpr>(Ty, Exprs); + } + + Node *E = parseExpr(); + if (E == nullptr) + return nullptr; + return make<ConversionExpr>(Ty, makeNodeArray(&E, &E + 1)); +} + +// <expr-primary> ::= L <type> <value number> E # integer literal +// ::= L <type> <value float> E # floating literal +// ::= L <string type> E # string literal +// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE") +// FIXME: ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) +// ::= L <mangled-name> 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<BoolExpr>(0); + if (consumeIf("b1E")) + return make<BoolExpr>(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<float>(); + case 'd': + ++First; + return parseFloatingLiteral<double>(); + case 'e': + ++First; + return parseFloatingLiteral<long double>(); + case '_': + if (consumeIf("_Z")) { + Node *R = legacyParse<parse_encoding>(); + 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<parse_type>(); + if (T == nullptr) + return nullptr; + StringView N = parseNumber(); + if (!N.empty()) { + if (!consumeIf('E')) + return nullptr; + return make<IntegerCastExpr>(T, N); + } + if (consumeIf('E')) + return T; + return nullptr; + } + } +} + +// <expression> ::= <unary operator-name> <expression> +// ::= <binary operator-name> <expression> <expression> +// ::= <ternary operator-name> <expression> <expression> <expression> +// ::= cl <expression>+ E # call +// ::= cv <type> <expression> # conversion with one argument +// ::= cv <type> _ <expression>* E # conversion with a different number of arguments +// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type +// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) +// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type +// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) +// ::= [gs] dl <expression> # delete expression +// ::= [gs] da <expression> # delete[] expression +// ::= pp_ <expression> # prefix ++ +// ::= mm_ <expression> # prefix -- +// ::= ti <type> # typeid (type) +// ::= te <expression> # typeid (expression) +// ::= dc <type> <expression> # dynamic_cast<type> (expression) +// ::= sc <type> <expression> # static_cast<type> (expression) +// ::= cc <type> <expression> # const_cast<type> (expression) +// ::= rc <type> <expression> # reinterpret_cast<type> (expression) +// ::= st <type> # sizeof (a type) +// ::= sz <expression> # sizeof (an expression) +// ::= at <type> # alignof (a type) +// ::= az <expression> # alignof (an expression) +// ::= nx <expression> # noexcept (expression) +// ::= <template-param> +// ::= <function-param> +// ::= dt <expression> <unresolved-name> # expr.name +// ::= pt <expression> <unresolved-name> # expr->name +// ::= ds <expression> <expression> # expr.*expr +// ::= sZ <template-param> # size of a parameter pack +// ::= sZ <function-param> # size of a function parameter pack +// ::= sp <expression> # pack expansion +// ::= tw <expression> # throw expression +// ::= tr # throw with no operand (rethrow) +// ::= <unresolved-name> # f(p), N::f(p), ::f(p), +// # freestanding dependent name (e.g., T::x), +// # objectless nonstatic member reference +// ::= fL <binary-operator-name> <expression> <expression> +// ::= fR <binary-operator-name> <expression> <expression> +// ::= fl <binary-operator-name> <expression> +// ::= fr <binary-operator-name> <expression> +// ::= <expr-primary> +Node *Db::parseExpr() { + bool Global = consumeIf("gs"); + if (numLeft() < 2) + return nullptr; + + switch (*First) { + case 'L': return parseExprPrimary(); + case 'T': return legacyParse<parse_template_param>(); + 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<parse_type>(); + if (Ty == nullptr) + return nullptr; + return make<EnclosingExpr>("alignof (", Ty, ")"); + } + case 'z': { + First += 2; + Node *Ty = parseExpr(); + if (Ty == nullptr) + return nullptr; + return make<EnclosingExpr>("alignof (", Ty, ")"); + } + } + return nullptr; + case 'c': + switch (First[1]) { + // cc <type> <expression> # const_cast<type> (expression) + case 'c': { + First += 2; + Node *Ty = legacyParse<parse_type>(); + if (Ty == nullptr) + return Ty; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make<CastExpr>("const_cast", Ty, Ex); + } + // cl <expression>+ 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<CallExpr>(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<DeleteExpr>(Ex, Global, /*is_array=*/true); + } + case 'c': { + First += 2; + Node *T = legacyParse<parse_type>(); + if (T == nullptr) + return T; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make<CastExpr>("dynamic_cast", T, Ex); + } + case 'e': + First += 2; + return parsePrefixExpr("*"); + case 'l': { + First += 2; + Node *E = parseExpr(); + if (E == nullptr) + return E; + return make<DeleteExpr>(E, Global, /*is_array=*/false); + } + case 'n': { + First++; + return legacyParse<parse_unresolved_name>(); + } + case 's': { + First += 2; + Node *LHS = parseExpr(); + if (LHS == nullptr) + return nullptr; + Node *RHS = parseExpr(); + if (RHS == nullptr) + return nullptr; + return make<MemberExpr>(LHS, ".*", RHS); + } + case 't': { + First += 2; + Node *LHS = parseExpr(); + if (LHS == nullptr) + return LHS; + Node *RHS = parseExpr(); + if (RHS == nullptr) + return nullptr; + return make<MemberExpr>(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<ArraySubscriptExpr>(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<PostfixExpr>(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<EnclosingExpr>("noexcept (", Ex, ")"); + } + return nullptr; + case 'o': + switch (First[1]) { + case 'n': { + First += 2; + return legacyParse<parse_unresolved_name>(); + } + 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<PostfixExpr>(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<MemberExpr>(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<ConditionalExpr>(Cond, LHS, RHS); + } + return nullptr; + case 'r': + switch (First[1]) { + case 'c': { + First += 2; + Node *T = legacyParse<parse_type>(); + if (T == nullptr) + return T; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make<CastExpr>("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<parse_type>(); + if (T == nullptr) + return T; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make<CastExpr>("static_cast", T, Ex); + } + case 'p': { + First += 2; + Node *Child = parseExpr(); + if (Child == nullptr) + return nullptr; + return make<ParameterPackExpansion>(Child); + } + case 'r': { + return legacyParse<parse_unresolved_name>(); + } + case 't': { + First += 2; + Node *Ty = legacyParse<parse_type>(); + if (Ty == nullptr) + return Ty; + return make<EnclosingExpr>("sizeof (", Ty, ")"); + } + case 'z': { + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return Ex; + return make<EnclosingExpr>("sizeof (", Ex, ")"); + } + case 'Z': + First += 2; + if (look() == 'T') { + Node *R = legacyParse<parse_template_param>(); + if (R == nullptr) + return nullptr; + return make<SizeofParamPackExpr>(R); + } else if (look() == 'f') { + Node *FP = parseFunctionParam(); + if (FP == nullptr) + return nullptr; + return make<EnclosingExpr>("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<EnclosingExpr>("typeid (", Ex, ")"); + } + case 'i': { + First += 2; + Node *Ty = legacyParse<parse_type>(); + if (Ty == nullptr) + return Ty; + return make<EnclosingExpr>("typeid(", Ty, ")"); + } + case 'r': + First += 2; + return make<NameType>("throw"); + case 'w': { + First += 2; + Node *Ex = parseExpr(); + if (Ex == nullptr) + return nullptr; + return make<ThrowExpr>(Ex); + } + } + return nullptr; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + return legacyParse<parse_unresolved_name>(); + } + } + return nullptr; +} // <number> ::= [n] <non-negative decimal integer> @@ -2190,26 +2975,18 @@ constexpr const char* FloatData<long double>::spec; template <class Float> -const char* -parse_floating_number(const char* first, const char* last, Db& db) -{ - const size_t N = FloatData<Float>::mangled_size; - if (static_cast<std::size_t>(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<FloatExpr<Float>>(StringView(first, t))); - first = t + 1; - } - return first; +Node *Db::parseFloatingLiteral() { + const size_t N = FloatData<Float>::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<FloatExpr<Float>>(Data); } // <positive length number> ::= [0-9]* @@ -2630,602 +3407,282 @@ return first; } -// cc <type> <expression> # const_cast<type> (expression) +// <simple-id> ::= <source-name> [ <template-args> ] const char* -parse_const_cast_expr(const char* first, const char* last, Db& db) +parse_simple_id(const char* first, const char* last, Db& db) { - if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') + if (first != last) { - const char* t = parse_type(first+2, last, db); - if (t != first+2) + const char* t = parse_source_name(first, last, db); + if (t != first) { - const char* t1 = parse_expression(t, last, db); + const char* t1 = parse_template_args(t, last, db); if (t1 != t) { if (db.Names.size() < 2) return first; - auto from_expr = db.Names.back(); + auto args = db.Names.back(); db.Names.pop_back(); - if (db.Names.empty()) - return first; - db.Names.back() = db.make<CastExpr>( - "const_cast", db.Names.back(), from_expr); - first = t1; + db.Names.back() = + db.make<NameWithTemplateArgs>(db.Names.back(), args); } + first = t1; } + else + first = t; } return first; } -// dc <type> <expression> # dynamic_cast<type> (expression) +// <unresolved-type> ::= <template-param> +// ::= <decltype> +// ::= <substitution> const char* -parse_dynamic_cast_expr(const char* first, const char* last, Db& db) +parse_unresolved_type(const char* first, const char* last, Db& db) { - if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') + if (first != last) { - const char* t = parse_type(first+2, last, db); - if (t != first+2) + const char* t = first; + switch (*first) { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) + case 'T': + { + size_t k0 = db.Names.size(); + t = parse_template_param(first, last, db); + size_t k1 = db.Names.size(); + if (t != first && k1 == k0 + 1) + { + db.Subs.push_back(db.Names.back()); + first = t; + } + else + { + for (; k1 != k0; --k1) + db.Names.pop_back(); + } + break; + } + case 'D': + t = parse_decltype(first, last, db); + if (t != first) { - 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<CastExpr>( - "dynamic_cast", db.Names.back(), from_expr); - first = t1; + db.Subs.push_back(db.Names.back()); + first = t; } - } + break; + case 'S': + t = parse_substitution(first, last, db); + if (t != first) + first = t; + else + { + if (last - first > 2 && first[1] == 't') + { + t = parse_unqualified_name(first+2, last, db); + if (t != first+2) + { + if (db.Names.empty()) + return first; + db.Names.back() = + db.make<StdQualifiedName>(db.Names.back()); + db.Subs.push_back(db.Names.back()); + first = t; + } + } + } + break; + } } return first; } -// rc <type> <expression> # reinterpret_cast<type> (expression) +// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) +// ::= <simple-id> # e.g., ~A<2*N> const char* -parse_reinterpret_cast_expr(const char* first, const char* last, Db& db) +parse_destructor_name(const char* first, const char* last, Db& db) { - if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') + if (first != last) { - 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<CastExpr>( - "reinterpret_cast", db.Names.back(), from_expr); - first = t1; - } - } - } - return first; -} - -// sc <type> <expression> # static_cast<type> (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<CastExpr>( - "static_cast", db.Names.back(), from_expr); - first = t1; - } - } - } - return first; -} - -// sp <expression> # 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<ParameterPackExpansion>(db.Names.back()); - } - return first; -} - -// st <type> # 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<EnclosingExpr>( - "sizeof (", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// sz <expr> # 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) + const char* t = parse_unresolved_type(first, last, db); + if (t == first) + t = parse_simple_id(first, last, db); + if (t != first) { if (db.Names.empty()) return first; - db.Names.back() = db.make<EnclosingExpr>( - "sizeof (", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// sZ <template-param> # 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<SizeofParamPackExpr>(db.Names.back()); + db.Names.back() = db.make<DtorName>(db.Names.back()); first = t; } } return first; } -// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter -// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters -// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter -// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters +// <base-unresolved-name> ::= <simple-id> # unresolved name +// extension ::= <operator-name> # unresolved operator-function-id +// extension ::= <operator-name> <template-args> # unresolved operator template-id +// ::= on <operator-name> # unresolved operator-function-id +// ::= on <operator-name> <template-args> # unresolved operator template-id +// ::= dn <destructor-name> # destructor or pseudo-destructor; +// # e.g. ~X or ~X<N-1> const char* -parse_function_param(const char* first, const char* last, Db& db) +parse_base_unresolved_name(const char* first, const char* last, Db& db) { - if (last - first >= 3 && *first == 'f') + if (last - first >= 2) { - if (first[1] == 'p') + if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') { - Qualifiers cv; - const char* t = parse_cv_qualifiers(first+2, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') + if (first[0] == 'o') { - db.Names.push_back( - db.make<FunctionParam>(StringView(t, t1))); - first = t1+1; + const char* t = parse_operator_name(first+2, last, db); + if (t != first+2) + { + first = parse_template_args(t, last, db); + if (first != t) + { + if (db.Names.size() < 2) + return first; + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), args); + } + } + } + else + { + const char* t = parse_destructor_name(first+2, last, db); + if (t != first+2) + first = t; } } - else if (first[1] == 'L') + else { - Qualifiers cv; - const char* t0 = parse_number(first+2, last); - if (t0 != last && *t0 == 'p') + const char* t = parse_simple_id(first, last, db); + if (t == first) { - ++t0; - const char* t = parse_cv_qualifiers(t0, last, cv); - const char* t1 = parse_number(t, last); - if (t1 != last && *t1 == '_') + t = parse_operator_name(first, last, db); + if (t != first) { - db.Names.push_back( - db.make<FunctionParam>(StringView(t, t1))); - first = t1+1; + first = parse_template_args(t, last, db); + if (first != t) + { + if (db.Names.size() < 2) + return first; + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<NameWithTemplateArgs>( + db.Names.back(), args); + } } } + else + first = t; } } return first; } -// sZ <function-param> # 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<EnclosingExpr>( - "sizeof...(", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// te <expression> # typeid (expression) -// ti <type> # typeid (type) +// <unresolved-qualifier-level> ::= <simple-id> const char* -parse_typeid_expr(const char* first, const char* last, Db& db) +parse_unresolved_qualifier_level(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<EnclosingExpr>( - "typeid(", db.Names.back(), ")"); - first = t; - } - } - return first; + return parse_simple_id(first, last, db); } -// tw <expression> # throw expression +// <unresolved-name> +// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> +// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x +// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> +// # A::x, N::y, A<T>::z; "gs" means leading "::" +// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x +// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name> +// # T::N::x /decltype(p)::N::x +// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> const char* -parse_throw_expr(const char* first, const char* last, Db& db) +parse_unresolved_name(const char* first, const char* last, Db& db) { - if (last - first >= 3 && first[0] == 't' && first[1] == 'w') + if (last - first > 2) { - const char* t = parse_expression(first+2, last, db); - if (t != first+2) + const char* t = first; + bool global = false; + if (t[0] == 'g' && t[1] == 's') { - if (db.Names.empty()) - return first; - db.Names.back() = db.make<ThrowExpr>(db.Names.back()); - first = t; + global = true; + t += 2; } - } - return first; -} - -// ds <expression> <expression> # 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* t2 = parse_base_unresolved_name(t, last, db); + if (t2 != t) { - const char* t1 = parse_expression(t, last, db); - if (t1 != t) + if (global) { - if (db.Names.size() < 2) + if (db.Names.empty()) return first; - auto rhs_expr = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make<MemberExpr>( - db.Names.back(), ".*", rhs_expr); - first = t1; + db.Names.back() = + db.make<GlobalQualifiedName>(db.Names.back()); } + first = t2; } - } - return first; -} - -// <simple-id> ::= <source-name> [ <template-args> ] - -const char* -parse_simple_id(const char* first, const char* last, Db& db) -{ - if (first != last) - { - const char* t = parse_source_name(first, last, db); - if (t != first) + else if (last - t > 2 && t[0] == 's' && t[1] == 'r') { - const char* t1 = parse_template_args(t, last, db); - if (t1 != t) + if (t[2] == 'N') { + t += 3; + const char* t1 = parse_unresolved_type(t, last, db); + if (t1 == t || t1 == last) + return first; + t = t1; + t1 = parse_template_args(t, last, db); + if (t1 != t) + { + if (db.Names.size() < 2) + return first; + auto args = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = db.make<NameWithTemplateArgs>( + db.Names.back(), args); + t = t1; + if (t == last) + { + db.Names.pop_back(); + return first; + } + } + while (*t != 'E') + { + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last || db.Names.size() < 2) + return first; + auto s = db.Names.back(); + db.Names.pop_back(); + db.Names.back() = + db.make<QualifiedName>(db.Names.back(), s); + t = t1; + } + ++t; + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) + { + if (!db.Names.empty()) + db.Names.pop_back(); + return first; + } if (db.Names.size() < 2) return first; - auto args = db.Names.back(); + auto s = db.Names.back(); db.Names.pop_back(); db.Names.back() = - db.make<NameWithTemplateArgs>(db.Names.back(), args); - } - first = t1; - } - else - first = t; - } - return first; -} - -// <unresolved-type> ::= <template-param> -// ::= <decltype> -// ::= <substitution> - -const char* -parse_unresolved_type(const char* first, const char* last, Db& db) -{ - if (first != last) - { - const char* t = first; - switch (*first) - { - case 'T': - { - size_t k0 = db.Names.size(); - t = parse_template_param(first, last, db); - size_t k1 = db.Names.size(); - if (t != first && k1 == k0 + 1) - { - db.Subs.push_back(db.Names.back()); - first = t; - } - else - { - for (; k1 != k0; --k1) - db.Names.pop_back(); - } - break; - } - case 'D': - t = parse_decltype(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - db.Subs.push_back(db.Names.back()); - first = t; - } - break; - case 'S': - t = parse_substitution(first, last, db); - if (t != first) - first = t; - else - { - if (last - first > 2 && first[1] == 't') - { - t = parse_unqualified_name(first+2, last, db); - if (t != first+2) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make<StdQualifiedName>(db.Names.back()); - db.Subs.push_back(db.Names.back()); - first = t; - } - } - } - break; - } - } - return first; -} - -// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) -// ::= <simple-id> # e.g., ~A<2*N> - -const char* -parse_destructor_name(const char* first, const char* last, Db& db) -{ - if (first != last) - { - const char* t = parse_unresolved_type(first, last, db); - if (t == first) - t = parse_simple_id(first, last, db); - if (t != first) - { - if (db.Names.empty()) - return first; - db.Names.back() = db.make<DtorName>(db.Names.back()); - first = t; - } - } - return first; -} - -// <base-unresolved-name> ::= <simple-id> # unresolved name -// extension ::= <operator-name> # unresolved operator-function-id -// extension ::= <operator-name> <template-args> # unresolved operator template-id -// ::= on <operator-name> # unresolved operator-function-id -// ::= on <operator-name> <template-args> # unresolved operator template-id -// ::= dn <destructor-name> # destructor or pseudo-destructor; -// # e.g. ~X or ~X<N-1> - -const char* -parse_base_unresolved_name(const char* first, const char* last, Db& db) -{ - if (last - first >= 2) - { - if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') - { - if (first[0] == 'o') - { - const char* t = parse_operator_name(first+2, last, db); - if (t != first+2) - { - first = parse_template_args(t, last, db); - if (first != t) - { - if (db.Names.size() < 2) - return first; - auto args = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = - db.make<NameWithTemplateArgs>( - db.Names.back(), args); - } - } - } - else - { - const char* t = parse_destructor_name(first+2, last, db); - if (t != first+2) - first = t; - } - } - else - { - const char* t = parse_simple_id(first, last, db); - if (t == first) - { - t = parse_operator_name(first, last, db); - if (t != first) - { - first = parse_template_args(t, last, db); - if (first != t) - { - if (db.Names.size() < 2) - return first; - auto args = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = - db.make<NameWithTemplateArgs>( - db.Names.back(), args); - } - } - } - else - first = t; - } - } - return first; -} - -// <unresolved-qualifier-level> ::= <simple-id> - -const char* -parse_unresolved_qualifier_level(const char* first, const char* last, Db& db) -{ - return parse_simple_id(first, last, db); -} - -// <unresolved-name> -// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> -// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x -// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> -// # A::x, N::y, A<T>::z; "gs" means leading "::" -// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x -// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name> -// # T::N::x /decltype(p)::N::x -// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> - -const char* -parse_unresolved_name(const char* first, const char* last, Db& db) -{ - if (last - first > 2) - { - const char* t = first; - bool global = false; - if (t[0] == 'g' && t[1] == 's') - { - global = true; - t += 2; - } - const char* t2 = parse_base_unresolved_name(t, last, db); - if (t2 != t) - { - if (global) - { - if (db.Names.empty()) - return first; - db.Names.back() = - db.make<GlobalQualifiedName>(db.Names.back()); - } - first = t2; - } - else if (last - t > 2 && t[0] == 's' && t[1] == 'r') - { - if (t[2] == 'N') - { - t += 3; - const char* t1 = parse_unresolved_type(t, last, db); - if (t1 == t || t1 == last) - return first; - t = t1; - t1 = parse_template_args(t, last, db); - if (t1 != t) - { - if (db.Names.size() < 2) - return first; - auto args = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = db.make<NameWithTemplateArgs>( - db.Names.back(), args); - t = t1; - if (t == last) - { - db.Names.pop_back(); - return first; - } - } - while (*t != 'E') - { - t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last || db.Names.size() < 2) - return first; - auto s = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = - db.make<QualifiedName>(db.Names.back(), s); - t = t1; - } - ++t; - t1 = parse_base_unresolved_name(t, last, db); - if (t1 == t) - { - if (!db.Names.empty()) - db.Names.pop_back(); - return first; - } - if (db.Names.size() < 2) - return first; - auto s = db.Names.back(); - db.Names.pop_back(); - db.Names.back() = - db.make<QualifiedName>(db.Names.back(), s); - first = t1; + db.make<QualifiedName>(db.Names.back(), s); + first = t1; } else { @@ -3308,220 +3765,10 @@ return first; } -// dt <expression> <unresolved-name> # 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<MemberExpr>(db.Names.back(), ".", name); - first = t1; - } - } - } - return first; -} - -// cl <expression>+ 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<CallExpr>( - callee, db.popTrailingNodeArray(args_begin)); - db.Names.push_back(the_call); - first = t; - } - return first; -} - -// [gs] nw <expression>* _ <type> E # new (expr-list) type -// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) -// [gs] na <expression>* _ <type> E # new[] (expr-list) type -// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) -// <initializer> ::= pi <expression>* 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<NewExpr>(ExprList, type, init_list, - parsed_gs, is_array)); - first = t+1; - } - } - return first; -} - -// cv <type> <expression> # conversion with one argument -// cv <type> _ <expression>* 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<ConversionExpr>( - db.Names[type_index], expressions); - db.Names.dropBack(type_index); - db.Names.push_back(conv_expr); - first = t; - } - } - return first; -} - -// pt <expression> <expression> # 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<MemberExpr>( - db.Names.back(), "->", tmp); - first = t1; - } - } - } - return first; -} - -// <ref-qualifier> ::= R # & ref-qualifier -// <ref-qualifier> ::= O # && ref-qualifier - -// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E +// <ref-qualifier> ::= R # & ref-qualifier +// <ref-qualifier> ::= O # && ref-qualifier + +// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E const char* parse_function_type(const char* first, const char* last, Db& db) @@ -4498,329 +4745,122 @@ return first; } -const char* -parse_integer_literal(const char* first, const char* last, StringView lit, Db& db) +Node* maybe_change_special_sub_name(Node* inp, Db& db) { - const char* t = parse_number(first, last); - if (t != first && t != last && *t == 'E') + if (inp->K != Node::KSpecialSubstitution) + return inp; + auto Kind = static_cast<SpecialSubstitution*>(inp)->SSK; + switch (Kind) { - db.Names.push_back( - db.make<IntegerExpr>(lit, StringView(first, t))); - first = t+1; + case SpecialSubKind::string: + case SpecialSubKind::istream: + case SpecialSubKind::ostream: + case SpecialSubKind::iostream: + return db.make<ExpandedSpecialSubstitution>(Kind); + default: + break; } - return first; + return inp; } -// <expr-primary> ::= L <type> <value number> E # integer literal -// ::= L <type> <value float> E # floating literal -// ::= L <string type> E # string literal -// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE") -// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) -// ::= L <mangled-name> E # external name - +// <ctor-dtor-name> ::= C1 # complete object constructor +// ::= C2 # base object constructor +// ::= C3 # complete object allocating constructor +// extension ::= C5 # ? +// ::= D0 # deleting destructor +// ::= D1 # complete object destructor +// ::= D2 # base object destructor +// extension ::= D5 # ? +// extension ::= <ctor-dtor-name> <abi-tag-seq> const char* -parse_expr_primary(const char* first, const char* last, Db& db) +parse_ctor_dtor_name(const char* first, const char* last, Db& db) { - if (last - first >= 4 && *first == 'L') + if (last-first >= 2 && !db.Names.empty()) { - switch (first[1]) + switch (first[0]) { - case 'w': + case 'C': + switch (first[1]) { - const char* t = parse_integer_literal(first+2, last, "wchar_t", db); - if (t != first+2) - first = t; + case '1': + case '2': + case '3': + case '5': + if (db.Names.empty()) + return first; + db.Names.back() = + maybe_change_special_sub_name(db.Names.back(), db); + db.Names.push_back( + db.make<CtorDtorName>(db.Names.back(), false)); + first += 2; + first = parse_abi_tag_seq(first, last, db); + db.ParsedCtorDtorCV = true; + break; } break; - case 'b': - if (first[3] == 'E') + case 'D': + switch (first[1]) { - switch (first[2]) - { - case '0': - db.Names.push_back(db.make<BoolExpr>(0)); - first += 4; - break; - case '1': - db.Names.push_back(db.make<BoolExpr>(1)); - first += 4; - break; - } + case '0': + case '1': + case '2': + case '5': + if (db.Names.empty()) + return first; + db.Names.push_back( + db.make<CtorDtorName>(db.Names.back(), true)); + first += 2; + first = parse_abi_tag_seq(first, last, db); + db.ParsedCtorDtorCV = true; + break; } break; - case 'c': + } + } + return first; +} + +// <unnamed-type-name> ::= Ut [<nonnegative number>] _ [<abi-tag-seq>] +// ::= <closure-type-name> +// +// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ +// +// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters +const char* +parse_unnamed_type_name(const char* first, const char* last, Db& db) +{ + if (last - first > 2 && first[0] == 'U') + { + char type = first[1]; + switch (type) + { + case 't': + { + const char* t0 = first+2; + if (t0 == last) + return first; + StringView count; + if (std::isdigit(*t0)) { - const char* t = parse_integer_literal(first+2, last, "char", db); - if (t != first+2) - first = t; + const char* t1 = t0 + 1; + while (t1 != last && std::isdigit(*t1)) + ++t1; + count = StringView(t0, t1); + t0 = t1; } + if (t0 == last || *t0 != '_') + return first; + db.Names.push_back(db.make<UnnamedTypeName>(count)); + first = t0 + 1; + first = parse_abi_tag_seq(first, last, db); + } 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<float>(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'd': - { - const char* t = parse_floating_number<double>(first+2, last, db); - if (t != first+2) - first = t; - } - break; - case 'e': - { - const char* t = parse_floating_number<long double>(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<IntegerCastExpr>( - 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) - return inp; - auto Kind = static_cast<SpecialSubstitution*>(inp)->SSK; - switch (Kind) - { - case SpecialSubKind::string: - case SpecialSubKind::istream: - case SpecialSubKind::ostream: - case SpecialSubKind::iostream: - return db.make<ExpandedSpecialSubstitution>(Kind); - default: - break; - } - return inp; -} - -// <ctor-dtor-name> ::= C1 # complete object constructor -// ::= C2 # base object constructor -// ::= C3 # complete object allocating constructor -// extension ::= C5 # ? -// ::= D0 # deleting destructor -// ::= D1 # complete object destructor -// ::= D2 # base object destructor -// extension ::= D5 # ? -// extension ::= <ctor-dtor-name> <abi-tag-seq> -const char* -parse_ctor_dtor_name(const char* first, const char* last, Db& db) -{ - if (last-first >= 2 && !db.Names.empty()) - { - switch (first[0]) - { - case 'C': - switch (first[1]) - { - case '1': - case '2': - case '3': - case '5': - if (db.Names.empty()) - return first; - db.Names.back() = - maybe_change_special_sub_name(db.Names.back(), db); - db.Names.push_back( - db.make<CtorDtorName>(db.Names.back(), false)); - first += 2; - first = parse_abi_tag_seq(first, last, db); - db.ParsedCtorDtorCV = true; - break; - } - break; - case 'D': - switch (first[1]) - { - case '0': - case '1': - case '2': - case '5': - if (db.Names.empty()) - return first; - db.Names.push_back( - db.make<CtorDtorName>(db.Names.back(), true)); - first += 2; - first = parse_abi_tag_seq(first, last, db); - db.ParsedCtorDtorCV = true; - break; - } - break; - } - } - return first; -} - -// <unnamed-type-name> ::= Ut [<nonnegative number>] _ [<abi-tag-seq>] -// ::= <closure-type-name> -// -// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ -// -// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters -const char* -parse_unnamed_type_name(const char* first, const char* last, Db& db) -{ - if (last - first > 2 && first[0] == 'U') - { - char type = first[1]; - switch (type) - { - case 't': - { - const char* t0 = first+2; - if (t0 == last) - return first; - StringView count; - if (std::isdigit(*t0)) - { - const char* t1 = t0 + 1; - while (t1 != last && std::isdigit(*t1)) - ++t1; - count = StringView(t0, t1); - t0 = t1; - } - if (t0 == last || *t0 != '_') - return first; - db.Names.push_back(db.make<UnnamedTypeName>(count)); - first = t0 + 1; - first = parse_abi_tag_seq(first, last, db); - } - break; - case 'l': - { - size_t begin_pos = db.Names.size(); - const char* t0 = first+2; - NodeArray lambda_params; - if (first[2] == 'v') + case 'l': + { + size_t begin_pos = db.Names.size(); + const char* t0 = first+2; + NodeArray lambda_params; + if (first[2] == 'v') { ++t0; } @@ -4943,631 +4983,6 @@ return first; } -// at <type> # 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<EnclosingExpr>("alignof (", db.Names.back(), ")"); - first = t; - } - } - return first; -} - -// az <expression> # 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<EnclosingExpr>("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<EnclosingExpr>("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<PrefixExpr>(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<BinaryExpr>(op1, op, op2); - first = t2; - } - } - return first; -} - -// <expression> ::= <unary operator-name> <expression> -// ::= <binary operator-name> <expression> <expression> -// ::= <ternary operator-name> <expression> <expression> <expression> -// ::= cl <expression>+ E # call -// ::= cv <type> <expression> # conversion with one argument -// ::= cv <type> _ <expression>* E # conversion with a different number of arguments -// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type -// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) -// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type -// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) -// ::= [gs] dl <expression> # delete expression -// ::= [gs] da <expression> # delete[] expression -// ::= pp_ <expression> # prefix ++ -// ::= mm_ <expression> # prefix -- -// ::= ti <type> # typeid (type) -// ::= te <expression> # typeid (expression) -// ::= dc <type> <expression> # dynamic_cast<type> (expression) -// ::= sc <type> <expression> # static_cast<type> (expression) -// ::= cc <type> <expression> # const_cast<type> (expression) -// ::= rc <type> <expression> # reinterpret_cast<type> (expression) -// ::= st <type> # sizeof (a type) -// ::= sz <expression> # sizeof (an expression) -// ::= at <type> # alignof (a type) -// ::= az <expression> # alignof (an expression) -// ::= nx <expression> # noexcept (expression) -// ::= <template-param> -// ::= <function-param> -// ::= dt <expression> <unresolved-name> # expr.name -// ::= pt <expression> <unresolved-name> # expr->name -// ::= ds <expression> <expression> # expr.*expr -// ::= sZ <template-param> # size of a parameter pack -// ::= sZ <function-param> # size of a function parameter pack -// ::= sp <expression> # pack expansion -// ::= tw <expression> # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= <unresolved-name> # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= <expr-primary> - -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<DeleteExpr>( - 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<DeleteExpr>( - 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<ArraySubscriptExpr>(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<PostfixExpr>(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<PostfixExpr>(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<ConditionalExpr>(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<NameType>("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; -} - // <template-arg> ::= <type> # type or template // ::= X <expression> E # expression // ::= <expr-primary> # simple expressions
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits