/*
								+---------------------------------+
								|                                 |
								| ***  Expression evaluation  *** |
								|                                 |
								|  Copyright  © -tHE SWINe- 2011  |
								|                                 |
								|           ExpEval.cpp           |
								|                                 |
								+---------------------------------+
*/

/**
 *	@file ExpEval.cpp
 *	@author -tHE SWINe-
 *	@brief simple expression evaluation template
 *	@date 2011
 */

#include "NewFix.h"
#include "CallStack.h"
#include "ExpEval.h"

using namespace exp_eval;

/*
 *								=== CExpEvalLexer ===
 */

CExpEvalLexer::CExpEvalLexer(const char *p_s_expr)
	:m_p_s_expr(p_s_expr)
{}

int CExpEvalLexer::n_LookForOperator(const char *p_s_op_list)
{
	SkipSpace();
	if(*m_p_s_expr && strchr(p_s_op_list, *m_p_s_expr)) {
		int n_result = *m_p_s_expr;
		++ m_p_s_expr; // skip
		return n_result;
	}
	return 0;
}

int CExpEvalLexer::n_PeekOperator2(const char *p_s_twochar_op_list) const
{
	SkipSpace();
	if(!*m_p_s_expr)
		return -1;
	_ASSERTE(strlen(p_s_twochar_op_list) % 2 == 0);
	for(int n_op = 0; *p_s_twochar_op_list; p_s_twochar_op_list += 2, ++ n_op) {
		if(p_s_twochar_op_list[0] == m_p_s_expr[0] &&
		   p_s_twochar_op_list[1] == m_p_s_expr[1])
			return n_op; // doesn't skip
	}
	return -1;
}

int CExpEvalLexer::n_LookForOperator2(const char *p_s_twochar_op_list)
{
	int n_result = n_PeekOperator2(p_s_twochar_op_list);
	if(n_result == -1)
		return -1;
	m_p_s_expr += 2; // skip the operator
	return n_result;
}

bool CExpEvalLexer::b_AtEnd() const
{
	SkipSpace();
	return !*m_p_s_expr; // it's at the end
}

bool CExpEvalLexer::LookForIdentifier(const char *&r_p_ident, size_t &r_n_length)
{
	SkipSpace();

	if(!*m_p_s_expr || (*m_p_s_expr != '_' && !isalpha((uint8_t)*m_p_s_expr)))
		return false;
	r_p_ident = m_p_s_expr;
	++ m_p_s_expr;
	// skip leading char

	for(;;) {
		while(*m_p_s_expr && (*m_p_s_expr == '_' || isalnum((uint8_t)*m_p_s_expr)))
			++ m_p_s_expr;
		if(*m_p_s_expr == '.') {
			++ m_p_s_expr;
			// skip '.'

			if(!*m_p_s_expr || (*m_p_s_expr != '_' && !isalpha((uint8_t)*m_p_s_expr)))
				return false;
			++ m_p_s_expr;
			// skip leading char
		} else
			break;
	}
	// allow chaining variable names using operator '.' (without spaces!)

	r_n_length = m_p_s_expr - r_p_ident;

	return true;
}

// old code
/*bool CExpEvalLexer::LookForNumberLiteral(_Ty &r_t_value)
{
	SkipSpace();
	if(m_p_s_expr[0] == '0' && m_p_s_expr[1] == 'x' && isxdigit((uint8_t)m_p_s_expr[2])) {
		uint64_t n_value = 0;
		for(m_p_s_expr += 2; *m_p_s_expr && isxdigit((uint8_t)*m_p_s_expr); ++ m_p_s_expr)
			n_value = (n_value << 4) | ((isdigit((uint8_t)*m_p_s_expr))? *m_p_s_expr - '0' : (*m_p_s_expr | 32) - 'a' + 10);
		r_t_value = _Ty(n_value);
	} else if(isdigit((uint8_t)m_p_s_expr[0]) ||
	   ((m_p_s_expr[0] == '+' || m_p_s_expr[0] == '-') && isdigit((uint8_t)m_p_s_expr[1])) ||
	   (m_p_s_expr[0] == '.' && isdigit((uint8_t)m_p_s_expr[1])) ||
	   ((m_p_s_expr[0] == '+' || m_p_s_expr[0] == '-') && m_p_s_expr[1] == '.' && isdigit((uint8_t)m_p_s_expr[2]))) {
		// [0-9] | [+\-][0-9] | \.[0-9] | [+\-]\.[0-9]

		int n_sign = 1;
		if(m_p_s_expr[0] == '+')
			++ m_p_s_expr;
		else if(m_p_s_expr[0] == '-') {
			++ m_p_s_expr;
			n_sign = -1;
		}
		// parse sign

		int64_t n_value = 0;
		for(; *m_p_s_expr && isdigit((uint8_t)*m_p_s_expr); ++ m_p_s_expr)
			n_value = n_value * 10 + *m_p_s_expr - '0';
		// parse integers

		if(*m_p_s_expr == '.' || *m_p_s_expr == 'e' || *m_p_s_expr == 'E') {
			double f_value = n_value;
			if(*m_p_s_expr == '.') {
				++ m_p_s_expr;
				for(double f_radix = .1; *m_p_s_expr && isdigit((uint8_t)*m_p_s_expr); ++ m_p_s_expr, f_radix *= .1)
					f_value += (*m_p_s_expr - '0') * f_radix;
			}
			// parse simple floats

			if((*m_p_s_expr == 'e' || *m_p_s_expr == 'E') && (isdigit((uint8_t)m_p_s_expr[1]) ||
			   ((m_p_s_expr[1] == '+' || m_p_s_expr[1] == '-') && isdigit((uint8_t)m_p_s_expr[2])))) {
				++ m_p_s_expr;

				int n_exp_sign = 1;
				if(m_p_s_expr[0] == '+')
					++ m_p_s_expr;
				else if(m_p_s_expr[0] == '-') {
					++ m_p_s_expr;
					n_exp_sign = -1;
				}
				// parse exponent sign

				int64_t n_exp_value = 0;
				for(; *m_p_s_expr && isdigit((uint8_t)*m_p_s_expr); ++ m_p_s_expr)
					n_exp_value = n_exp_value * 10 + *m_p_s_expr - '0';
				// parse integer exponent

				f_value *= pow(10, n_exp_value * n_exp_sign);
				// apply the exponent
			}

			r_t_value = _Ty(f_value * n_sign);
		} else
			r_t_value = _Ty(n_value * n_sign);
	} else
		return false; // no number
	return true;
}*/

