C++程序  |  239行  |  4.23 KB

/**
 * @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());
}