/**
* @file demangle_java_symbol.cpp
* Demangle a java symbol
*
* @remark Copyright 2007 OProfile authors
* @remark Read the file COPYING
*
* @author Philippe Elie
*/
#include "demangle_java_symbol.h"
#include <algorithm>
using namespace std;
namespace {
/**
* The grammar we implement:
*
* field_type:
* base_type | object_type | array_type
* base_type:
* B | C | D | F | I | J | S | Z
* object_type:
* L<classname>;
* array_type:
* [field_type
* method_descriptor:
* ( field_type* ) return_descriptor
* return_descriptor:
* field_type | V
* method_signature:
* object_type method_name method_descriptor
*
*/
bool array_type(string & result,
string::const_iterator & begin, string::const_iterator end);
bool object_type(string & result,
string::const_iterator & begin, string::const_iterator end);
bool base_type(string & result,
string::const_iterator & begin, string::const_iterator end)
{
bool ret = true;
if (begin == end)
return false;
switch (*begin) {
case 'B': result += "byte"; break;
case 'C': result += "char"; break;
case 'D': result += "double"; break;
case 'F': result += "float"; break;
case 'I': result += "int"; break;
case 'J': result += "long"; break;
case 'S': result += "short"; break;
case 'Z': result += "boolean"; break;
default: ret = false; break;
}
if (ret)
++begin;
return ret;
}
bool field_type(string & result,
string::const_iterator & begin, string::const_iterator end)
{
if (base_type(result, begin, end))
return true;
if (object_type(result, begin, end))
return true;
if (array_type(result, begin, end))
return true;
return false;
}
bool array_type(string & result,
string::const_iterator & begin, string::const_iterator end)
{
if (begin == end || *begin != '[')
return false;
++begin;
if (field_type(result, begin, end)) {
result += "[]";
return true;
}
return false;
}
bool list_of_field_type(string & result,
string::const_iterator & begin, string::const_iterator end)
{
bool first = false;
while (begin != end) {
if (first)
result += ", ";
if (!field_type(result, begin, end))
return false;
first = true;
}
return true;
}
bool return_descriptor(string & result,
string::const_iterator & begin, string::const_iterator end)
{
if (begin == end)
return false;
if (*begin == 'V') {
++begin;
result = "void " + result;
return true;
}
string temp;
if (!field_type(temp, begin, end))
return false;
result = temp + " " + result;
return true;
}
bool method_descriptor(string & result,
string::const_iterator & begin, string::const_iterator end)
{
if (begin == end || *begin != '(')
return false;
++begin;
string::const_iterator pos = find(begin, end, ')');
if (pos == end)
return false;
result += "(";
if (!list_of_field_type(result, begin, pos))
return false;
if (begin == end || *begin != ')')
return false;
++begin;
if (!return_descriptor(result, begin, end))
return false;
result += ')';
return true;
}
bool methode_name(string & result,
string::const_iterator & begin, string::const_iterator end)
{
if (begin == end)
return false;
string::const_iterator pos = find(begin, end, '(');
if (pos == end)
return false;
result += '.' + string(begin, pos);
begin = pos;
return true;
}
bool object_type(string & result,
string::const_iterator & begin, string::const_iterator end)
{
if (begin == end || *begin != 'L')
return false;
string::const_iterator pos = find(begin, end, ';');
if (pos == end)
return false;
string temp = string(begin + 1, pos);
replace(temp.begin(), temp.end(), '/', '.');
result += temp;
begin = pos + 1;
return true;
}
string demangle_symbol(string::const_iterator begin,
string::const_iterator end)
{
string result;
if (!object_type(result, begin, end))
return string();
if (!methode_name(result, begin, end))
return string();
if (!method_descriptor(result, begin, end))
return string();
if (begin != end) {
if (*begin == '~') {
// special case for disambiguated symbol.
result += string(begin, end);
} else {
return string();
}
}
return result;
}
} // anonymous namespace
string const demangle_java_symbol(string const & name)
{
return demangle_symbol(name.begin(), name.end());
}