Commit 3ae5baa1 authored by 's avatar

Reduce stack consumption for Demangle(). Fixes issue 81.


git-svn-id: https://google-glog.googlecode.com/svn/trunk@92 eb4d4688-79bd-11dd-afb4-1d65580434c0
parent 0b4dcd23
......@@ -143,14 +143,12 @@ static const AbbrevPair kSubstitutionList[] = {
// State needed for demangling.
typedef struct {
const char *mangled_cur; // Cursor of mangled name.
const char *mangled_end; // End of mangled name.
char *out_cur; // Cursor of output string.
const char *out_begin; // Beginning of output string.
const char *out_end; // End of output string.
const char *prev_name; // For constructors/destructors.
int prev_name_length; // For constructors/destructors.
int nest_level; // For nested names.
int number; // Remember the previous number.
short nest_level; // For nested names.
bool append; // Append flag.
bool overflowed; // True if output gets overflowed.
} State;
......@@ -166,6 +164,16 @@ static size_t StrLen(const char *str) {
return len;
}
// Returns true if "str" has at least "n" characters remaining.
static bool AtLeastNumCharsRemaining(const char *str, int n) {
for (int i = 0; i < n; ++i) {
if (str == '\0') {
return false;
}
}
return true;
}
// Returns true if "str" has "prefix" as a prefix.
static bool StrPrefix(const char *str, const char *prefix) {
size_t i = 0;
......@@ -179,39 +187,33 @@ static bool StrPrefix(const char *str, const char *prefix) {
static void InitState(State *state, const char *mangled,
char *out, int out_size) {
state->mangled_cur = mangled;
state->mangled_end = mangled + StrLen(mangled);
state->out_cur = out;
state->out_begin = out;
state->out_end = out + out_size;
state->prev_name = NULL;
state->prev_name_length = -1;
state->nest_level = -1;
state->number = -1;
state->append = true;
state->overflowed = false;
}
// Calculates the remaining length of the mangled name.
static int RemainingLength(State *state) {
return state->mangled_end - state->mangled_cur;
}
// Returns true and advances "mangled_cur" if we find "c" at
// "mangled_cur" position.
static bool ParseChar(State *state, const char c) {
if (RemainingLength(state) >= 1 && *state->mangled_cur == c) {
// Returns true and advances "mangled_cur" if we find "one_char_token"
// at "mangled_cur" position. It is assumed that "one_char_token" does
// not contain '\0'.
static bool ParseOneCharToken(State *state, const char one_char_token) {
if (state->mangled_cur[0] == one_char_token) {
++state->mangled_cur;
return true;
}
return false;
}
// Returns true and advances "mangled_cur" if we find "two_chars" at
// "mangled_cur" position.
static bool ParseTwoChar(State *state, const char *two_chars) {
if (RemainingLength(state) >= 2 &&
state->mangled_cur[0] == two_chars[0] &&
state->mangled_cur[1] == two_chars[1]) {
// Returns true and advances "mangled_cur" if we find "two_char_token"
// at "mangled_cur" position. It is assumed that "two_char_token" does
// not contain '\0'.
static bool ParseTwoCharToken(State *state, const char *two_char_token) {
if (state->mangled_cur[0] == two_char_token[0] &&
state->mangled_cur[1] == two_char_token[1]) {
state->mangled_cur += 2;
return true;
}
......@@ -221,13 +223,13 @@ static bool ParseTwoChar(State *state, const char *two_chars) {
// Returns true and advances "mangled_cur" if we find any character in
// "char_class" at "mangled_cur" position.
static bool ParseCharClass(State *state, const char *char_class) {
if (state->mangled_cur == state->mangled_end) {
if (state->mangled_cur == '\0') {
return false;
}
const char *p = char_class;
for (; *p != '\0'; ++p) {
if (*state->mangled_cur == *p) {
state->mangled_cur += 1;
if (state->mangled_cur[0] == *p) {
++state->mangled_cur;
return true;
}
}
......@@ -251,8 +253,9 @@ static bool OneOrMore(ParseFunc parse_func, State *state) {
}
// This function is used for handling <non-terminal>* syntax. The function
// always returns true and must be followed by a termination symbol or a
// terminating sequence not handled by parse_func (e.g. ParseChar(state, 'E')).
// always returns true and must be followed by a termination token or a
// terminating sequence not handled by parse_func (e.g.
// ParseOneCharToken(state, 'E')).
static bool ZeroOrMore(ParseFunc parse_func, State *state) {
while (parse_func(state)) {
}
......@@ -284,7 +287,7 @@ static bool IsLower(char c) {
}
static bool IsAlpha(char c) {
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
static bool IsDigit(char c) {
......@@ -353,7 +356,7 @@ static bool EnterNestedName(State *state) {
}
// This function is used for handling nested names.
static bool LeaveNestedName(State *state, int prev_value) {
static bool LeaveNestedName(State *state, short prev_value) {
state->nest_level = prev_value;
return true;
}
......@@ -393,11 +396,11 @@ static void MaybeCancelLastSeparator(State *state) {
}
}
// Returns true if identifier pointed by "mangled_cur" is anonymous
// namespace.
static bool IdentifierIsAnonymousNamespace(State *state) {
const char anon_prefix[] = "_GLOBAL__N_";
return (state->number > sizeof(anon_prefix) - 1 && // Should be longer.
// Returns true if the identifier of the given length pointed to by
// "mangled_cur" is anonymous namespace.
static bool IdentifierIsAnonymousNamespace(State *state, int length) {
static const char anon_prefix[] = "_GLOBAL__N_";
return (length > sizeof(anon_prefix) - 1 && // Should be longer.
StrPrefix(state->mangled_cur, anon_prefix));
}
......@@ -412,10 +415,10 @@ static bool ParsePrefix(State *state);
static bool ParseUnqualifiedName(State *state);
static bool ParseSourceName(State *state);
static bool ParseLocalSourceName(State *state);
static bool ParseNumber(State *state);
static bool ParseNumber(State *state, int *number_out);
static bool ParseFloatNumber(State *state);
static bool ParseSeqId(State *state);
static bool ParseIdentifier(State *state);
static bool ParseIdentifier(State *state, int length);
static bool ParseOperatorName(State *state);
static bool ParseSpecialName(State *state);
static bool ParseCallOffset(State *state);
......@@ -472,21 +475,7 @@ static bool ParseSubstitution(State *state);
// <mangled-name> ::= _Z <encoding>
static bool ParseMangledName(State *state) {
if (ParseTwoChar(state, "_Z") && ParseEncoding(state)) {
// Drop trailing function clone suffix, if any.
if (IsFunctionCloneSuffix(state->mangled_cur)) {
state->mangled_cur = state->mangled_end;
}
// Append trailing version suffix if any.
// ex. _Z3foo@@GLIBCXX_3.4
if (state->mangled_cur < state->mangled_end &&
state->mangled_cur[0] == '@') {
MaybeAppend(state, state->mangled_cur);
state->mangled_cur = state->mangled_end;
}
return true;
}
return false;
return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
}
// <encoding> ::= <(function) name> <bare-function-type>
......@@ -536,7 +525,7 @@ static bool ParseUnscopedName(State *state) {
}
State copy = *state;
if (ParseTwoChar(state, "St") &&
if (ParseTwoCharToken(state, "St") &&
MaybeAppend(state, "std::") &&
ParseUnqualifiedName(state)) {
return true;
......@@ -555,12 +544,12 @@ static bool ParseUnscopedTemplateName(State *state) {
// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
static bool ParseNestedName(State *state) {
State copy = *state;
if (ParseChar(state, 'N') &&
if (ParseOneCharToken(state, 'N') &&
EnterNestedName(state) &&
Optional(ParseCVQualifiers(state)) &&
ParsePrefix(state) &&
LeaveNestedName(state, copy.nest_level) &&
ParseChar(state, 'E')) {
ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
......@@ -613,7 +602,8 @@ static bool ParseUnqualifiedName(State *state) {
// <source-name> ::= <positive length number> <identifier>
static bool ParseSourceName(State *state) {
State copy = *state;
if (ParseNumber(state) && ParseIdentifier(state)) {
int length = -1;
if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
return true;
}
*state = copy;
......@@ -627,7 +617,7 @@ static bool ParseSourceName(State *state) {
// http://gcc.gnu.org/viewcvs?view=rev&revision=124467
static bool ParseLocalSourceName(State *state) {
State copy = *state;
if (ParseChar(state, 'L') && ParseSourceName(state) &&
if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
Optional(ParseDiscriminator(state))) {
return true;
}
......@@ -636,14 +626,16 @@ static bool ParseLocalSourceName(State *state) {
}
// <number> ::= [n] <non-negative decimal integer>
static bool ParseNumber(State *state) {
// If "number_out" is non-null, then *number_out is set to the value of the
// parsed number on success.
static bool ParseNumber(State *state, int *number_out) {
int sign = 1;
if (ParseChar(state, 'n')) {
if (ParseOneCharToken(state, 'n')) {
sign = -1;
}
const char *p = state->mangled_cur;
int number = 0;
for (;p < state->mangled_end; ++p) {
for (;*p != '\0'; ++p) {
if (IsDigit(*p)) {
number = number * 10 + (*p - '0');
} else {
......@@ -652,7 +644,9 @@ static bool ParseNumber(State *state) {
}
if (p != state->mangled_cur) { // Conversion succeeded.
state->mangled_cur = p;
state->number = number * sign;
if (number_out != NULL) {
*number_out = number * sign;
}
return true;
}
return false;
......@@ -662,19 +656,13 @@ static bool ParseNumber(State *state) {
// hexadecimal string.
static bool ParseFloatNumber(State *state) {
const char *p = state->mangled_cur;
int number = 0;
for (;p < state->mangled_end; ++p) {
if (IsDigit(*p)) {
number = number * 16 + (*p - '0');
} else if (*p >= 'a' && *p <= 'f') {
number = number * 16 + (*p - 'a' + 10);
} else {
for (;*p != '\0'; ++p) {
if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
break;
}
}
if (p != state->mangled_cur) { // Conversion succeeded.
state->mangled_cur = p;
state->number = number;
return true;
}
return false;
......@@ -684,37 +672,30 @@ static bool ParseFloatNumber(State *state) {
// using digits and upper case letters
static bool ParseSeqId(State *state) {
const char *p = state->mangled_cur;
int number = 0;
for (;p < state->mangled_end; ++p) {
if (IsDigit(*p)) {
number = number * 36 + (*p - '0');
} else if (*p >= 'A' && *p <= 'Z') {
number = number * 36 + (*p - 'A' + 10);
} else {
for (;*p != '\0'; ++p) {
if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
break;
}
}
if (p != state->mangled_cur) { // Conversion succeeded.
state->mangled_cur = p;
state->number = number;
return true;
}
return false;
}
// <identifier> ::= <unqualified source code identifier>
static bool ParseIdentifier(State *state) {
if (state->number == -1 ||
RemainingLength(state) < state->number) {
// <identifier> ::= <unqualified source code identifier> (of given length)
static bool ParseIdentifier(State *state, int length) {
if (length == -1 ||
!AtLeastNumCharsRemaining(state->mangled_cur, length)) {
return false;
}
if (IdentifierIsAnonymousNamespace(state)) {
if (IdentifierIsAnonymousNamespace(state, length)) {
MaybeAppend(state, "(anonymous namespace)");
} else {
MaybeAppendWithLength(state, state->mangled_cur, state->number);
MaybeAppendWithLength(state, state->mangled_cur, length);
}
state->mangled_cur += state->number;
state->number = -1; // Reset the number.
state->mangled_cur += length;
return true;
}
......@@ -722,12 +703,12 @@ static bool ParseIdentifier(State *state) {
// ::= cv <type> # (cast)
// ::= v <digit> <source-name> # vendor extended operator
static bool ParseOperatorName(State *state) {
if (RemainingLength(state) < 2) {
if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) {
return false;
}
// First check with "cv" (cast) case.
State copy = *state;
if (ParseTwoChar(state, "cv") &&
if (ParseTwoCharToken(state, "cv") &&
MaybeAppend(state, "operator ") &&
EnterNestedName(state) &&
ParseType(state) &&
......@@ -737,7 +718,7 @@ static bool ParseOperatorName(State *state) {
*state = copy;
// Then vendor extended operators.
if (ParseChar(state, 'v') && ParseCharClass(state, "0123456789") &&
if (ParseOneCharToken(state, 'v') && ParseCharClass(state, "0123456789") &&
ParseSourceName(state)) {
return true;
}
......@@ -786,34 +767,34 @@ static bool ParseOperatorName(State *state) {
// stack traces. The are special data.
static bool ParseSpecialName(State *state) {
State copy = *state;
if (ParseChar(state, 'T') &&
if (ParseOneCharToken(state, 'T') &&
ParseCharClass(state, "VTIS") &&
ParseType(state)) {
return true;
}
*state = copy;
if (ParseTwoChar(state, "Tc") && ParseCallOffset(state) &&
if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) &&
ParseCallOffset(state) && ParseEncoding(state)) {
return true;
}
*state = copy;
if (ParseTwoChar(state, "GV") &&
if (ParseTwoCharToken(state, "GV") &&
ParseName(state)) {
return true;
}
*state = copy;
if (ParseChar(state, 'T') && ParseCallOffset(state) &&
if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) &&
ParseEncoding(state)) {
return true;
}
*state = copy;
// G++ extensions
if (ParseTwoChar(state, "TC") && ParseType(state) &&
ParseNumber(state) && ParseChar(state, '_') &&
if (ParseTwoCharToken(state, "TC") && ParseType(state) &&
ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
DisableAppend(state) &&
ParseType(state)) {
RestoreAppend(state, copy.append);
......@@ -821,23 +802,23 @@ static bool ParseSpecialName(State *state) {
}
*state = copy;
if (ParseChar(state, 'T') && ParseCharClass(state, "FJ") &&
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") &&
ParseType(state)) {
return true;
}
*state = copy;
if (ParseTwoChar(state, "GR") && ParseName(state)) {
if (ParseTwoCharToken(state, "GR") && ParseName(state)) {
return true;
}
*state = copy;
if (ParseTwoChar(state, "GA") && ParseEncoding(state)) {
if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) {
return true;
}
*state = copy;
if (ParseChar(state, 'T') && ParseCharClass(state, "hv") &&
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") &&
ParseCallOffset(state) && ParseEncoding(state)) {
return true;
}
......@@ -849,14 +830,14 @@ static bool ParseSpecialName(State *state) {
// ::= v <v-offset> _
static bool ParseCallOffset(State *state) {
State copy = *state;
if (ParseChar(state, 'h') &&
ParseNVOffset(state) && ParseChar(state, '_')) {
if (ParseOneCharToken(state, 'h') &&
ParseNVOffset(state) && ParseOneCharToken(state, '_')) {
return true;
}
*state = copy;
if (ParseChar(state, 'v') &&
ParseVOffset(state) && ParseChar(state, '_')) {
if (ParseOneCharToken(state, 'v') &&
ParseVOffset(state) && ParseOneCharToken(state, '_')) {
return true;
}
*state = copy;
......@@ -866,14 +847,14 @@ static bool ParseCallOffset(State *state) {
// <nv-offset> ::= <(offset) number>
static bool ParseNVOffset(State *state) {
return ParseNumber(state);
return ParseNumber(state, NULL);
}
// <v-offset> ::= <(offset) number> _ <(virtual offset) number>
static bool ParseVOffset(State *state) {
State copy = *state;
if (ParseNumber(state) && ParseChar(state, '_') &&
ParseNumber(state)) {
if (ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
ParseNumber(state, NULL)) {
return true;
}
*state = copy;
......@@ -884,7 +865,7 @@ static bool ParseVOffset(State *state) {
// ::= D0 | D1 | D2
static bool ParseCtorDtorName(State *state) {
State copy = *state;
if (ParseChar(state, 'C') &&
if (ParseOneCharToken(state, 'C') &&
ParseCharClass(state, "123")) {
const char * const prev_name = state->prev_name;
const int prev_name_length = state->prev_name_length;
......@@ -893,7 +874,7 @@ static bool ParseCtorDtorName(State *state) {
}
*state = copy;
if (ParseChar(state, 'D') &&
if (ParseOneCharToken(state, 'D') &&
ParseCharClass(state, "012")) {
const char * const prev_name = state->prev_name;
const int prev_name_length = state->prev_name_length;
......@@ -938,18 +919,18 @@ static bool ParseType(State *state) {
}
*state = copy;
if (ParseTwoChar(state, "Dp") && ParseType(state)) {
if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
return true;
}
*state = copy;
if (ParseChar(state, 'D') && ParseCharClass(state, "tT") &&
ParseExpression(state) && ParseChar(state, 'E')) {
if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") &&
ParseExpression(state) && ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
if (ParseChar(state, 'U') && ParseSourceName(state) &&
if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
ParseType(state)) {
return true;
}
......@@ -983,9 +964,9 @@ static bool ParseType(State *state) {
// ParseType().
static bool ParseCVQualifiers(State *state) {
int num_cv_qualifiers = 0;
num_cv_qualifiers += ParseChar(state, 'r');
num_cv_qualifiers += ParseChar(state, 'V');
num_cv_qualifiers += ParseChar(state, 'K');
num_cv_qualifiers += ParseOneCharToken(state, 'r');
num_cv_qualifiers += ParseOneCharToken(state, 'V');
num_cv_qualifiers += ParseOneCharToken(state, 'K');
return num_cv_qualifiers > 0;
}
......@@ -1002,7 +983,7 @@ static bool ParseBuiltinType(State *state) {
}
State copy = *state;
if (ParseChar(state, 'u') && ParseSourceName(state)) {
if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) {
return true;
}
*state = copy;
......@@ -1012,8 +993,9 @@ static bool ParseBuiltinType(State *state) {
// <function-type> ::= F [Y] <bare-function-type> E
static bool ParseFunctionType(State *state) {
State copy = *state;
if (ParseChar(state, 'F') && Optional(ParseChar(state, 'Y')) &&
ParseBareFunctionType(state) && ParseChar(state, 'E')) {
if (ParseOneCharToken(state, 'F') &&
Optional(ParseOneCharToken(state, 'Y')) &&
ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
......@@ -1042,14 +1024,14 @@ static bool ParseClassEnumType(State *state) {
// ::= A [<(dimension) expression>] _ <(element) type>
static bool ParseArrayType(State *state) {
State copy = *state;
if (ParseChar(state, 'A') && ParseNumber(state) &&
ParseChar(state, '_') && ParseType(state)) {
if (ParseOneCharToken(state, 'A') && ParseNumber(state, NULL) &&
ParseOneCharToken(state, '_') && ParseType(state)) {
return true;
}
*state = copy;
if (ParseChar(state, 'A') && Optional(ParseExpression(state)) &&
ParseChar(state, '_') && ParseType(state)) {
if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) &&
ParseOneCharToken(state, '_') && ParseType(state)) {
return true;
}
*state = copy;
......@@ -1059,7 +1041,7 @@ static bool ParseArrayType(State *state) {
// <pointer-to-member-type> ::= M <(class) type> <(member) type>
static bool ParsePointerToMemberType(State *state) {
State copy = *state;
if (ParseChar(state, 'M') && ParseType(state) &&
if (ParseOneCharToken(state, 'M') && ParseType(state) &&
ParseType(state)) {
return true;
}
......@@ -1070,14 +1052,14 @@ static bool ParsePointerToMemberType(State *state) {
// <template-param> ::= T_
// ::= T <parameter-2 non-negative number> _
static bool ParseTemplateParam(State *state) {
if (ParseTwoChar(state, "T_")) {
if (ParseTwoCharToken(state, "T_")) {
MaybeAppend(state, "?"); // We don't support template substitutions.
return true;
}
State copy = *state;
if (ParseChar(state, 'T') && ParseNumber(state) &&
ParseChar(state, '_')) {
if (ParseOneCharToken(state, 'T') && ParseNumber(state, NULL) &&
ParseOneCharToken(state, '_')) {
MaybeAppend(state, "?"); // We don't support template substitutions.
return true;
}
......@@ -1097,9 +1079,9 @@ static bool ParseTemplateTemplateParam(State *state) {
static bool ParseTemplateArgs(State *state) {
State copy = *state;
DisableAppend(state);
if (ParseChar(state, 'I') &&
if (ParseOneCharToken(state, 'I') &&
OneOrMore(ParseTemplateArg, state) &&
ParseChar(state, 'E')) {
ParseOneCharToken(state, 'E')) {
RestoreAppend(state, copy.append);
MaybeAppend(state, "<>");
return true;
......@@ -1114,9 +1096,9 @@ static bool ParseTemplateArgs(State *state) {
// ::= X <expression> E
static bool ParseTemplateArg(State *state) {
State copy = *state;
if (ParseChar(state, 'I') &&
if (ParseOneCharToken(state, 'I') &&
ZeroOrMore(ParseTemplateArg, state) &&
ParseChar(state, 'E')) {
ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
......@@ -1127,8 +1109,8 @@ static bool ParseTemplateArg(State *state) {
}
*state = copy;
if (ParseChar(state, 'X') && ParseExpression(state) &&
ParseChar(state, 'E')) {
if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&
ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
......@@ -1171,19 +1153,19 @@ static bool ParseExpression(State *state) {
}
*state = copy;
if (ParseTwoChar(state, "st") && ParseType(state)) {
if (ParseTwoCharToken(state, "st") && ParseType(state)) {
return true;
}
*state = copy;
if (ParseTwoChar(state, "sr") && ParseType(state) &&
if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
ParseUnqualifiedName(state) &&
ParseTemplateArgs(state)) {
return true;
}
*state = copy;
if (ParseTwoChar(state, "sr") && ParseType(state) &&
if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
ParseUnqualifiedName(state)) {
return true;
}
......@@ -1198,28 +1180,28 @@ static bool ParseExpression(State *state) {
// ::= LZ <encoding> E
static bool ParseExprPrimary(State *state) {
State copy = *state;
if (ParseChar(state, 'L') && ParseType(state) &&
ParseNumber(state) &&
ParseChar(state, 'E')) {
if (ParseOneCharToken(state, 'L') && ParseType(state) &&
ParseNumber(state, NULL) &&
ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
if (ParseChar(state, 'L') && ParseType(state) &&
if (ParseOneCharToken(state, 'L') && ParseType(state) &&
ParseFloatNumber(state) &&
ParseChar(state, 'E')) {
ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
if (ParseChar(state, 'L') && ParseMangledName(state) &&
ParseChar(state, 'E')) {
if (ParseOneCharToken(state, 'L') && ParseMangledName(state) &&
ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
if (ParseTwoChar(state, "LZ") && ParseEncoding(state) &&
ParseChar(state, 'E')) {
if (ParseTwoCharToken(state, "LZ") && ParseEncoding(state) &&
ParseOneCharToken(state, 'E')) {
return true;
}
*state = copy;
......@@ -1232,15 +1214,15 @@ static bool ParseExprPrimary(State *state) {
// := Z <(function) encoding> E s [<discriminator>]
static bool ParseLocalName(State *state) {
State copy = *state;
if (ParseChar(state, 'Z') && ParseEncoding(state) &&
ParseChar(state, 'E') && MaybeAppend(state, "::") &&
if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
ParseOneCharToken(state, 'E') && MaybeAppend(state, "::") &&
ParseName(state) && Optional(ParseDiscriminator(state))) {
return true;
}
*state = copy;
if (ParseChar(state, 'Z') && ParseEncoding(state) &&
ParseTwoChar(state, "Es") && Optional(ParseDiscriminator(state))) {
if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
ParseTwoCharToken(state, "Es") && Optional(ParseDiscriminator(state))) {
return true;
}
*state = copy;
......@@ -1250,7 +1232,7 @@ static bool ParseLocalName(State *state) {
// <discriminator> := _ <(non-negative) number>
static bool ParseDiscriminator(State *state) {
State copy = *state;
if (ParseChar(state, '_') && ParseNumber(state)) {
if (ParseOneCharToken(state, '_') && ParseNumber(state, NULL)) {
return true;
}
*state = copy;
......@@ -1261,21 +1243,21 @@ static bool ParseDiscriminator(State *state) {
// ::= S <seq-id> _
// ::= St, etc.
static bool ParseSubstitution(State *state) {
if (ParseTwoChar(state, "S_")) {
if (ParseTwoCharToken(state, "S_")) {
MaybeAppend(state, "?"); // We don't support substitutions.
return true;
}
State copy = *state;
if (ParseChar(state, 'S') && ParseSeqId(state) &&
ParseChar(state, '_')) {
if (ParseOneCharToken(state, 'S') && ParseSeqId(state) &&
ParseOneCharToken(state, '_')) {
MaybeAppend(state, "?"); // We don't support substitutions.
return true;
}
*state = copy;
// Expand abbreviations like "St" => "std".
if (ParseChar(state, 'S')) {
if (ParseOneCharToken(state, 'S')) {
const AbbrevPair *p;
for (p = kSubstitutionList; p->abbrev != NULL; ++p) {
if (state->mangled_cur[0] == p->abbrev[1]) {
......@@ -1284,7 +1266,7 @@ static bool ParseSubstitution(State *state) {
MaybeAppend(state, "::");
MaybeAppend(state, p->real_name);
}
state->mangled_cur += 1;
++state->mangled_cur;
return true;
}
}
......@@ -1293,13 +1275,33 @@ static bool ParseSubstitution(State *state) {
return false;
}
// Parse <mangled-name>, optionally followed by either a function-clone suffix
// or version suffix. Returns true only if all of "mangled_cur" was consumed.
static bool ParseTopLevelMangledName(State *state) {
if (ParseMangledName(state)) {
if (state->mangled_cur[0] != '\0') {
// Drop trailing function clone suffix, if any.
if (IsFunctionCloneSuffix(state->mangled_cur)) {
return true;
}
// Append trailing version suffix if any.
// ex. _Z3foo@@GLIBCXX_3.4
if (state->mangled_cur[0] == '@') {
MaybeAppend(state, state->mangled_cur);
return true;
}
return false; // Unconsumed suffix.
}
return true;
}
return false;
}
// The demangler entry point.
bool Demangle(const char *mangled, char *out, int out_size) {
State state;
InitState(&state, mangled, out, out_size);
return (ParseMangledName(&state) &&
state.overflowed == false &&
RemainingLength(&state) == 0);
return ParseTopLevelMangledName(&state) && !state.overflowed;
}
_END_GOOGLE_NAMESPACE_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment