HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Pie
|
9.0.0_r8
下载
查看原文件
收藏
根目录
external
swiftshader
third_party
llvm-subzero
lib
Demangle
ItaniumDemangle.cpp
//===- ItaniumDemangle.cpp ------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/Demangle/Demangle.h" // This file exports a single function: llvm::itanium_demangle. // It also has no dependencies on the rest of llvm. It is implemented this way // so that it can be easily reused in libcxxabi. #include
#include
#include
#include
#include
#include
#include
#ifdef _MSC_VER // snprintf is implemented in VS 2015 #if _MSC_VER < 1900 #define snprintf _snprintf_s #endif #endif enum { unknown_error = -4, invalid_args = -3, invalid_mangled_name, memory_alloc_failure, success }; template
static const char *parse_type(const char *first, const char *last, C &db); template
static const char *parse_encoding(const char *first, const char *last, C &db); template
static const char *parse_name(const char *first, const char *last, C &db, bool *ends_with_template_args = 0); template
static const char *parse_expression(const char *first, const char *last, C &db); template
static const char *parse_template_args(const char *first, const char *last, C &db); template
static const char *parse_operator_name(const char *first, const char *last, C &db); template
static const char *parse_unqualified_name(const char *first, const char *last, C &db); template
static const char *parse_decltype(const char *first, const char *last, C &db); //
::= [n]
static const char *parse_number(const char *first, const char *last) { if (first != last) { const char *t = first; if (*t == 'n') ++t; if (t != last) { if (*t == '0') { first = t + 1; } else if ('1' <= *t && *t <= '9') { first = t + 1; while (first != last && std::isdigit(*first)) ++first; } } } return first; } namespace { template
struct float_data; template <> struct float_data
{ static const size_t mangled_size = 8; static const size_t max_demangled_size = 24; static const char *spec; }; const char *float_data
::spec = "%af"; template <> struct float_data
{ static const size_t mangled_size = 16; static const size_t max_demangled_size = 32; static const char *spec; }; const char *float_data
::spec = "%a"; template <> struct float_data
{ #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ defined(__wasm__) static const size_t mangled_size = 32; #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) static const size_t mangled_size = 16; #else static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms #endif static const size_t max_demangled_size = 40; static const char *spec; }; const char *float_data
::spec = "%LaL"; } template
static const char *parse_floating_number(const char *first, const char *last, C &db) { const size_t N = float_data
::mangled_size; if (static_cast
(last - first) > N) { last = first + N; union { Float value; char buf[sizeof(Float)]; }; const char *t = first; char *e = buf; for (; t != last; ++t, ++e) { if (!isxdigit(*t)) return first; unsigned d1 = isdigit(*t) ? static_cast
(*t - '0') : static_cast
(*t - 'a' + 10); ++t; unsigned d0 = isdigit(*t) ? static_cast
(*t - '0') : static_cast
(*t - 'a' + 10); *e = static_cast
((d1 << 4) + d0); } if (*t == 'E') { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ std::reverse(buf, e); #endif char num[float_data
::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), float_data
::spec, value); if (static_cast
(n) >= sizeof(num)) return first; db.names.push_back(std::string(num, static_cast
(n))); first = t + 1; } } return first; } //
::=
template
static const char *parse_source_name(const char *first, const char *last, C &db) { if (first != last) { char c = *first; if (isdigit(c) && first + 1 != last) { const char *t = first + 1; size_t n = static_cast
(c - '0'); for (c = *t; isdigit(c); c = *t) { n = n * 10 + static_cast
(c - '0'); if (++t == last) return first; } if (static_cast
(last - t) >= n) { std::string r(t, n); if (r.substr(0, 10) == "_GLOBAL__N") db.names.push_back("(anonymous namespace)"); else db.names.push_back(std::move(r)); first = t + n; } } } return first; } //
::= S
_ // ::= S_ //
::= Sa # ::std::allocator //
::= Sb # ::std::basic_string //
::= Ss # ::std::basic_string < char, // ::std::char_traits
, // ::std::allocator
> //
::= Si # ::std::basic_istream
> //
::= So # ::std::basic_ostream
> //
::= Sd # ::std::basic_iostream
> template
static const char *parse_substitution(const char *first, const char *last, C &db) { if (last - first >= 2) { if (*first == 'S') { switch (first[1]) { case 'a': db.names.push_back("std::allocator"); first += 2; break; case 'b': db.names.push_back("std::basic_string"); first += 2; break; case 's': db.names.push_back("std::string"); first += 2; break; case 'i': db.names.push_back("std::istream"); first += 2; break; case 'o': db.names.push_back("std::ostream"); first += 2; break; case 'd': db.names.push_back("std::iostream"); first += 2; break; case '_': if (!db.subs.empty()) { for (const auto &n : db.subs.front()) db.names.push_back(n); first += 2; } break; default: if (std::isdigit(first[1]) || std::isupper(first[1])) { size_t sub = 0; const char *t = first + 1; if (std::isdigit(*t)) sub = static_cast
(*t - '0'); else sub = static_cast
(*t - 'A') + 10; for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t) { sub *= 36; if (std::isdigit(*t)) sub += static_cast
(*t - '0'); else sub += static_cast
(*t - 'A') + 10; } if (t == last || *t != '_') return first; ++sub; if (sub < db.subs.size()) { for (const auto &n : db.subs[sub]) db.names.push_back(n); first = t + 1; } } break; } } } return first; } //
::= v # void // ::= w # wchar_t // ::= b # bool // ::= c # char // ::= a # signed char // ::= h # unsigned char // ::= s # short // ::= t # unsigned short // ::= i # int // ::= j # unsigned int // ::= l # long // ::= m # unsigned long // ::= x # long long, __int64 // ::= y # unsigned long long, __int64 // ::= n # __int128 // ::= o # unsigned __int128 // ::= f # float // ::= d # double // ::= e # long double, __float80 // ::= g # __float128 // ::= z # ellipsis // ::= Dd # IEEE 754r decimal floating point (64 bits) // ::= De # IEEE 754r decimal floating point (128 bits) // ::= Df # IEEE 754r decimal floating point (32 bits) // ::= Dh # IEEE 754r half-precision floating point (16 bits) // ::= Di # char32_t // ::= Ds # char16_t // ::= Da # auto (in dependent new-expressions) // ::= Dc # decltype(auto) // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) // ::= u
# vendor extended type template
static const char *parse_builtin_type(const char *first, const char *last, C &db) { if (first != last) { switch (*first) { case 'v': db.names.push_back("void"); ++first; break; case 'w': db.names.push_back("wchar_t"); ++first; break; case 'b': db.names.push_back("bool"); ++first; break; case 'c': db.names.push_back("char"); ++first; break; case 'a': db.names.push_back("signed char"); ++first; break; case 'h': db.names.push_back("unsigned char"); ++first; break; case 's': db.names.push_back("short"); ++first; break; case 't': db.names.push_back("unsigned short"); ++first; break; case 'i': db.names.push_back("int"); ++first; break; case 'j': db.names.push_back("unsigned int"); ++first; break; case 'l': db.names.push_back("long"); ++first; break; case 'm': db.names.push_back("unsigned long"); ++first; break; case 'x': db.names.push_back("long long"); ++first; break; case 'y': db.names.push_back("unsigned long long"); ++first; break; case 'n': db.names.push_back("__int128"); ++first; break; case 'o': db.names.push_back("unsigned __int128"); ++first; break; case 'f': db.names.push_back("float"); ++first; break; case 'd': db.names.push_back("double"); ++first; break; case 'e': db.names.push_back("long double"); ++first; break; case 'g': db.names.push_back("__float128"); ++first; break; case 'z': db.names.push_back("..."); ++first; break; case 'u': { const char *t = parse_source_name(first + 1, last, db); if (t != first + 1) first = t; } break; case 'D': if (first + 1 != last) { switch (first[1]) { case 'd': db.names.push_back("decimal64"); first += 2; break; case 'e': db.names.push_back("decimal128"); first += 2; break; case 'f': db.names.push_back("decimal32"); first += 2; break; case 'h': db.names.push_back("decimal16"); first += 2; break; case 'i': db.names.push_back("char32_t"); first += 2; break; case 's': db.names.push_back("char16_t"); first += 2; break; case 'a': db.names.push_back("auto"); first += 2; break; case 'c': db.names.push_back("decltype(auto)"); first += 2; break; case 'n': db.names.push_back("std::nullptr_t"); first += 2; break; } } break; } } return first; } //
::= [r] [V] [K] static const char *parse_cv_qualifiers(const char *first, const char *last, unsigned &cv) { cv = 0; if (first != last) { if (*first == 'r') { cv |= 4; ++first; } if (*first == 'V') { cv |= 2; ++first; } if (*first == 'K') { cv |= 1; ++first; } } return first; } //
::= T_ # first template parameter // ::= T
_ template
static const char *parse_template_param(const char *first, const char *last, C &db) { if (last - first >= 2) { if (*first == 'T') { if (first[1] == '_') { if (db.template_param.empty()) return first; if (!db.template_param.back().empty()) { for (auto &t : db.template_param.back().front()) db.names.push_back(t); first += 2; } else { db.names.push_back("T_"); first += 2; db.fix_forward_references = true; } } else if (isdigit(first[1])) { const char *t = first + 1; size_t sub = static_cast
(*t - '0'); for (++t; t != last && isdigit(*t); ++t) { sub *= 10; sub += static_cast
(*t - '0'); } if (t == last || *t != '_' || db.template_param.empty()) return first; ++sub; if (sub < db.template_param.back().size()) { for (auto &temp : db.template_param.back()[sub]) db.names.push_back(temp); first = t + 1; } else { db.names.push_back(std::string(first, t + 1)); first = t + 1; db.fix_forward_references = true; } } } } return first; } // cc
# const_cast
// (expression) template
static const char *parse_const_cast_expr(const char *first, const char *last, C &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 expr = db.names.back().move_full(); db.names.pop_back(); if (db.names.empty()) return first; db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")"; first = t1; } } } return first; } // dc
# dynamic_cast
// (expression) template
static const char *parse_dynamic_cast_expr(const char *first, const char *last, C &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 expr = db.names.back().move_full(); db.names.pop_back(); if (db.names.empty()) return first; db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")"; first = t1; } } } return first; } // rc
# reinterpret_cast
// (expression) template
static const char *parse_reinterpret_cast_expr(const char *first, const char *last, C &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 expr = db.names.back().move_full(); db.names.pop_back(); if (db.names.empty()) return first; db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")"; first = t1; } } } return first; } // sc
# static_cast
// (expression) template
static const char *parse_static_cast_expr(const char *first, const char *last, C &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 expr = db.names.back().move_full(); db.names.pop_back(); db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")"; first = t1; } } } return first; } // sp
# pack expansion template
static const char *parse_pack_expansion(const char *first, const char *last, C &db) { if (last - first >= 3 && first[0] == 's' && first[1] == 'p') { const char *t = parse_expression(first + 2, last, db); if (t != first + 2) first = t; } return first; } // st
# sizeof (a type) template
static const char *parse_sizeof_type_expr(const char *first, const char *last, C &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() = "sizeof (" + db.names.back().move_full() + ")"; first = t; } } return first; } // sz
# sizeof (a expression) template
static const char *parse_sizeof_expr_expr(const char *first, const char *last, C &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() = "sizeof (" + db.names.back().move_full() + ")"; first = t; } } return first; } // sZ
# size of a parameter // pack template
static const char *parse_sizeof_param_pack_expr(const char *first, const char *last, C &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) { std::string tmp("sizeof...("); size_t k = k0; if (k != k1) { tmp += db.names[k].move_full(); for (++k; k != k1; ++k) tmp += ", " + db.names[k].move_full(); } tmp += ")"; for (; k1 != k0; --k1) db.names.pop_back(); db.names.push_back(std::move(tmp)); 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 template
static const char *parse_function_param(const char *first, const char *last, C &db) { if (last - first >= 3 && *first == 'f') { if (first[1] == 'p') { unsigned 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("fp" + std::string(t, t1)); first = t1 + 1; } } else if (first[1] == 'L') { unsigned 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("fp" + std::string(t, t1)); first = t1 + 1; } } } } return first; } // sZ
# size of a function // parameter pack template
static const char *parse_sizeof_function_param_pack_expr(const char *first, const char *last, C &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() = "sizeof...(" + db.names.back().move_full() + ")"; first = t; } } return first; } // te
# typeid (expression) // ti
# typeid (type) template
static const char *parse_typeid_expr(const char *first, const char *last, C &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() = "typeid(" + db.names.back().move_full() + ")"; first = t; } } return first; } // tw
# throw expression template
static const char *parse_throw_expr(const char *first, const char *last, C &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() = "throw " + db.names.back().move_full(); first = t; } } return first; } // ds
# expr.*expr template
static const char *parse_dot_star_expr(const char *first, const char *last, C &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 expr = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += ".*" + expr; first = t1; } } } return first; } //
::=
[
] template
static const char *parse_simple_id(const char *first, const char *last, C &db) { if (first != last) { const char *t = parse_source_name(first, last, db); if (t != first) { const char *t1 = parse_template_args(t, last, db); if (t1 != t) { if (db.names.size() < 2) return first; auto args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += std::move(args); } first = t1; } else first = t; } return first; } //
::=
// ::=
// ::=
template
static const char *parse_unresolved_type(const char *first, const char *last, C &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(typename C::sub_type(1, 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(typename C::sub_type(1, 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().first.insert(0, "std::"); db.subs.push_back(typename C::sub_type(1, db.names.back())); first = t; } } } break; } } return first; } //
::=
# e.g., // ~T or ~decltype(f()) // ::=
# e.g., // ~A<2*N> template
static const char *parse_destructor_name(const char *first, const char *last, C &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().first.insert(0, "~"); first = t; } } return first; } //
::=
# // unresolved name // extension ::=
# // unresolved operator-function-id // extension ::=
# // unresolved operator template-id // ::= on
# // unresolved operator-function-id // ::= on
# // unresolved operator template-id // ::= dn
# // destructor or pseudo-destructor; // # // e.g. // ~X or // ~X
template
static const char *parse_base_unresolved_name(const char *first, const char *last, C &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().move_full(); db.names.pop_back(); db.names.back().first += std::move(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().move_full(); db.names.pop_back(); db.names.back().first += std::move(args); } } } else first = t; } } return first; } //
::=
template
static const char *parse_unresolved_qualifier_level(const char *first, const char *last, C &db) { return parse_simple_id(first, last, db); } //
// extension ::= srN
[
] //
* E
// ::= [gs]
# x or // (with "gs") ::x // ::= [gs] sr
+ E //
// # A::x, // N::y, // A
::z; // "gs" // means // leading // "::" // ::= sr
# T::x // / decltype(p)::x // extension ::= sr
//
// # // T::N::x // /decltype(p)::N::x // (ignored) ::= srN
+ E //
template
static const char *parse_unresolved_name(const char *first, const char *last, C &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().first.insert(0, "::"); } 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().move_full(); db.names.pop_back(); db.names.back().first += std::move(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().move_full(); db.names.pop_back(); db.names.back().first += "::" + std::move(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().move_full(); db.names.pop_back(); db.names.back().first += "::" + std::move(s); first = t1; } else { t += 2; const char *t1 = parse_unresolved_type(t, last, db); if (t1 != t) { t = t1; t1 = parse_template_args(t, last, db); if (t1 != t) { if (db.names.size() < 2) return first; auto args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += std::move(args); t = t1; } 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().move_full(); db.names.pop_back(); db.names.back().first += "::" + std::move(s); first = t1; } else { t1 = parse_unresolved_qualifier_level(t, last, db); if (t1 == t || t1 == last) return first; t = t1; if (global) { if (db.names.empty()) return first; db.names.back().first.insert(0, "::"); } 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().move_full(); db.names.pop_back(); db.names.back().first += "::" + std::move(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().move_full(); db.names.pop_back(); db.names.back().first += "::" + std::move(s); first = t1; } } } } return first; } // dt
# expr.name template
static const char *parse_dot_expr(const char *first, const char *last, C &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().move_full(); db.names.pop_back(); if (db.names.empty()) return first; db.names.back().first += "." + name; first = t1; } } } return first; } // cl
+ E # call template
static const char *parse_call_expr(const char *first, const char *last, C &db) { if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') { const char *t = parse_expression(first + 2, last, db); if (t != first + 2) { if (t == last) return first; if (db.names.empty()) return first; db.names.back().first += db.names.back().second; db.names.back().second = std::string(); db.names.back().first.append("("); bool first_expr = true; while (*t != 'E') { const char *t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; if (db.names.empty()) return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); if (!tmp.empty()) { if (db.names.empty()) return first; if (!first_expr) { db.names.back().first.append(", "); first_expr = false; } db.names.back().first.append(tmp); } t = t1; } ++t; if (db.names.empty()) return first; db.names.back().first.append(")"); 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 template
static const char *parse_new_expr(const char *first, const char *last, C &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; bool has_expr_list = false; bool first_expr = true; while (*t != '_') { const char *t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; has_expr_list = true; if (!first_expr) { if (db.names.empty()) return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); if (!tmp.empty()) { if (db.names.empty()) return first; db.names.back().first.append(", "); db.names.back().first.append(tmp); first_expr = false; } } t = t1; } ++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; first_expr = true; while (*t != 'E') { t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; if (!first_expr) { if (db.names.empty()) return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); if (!tmp.empty()) { if (db.names.empty()) return first; db.names.back().first.append(", "); db.names.back().first.append(tmp); first_expr = false; } } t = t1; } } if (*t != 'E') return first; std::string init_list; if (has_init) { if (db.names.empty()) return first; init_list = db.names.back().move_full(); db.names.pop_back(); } if (db.names.empty()) return first; auto type = db.names.back().move_full(); db.names.pop_back(); std::string expr_list; if (has_expr_list) { if (db.names.empty()) return first; expr_list = db.names.back().move_full(); db.names.pop_back(); } std::string r; if (parsed_gs) r = "::"; if (is_array) r += "[] "; else r += " "; if (has_expr_list) r += "(" + expr_list + ") "; r += type; if (has_init) r += " (" + init_list + ")"; db.names.push_back(std::move(r)); first = t + 1; } } return first; } // cv
# conversion with one // argument // cv
_
* E # conversion with a // different number of arguments template
static const char *parse_conversion_expr(const char *first, const char *last, C &db) { if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') { bool try_to_parse_template_args = db.try_to_parse_template_args; db.try_to_parse_template_args = false; const char *t = parse_type(first + 2, last, db); db.try_to_parse_template_args = try_to_parse_template_args; if (t != first + 2 && t != last) { 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') db.names.emplace_back(); else { bool first_expr = true; while (*t != 'E') { const char *t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; if (!first_expr) { if (db.names.empty()) return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); if (!tmp.empty()) { if (db.names.empty()) return first; db.names.back().first.append(", "); db.names.back().first.append(tmp); first_expr = false; } } t = t1; } } ++t; } if (db.names.size() < 2) return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")"; first = t; } } return first; } // pt
# expr->name template
static const char *parse_arrow_expr(const char *first, const char *last, C &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().move_full(); db.names.pop_back(); db.names.back().first += "->"; db.names.back().first += tmp; first = t1; } } } return first; } //
::= R # & ref-qualifier //
::= O # && ref-qualifier //
::= F [Y]
[
] E template
static const char *parse_function_type(const char *first, const char *last, C &db) { if (first != last && *first == 'F') { const char *t = first + 1; if (t != last) { if (*t == 'Y') { /* extern "C" */ if (++t == last) return first; } const char *t1 = parse_type(t, last, db); if (t1 != t) { t = t1; std::string sig("("); int ref_qual = 0; while (true) { if (t == last) { db.names.pop_back(); return first; } if (*t == 'E') { ++t; break; } if (*t == 'v') { ++t; continue; } if (*t == 'R' && t + 1 != last && t[1] == 'E') { ref_qual = 1; ++t; continue; } if (*t == 'O' && t + 1 != last && t[1] == 'E') { ref_qual = 2; ++t; continue; } size_t k0 = db.names.size(); t1 = parse_type(t, last, db); size_t k1 = db.names.size(); if (t1 == t || t1 == last) return first; for (size_t k = k0; k < k1; ++k) { if (sig.size() > 1) sig += ", "; sig += db.names[k].move_full(); } for (size_t k = k0; k < k1; ++k) db.names.pop_back(); t = t1; } sig += ")"; switch (ref_qual) { case 1: sig += " &"; break; case 2: sig += " &&"; break; } if (db.names.empty()) return first; db.names.back().first += " "; db.names.back().second.insert(0, sig); first = t; } } } return first; } //
::= M
template
static const char *parse_pointer_to_member_type(const char *first, const char *last, C &db) { if (first != last && *first == 'M') { const char *t = parse_type(first + 1, last, db); if (t != first + 1) { const char *t2 = parse_type(t, last, db); if (t2 != t) { if (db.names.size() < 2) return first; auto func = std::move(db.names.back()); db.names.pop_back(); auto class_type = std::move(db.names.back()); if (!func.second.empty() && func.second.front() == '(') { db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*"; db.names.back().second = ")" + std::move(func.second); } else { db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*"; db.names.back().second = std::move(func.second); } first = t2; } } } return first; } //
::= A
_
// ::= A [
] _
template
static const char *parse_array_type(const char *first, const char *last, C &db) { if (first != last && *first == 'A' && first + 1 != last) { if (first[1] == '_') { const char *t = parse_type(first + 2, last, db); if (t != first + 2) { if (db.names.empty()) return first; if (db.names.back().second.substr(0, 2) == " [") db.names.back().second.erase(0, 1); db.names.back().second.insert(0, " []"); first = t; } } else if ('1' <= first[1] && first[1] <= '9') { const char *t = parse_number(first + 1, last); if (t != last && *t == '_') { const char *t2 = parse_type(t + 1, last, db); if (t2 != t + 1) { if (db.names.empty()) return first; if (db.names.back().second.substr(0, 2) == " [") db.names.back().second.erase(0, 1); db.names.back().second.insert(0, " [" + std::string(first + 1, t) + "]"); first = t2; } } } else { const char *t = parse_expression(first + 1, last, db); if (t != first + 1 && t != last && *t == '_') { const char *t2 = parse_type(++t, last, db); if (t2 != t) { if (db.names.size() < 2) return first; auto type = std::move(db.names.back()); db.names.pop_back(); auto expr = std::move(db.names.back()); db.names.back().first = std::move(type.first); if (type.second.substr(0, 2) == " [") type.second.erase(0, 1); db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second); first = t2; } } } } return first; } //
::= Dt
E # decltype of an id-expression or class // member access (C++0x) // ::= DT
E # decltype of an expression (C++0x) template
static const char *parse_decltype(const char *first, const char *last, C &db) { if (last - first >= 4 && first[0] == 'D') { switch (first[1]) { case 't': case 'T': { const char *t = parse_expression(first + 2, last, db); if (t != first + 2 && t != last && *t == 'E') { if (db.names.empty()) return first; db.names.back() = "decltype(" + db.names.back().move_full() + ")"; first = t + 1; } } break; } } return first; } // extension: //
::= Dv
_ //
// ::= Dv [
] _
//
::=
// ::= p # AltiVec vector pixel template
static const char *parse_vector_type(const char *first, const char *last, C &db) { if (last - first > 3 && first[0] == 'D' && first[1] == 'v') { if ('1' <= first[2] && first[2] <= '9') { const char *t = parse_number(first + 2, last); if (t == last || *t != '_') return first; const char *num = first + 2; size_t sz = static_cast
(t - num); if (++t != last) { if (*t != 'p') { const char *t1 = parse_type(t, last, db); if (t1 != t) { if (db.names.empty()) return first; db.names.back().first += " vector[" + std::string(num, sz) + "]"; first = t1; } } else { ++t; db.names.push_back("pixel vector[" + std::string(num, sz) + "]"); first = t; } } } else { std::string num; const char *t1 = first + 2; if (*t1 != '_') { const char *t = parse_expression(t1, last, db); if (t != t1) { if (db.names.empty()) return first; num = db.names.back().move_full(); db.names.pop_back(); t1 = t; } } if (t1 != last && *t1 == '_' && ++t1 != last) { const char *t = parse_type(t1, last, db); if (t != t1) { if (db.names.empty()) return first; db.names.back().first += " vector[" + num + "]"; first = t; } } } } return first; } //
::=
// ::=
// ::=
// ::=
// ::=
// ::=
// ::=
// ::=
// ::=
// ::=
// ::= P
# pointer-to // ::= R
# reference-to // ::= O
# rvalue reference-to (C++0x) // ::= C
# complex pair (C 2000) // ::= G
# imaginary (C 2000) // ::= Dp
# pack expansion (C++0x) // ::= U
# vendor extended type qualifier // extension := U
# objc-type
// extension :=
#
starts with Dv //
::=
objcproto
# k0 = 9 + //
+ k1 //
:=
# PU<11+>objcproto 11objc_object
// 11objc_object -> id
template
static const char *parse_type(const char *first, const char *last, C &db) { if (first != last) { switch (*first) { case 'r': case 'V': case 'K': { unsigned cv = 0; const char *t = parse_cv_qualifiers(first, last, cv); if (t != first) { bool is_function = *t == 'F'; size_t k0 = db.names.size(); const char *t1 = parse_type(t, last, db); size_t k1 = db.names.size(); if (t1 != t) { if (is_function) db.subs.pop_back(); db.subs.emplace_back(); for (size_t k = k0; k < k1; ++k) { if (is_function) { size_t p = db.names[k].second.size(); if (db.names[k].second[p - 2] == '&') p -= 3; else if (db.names[k].second.back() == '&') p -= 2; if (cv & 1) { db.names[k].second.insert(p, " const"); p += 6; } if (cv & 2) { db.names[k].second.insert(p, " volatile"); p += 9; } if (cv & 4) db.names[k].second.insert(p, " restrict"); } else { if (cv & 1) db.names[k].first.append(" const"); if (cv & 2) db.names[k].first.append(" volatile"); if (cv & 4) db.names[k].first.append(" restrict"); } db.subs.back().push_back(db.names[k]); } first = t1; } } } break; default: { const char *t = parse_builtin_type(first, last, db); if (t != first) { first = t; } else { switch (*first) { case 'A': t = parse_array_type(first, last, db); if (t != first) { if (db.names.empty()) return first; first = t; db.subs.push_back(typename C::sub_type(1, db.names.back())); } break; case 'C': t = parse_type(first + 1, last, db); if (t != first + 1) { if (db.names.empty()) return first; db.names.back().first.append(" complex"); first = t; db.subs.push_back(typename C::sub_type(1, db.names.back())); } break; case 'F': t = parse_function_type(first, last, db); if (t != first) { if (db.names.empty()) return first; first = t; db.subs.push_back(typename C::sub_type(1, db.names.back())); } break; case 'G': t = parse_type(first + 1, last, db); if (t != first + 1) { if (db.names.empty()) return first; db.names.back().first.append(" imaginary"); first = t; db.subs.push_back(typename C::sub_type(1, db.names.back())); } break; case 'M': t = parse_pointer_to_member_type(first, last, db); if (t != first) { if (db.names.empty()) return first; first = t; db.subs.push_back(typename C::sub_type(1, db.names.back())); } break; case 'O': { size_t k0 = db.names.size(); t = parse_type(first + 1, last, db); size_t k1 = db.names.size(); if (t != first + 1) { db.subs.emplace_back(); for (size_t k = k0; k < k1; ++k) { if (db.names[k].second.substr(0, 2) == " [") { db.names[k].first += " ("; db.names[k].second.insert(0, ")"); } else if (!db.names[k].second.empty() && db.names[k].second.front() == '(') { db.names[k].first += "("; db.names[k].second.insert(0, ")"); } db.names[k].first.append("&&"); db.subs.back().push_back(db.names[k]); } first = t; } break; } case 'P': { size_t k0 = db.names.size(); t = parse_type(first + 1, last, db); size_t k1 = db.names.size(); if (t != first + 1) { db.subs.emplace_back(); for (size_t k = k0; k < k1; ++k) { if (db.names[k].second.substr(0, 2) == " [") { db.names[k].first += " ("; db.names[k].second.insert(0, ")"); } else if (!db.names[k].second.empty() && db.names[k].second.front() == '(') { db.names[k].first += "("; db.names[k].second.insert(0, ")"); } if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<") { db.names[k].first.append("*"); } else { db.names[k].first.replace(0, 11, "id"); } db.subs.back().push_back(db.names[k]); } first = t; } break; } case 'R': { size_t k0 = db.names.size(); t = parse_type(first + 1, last, db); size_t k1 = db.names.size(); if (t != first + 1) { db.subs.emplace_back(); for (size_t k = k0; k < k1; ++k) { if (db.names[k].second.substr(0, 2) == " [") { db.names[k].first += " ("; db.names[k].second.insert(0, ")"); } else if (!db.names[k].second.empty() && db.names[k].second.front() == '(') { db.names[k].first += "("; db.names[k].second.insert(0, ")"); } db.names[k].first.append("&"); db.subs.back().push_back(db.names[k]); } first = t; } break; } case 'T': { size_t k0 = db.names.size(); t = parse_template_param(first, last, db); size_t k1 = db.names.size(); if (t != first) { db.subs.emplace_back(); for (size_t k = k0; k < k1; ++k) db.subs.back().push_back(db.names[k]); if (db.try_to_parse_template_args && k1 == k0 + 1) { const char *t1 = parse_template_args(t, last, db); if (t1 != t) { auto args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += std::move(args); db.subs.push_back(typename C::sub_type(1, db.names.back())); t = t1; } } first = t; } break; } case 'U': if (first + 1 != last) { t = parse_source_name(first + 1, last, db); if (t != first + 1) { const char *t2 = parse_type(t, last, db); if (t2 != t) { if (db.names.size() < 2) return first; auto type = db.names.back().move_full(); db.names.pop_back(); if (db.names.back().first.substr(0, 9) != "objcproto") { db.names.back() = type + " " + db.names.back().move_full(); } else { auto proto = db.names.back().move_full(); db.names.pop_back(); t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db); if (t != proto.data() + 9) { db.names.back() = type + "<" + db.names.back().move_full() + ">"; } else { db.names.push_back(type + " " + proto); } } db.subs.push_back(typename C::sub_type(1, db.names.back())); first = t2; } } } break; case 'S': if (first + 1 != last && first[1] == 't') { t = parse_name(first, last, db); if (t != first) { if (db.names.empty()) return first; db.subs.push_back(typename C::sub_type(1, db.names.back())); first = t; } } else { t = parse_substitution(first, last, db); if (t != first) { first = t; // Parsed a substitution. If the substitution is a //
it might be followed by
. t = parse_template_args(first, last, db); if (t != first) { if (db.names.size() < 2) return first; auto template_args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += template_args; // Need to create substitution for
//