/* $Id$ 
 * vim:tabstop=8:shiftwidth=8:filetype=cpp:textwidth=72:
 *
 * ParserDriver: glue class to driver between scanner and parser.
 *
 * Copyright (C) 2007-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

namespace yy {

template <typename T>
T
ParserDriver::makeBase10(std::string number)
{
	std::string exponent = "";
	unsigned long i = 0;
	
	/* remove all underscores */
	i = number.find('_', 0);
	while (i != std::string::npos) {
		number.erase(i, 1);
		i = number.find('_', 0);
	}

	/* check for exponent */
	i = number.find_first_of("eE", 0);
	if (i != std::string::npos) {
		exponent = number.substr(i);
		/* remove exponent from number */
		number = number.substr(0, i);
	}

	return ParserDriver::makeNumberFromParts<T>(number, exponent, 10);
}

template <typename T>
T
ParserDriver::makeBased(std::string number)
	/* throw(std::invalid_argument) */
{
	std::string exponent = "";
	T num;
	unsigned long j = 0;
	char base = 10;

	/* remove all underscores */
	j = number.find('_', 0);
	while (j != std::string::npos) {
		number.erase(j, 1);
		j = number.find('_', 0);
	}

	/* base specifier present? */
	j = number.find('#', 0);
	if (j != std::string::npos) {
		std::string baseS = number.substr(0, j);
		base = static_cast<char>(ParserDriver::makeLong(baseS, 10));

		/* remove basespecifier + '#' */
		number = number.substr(j + 1);
		
		j = number.find('#', 0);
		exponent = number.substr(j + 1);

		/* remove exponent */
		number.erase(j);
	} else {
		throw std::invalid_argument("Number w.o. base specifier: " 
						+ number);
	}
	
	num = ParserDriver::makeNumberFromParts<T>(number, exponent, base);	

	return num;
}

template <typename T>
T 
ParserDriver::makeNumberFromParts(std::string& val, 
				  std::string& exponent, 
				  unsigned char base)
{
	unsigned long i;
	long exp = 0;
	T result;
	/* 1. convert exponent */
	/* leading E? -> remove it. */
	if (exponent[0] == 'E' || exponent[0] == 'e') {
		exponent = exponent.substr(1);
	}

	exp = ParserDriver::makeLong(exponent, 10);

	/* 2. check for decimal point in val */
	i = val.find('.');
	if (i != std::string::npos) {
		/* remove . */
		val.erase(i, 1);
		/* shift exponent by number of digits after . */
		exp -= val.length() - i;
	}

	/* convert number */
	result = static_cast<T>(ParserDriver::makeLong(val, base));

	/* 3. adjust by exponent */
	/* FIXME sistpoty: range check! */
	while (0 < exp) {
		result *= base;
		exp--;
	}

	while (exp < 0) {
		result /= base;
		exp++;
	}

	return result;
}

template <typename T>
void
ParserDriver::registerSymbolDecls(
	const T *symbols,
	enum ast::symType type
)
{
	if (symbols == NULL) {
		return;
	}

	for (typename T::const_iterator i = 
		symbols->begin(); i != symbols->end(); i++) {

		this->symbolTable.registerSymbol(type, **i);
	}
}


}; /* namespace yy */