bool CExpEvalLexer::LookForNumberLiteral(int64_t &r_n_value, double &r_f_value, bool &r_b_is_integer)
{
	SkipSpace();
	if(m_p_s_expr[0] == '0' && m_p_s_expr[1] == 'x' && isxdigit((uint8_t)m_p_s_expr[2])) {
		// there is an x-number

		uint64_t n_value = 0;
		for(m_p_s_expr += 2; *m_p_s_expr && isxdigit((uint8_t)*m_p_s_expr); ++ m_p_s_expr) {
			n_value = (n_value << 4) | ((isdigit((uint8_t)*m_p_s_expr))?
				*m_p_s_expr - '0' : (*m_p_s_expr | 32) - 'a' + 10);
		}
		// parse

		r_n_value = n_value; // !!
		r_f_value = double(n_value);
		r_b_is_integer = true;
		// write output

		return true;
	} else if(isdigit((uint8_t)m_p_s_expr[0]) || ((m_p_s_expr[0] == '+' ||
	   m_p_s_expr[0] == '-') && isdigit((uint8_t)m_p_s_expr[1])) ||
	   (m_p_s_expr[0] == '.' && isdigit((uint8_t)m_p_s_expr[1])) ||
	   ((m_p_s_expr[0] == '+' || m_p_s_expr[0] == '-') && m_p_s_expr[1] == '.' &&
	   isdigit((uint8_t)m_p_s_expr[2]))) {
		// [0-9] | [+\-][0-9] | \.[0-9] | [+\-]\.[0-9]
		// which means there is a number (int or float)

		int n_sign = 1;
		if(m_p_s_expr[0] == '+')
			++ m_p_s_expr;
		else if(m_p_s_expr[0] == '-') {
			++ m_p_s_expr;
			n_sign = -1;
		}
		// parse sign

		int64_t n_value = 0;
		for(; *m_p_s_expr && isdigit((uint8_t)*m_p_s_expr); ++ m_p_s_expr)
			n_value = n_value * 10 + *m_p_s_expr - '0';
		// parse integers

		if(*m_p_s_expr == '.' || *m_p_s_expr == 'e' || *m_p_s_expr == 'E') {
			double f_value = double(n_value);
			if(*m_p_s_expr == '.') {
				++ m_p_s_expr;
				for(double f_radix = .1; *m_p_s_expr && isdigit((uint8_t)*m_p_s_expr); ++ m_p_s_expr, f_radix *= .1)
					f_value += (*m_p_s_expr - '0') * f_radix;
			}
			// parse simple floats

			if((*m_p_s_expr == 'e' || *m_p_s_expr == 'E') && (isdigit((uint8_t)m_p_s_expr[1]) ||
			   ((m_p_s_expr[1] == '+' || m_p_s_expr[1] == '-') && isdigit((uint8_t)m_p_s_expr[2])))) {
				++ m_p_s_expr;

				int n_exp_sign = 1;
				if(m_p_s_expr[0] == '+')
					++ m_p_s_expr;
				else if(m_p_s_expr[0] == '-') {
					++ m_p_s_expr;
					n_exp_sign = -1;
				}
				// parse exponent sign

				int64_t n_exp_value = 0;
				for(; *m_p_s_expr && isdigit((uint8_t)*m_p_s_expr); ++ m_p_s_expr)
					n_exp_value = n_exp_value * 10 + *m_p_s_expr - '0';
				// parse integer exponent

				f_value *= pow(10.0, double(n_exp_value * n_exp_sign));
				// apply the exponent
			}
			// parse floats with exponentiation

			r_n_value = int64_t(f_value * n_sign);
			r_f_value = f_value * n_sign;
			r_b_is_integer = false;
			// write output
		} else {
			r_n_value = n_value * n_sign;
			r_f_value = double(n_value * n_sign);
			r_b_is_integer = true;
			// write output
		}

		return true;
	} else
		return false; // no number on input
}

void CExpEvalLexer::SkipSpace() const
{
	while(*m_p_s_expr && isspace((uint8_t)*m_p_s_expr)) // would cause problems on characters above 127
		++ m_p_s_expr;
}

const char *CExpEvalLexer::p_s_CurrentPosition() const
{
	return m_p_s_expr;
}

/*
 *								=== ~CExpEvalLexer ===
 */
