/*
Copyright (C) 2006 Evan Teran
                   eteran@alum.rit.edu

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef EXPRESSION_20070402_H_
#define EXPRESSION_20070402_H_

#include <QString>
#include <iostream>

struct ExpressionError {
public:
	enum ERROR_MSG {
		NONE,
		SYNTAX,
		UNBALANCED_PARENS,
		INCORRECT_PARENS,
		UNBALANCED_BRACES,
		INCORRECT_BRACES,
		DIVIDE_BY_ZERO,
		INVALID_NUMBER,
		UNKNOWN_VARIABLE,
		CANNOT_READ_MEMORY
	};
public:
	ExpressionError() : m_Error(NONE) {
	}
	
	explicit ExpressionError(ERROR_MSG type) : m_Error(type) {
	}

	virtual ~ExpressionError() throw() {
	}

	virtual const char *what() const throw() {
		switch(m_Error) {
		case SYNTAX:
			return "Syntax Error";
		case UNBALANCED_PARENS:
			return "Unbalanced Parenthesis";
		case DIVIDE_BY_ZERO:
			return "Divide By Zero";
		case INVALID_NUMBER:
			return "Invalid Numerical Constant";
		case UNKNOWN_VARIABLE:
			return "Unknown Variable";
		case INCORRECT_PARENS:
			return "Incorrect Usage of Parenthesis";
		case UNBALANCED_BRACES:
			return "Unbalanced Braces";
		case INCORRECT_BRACES:
			return "Incorrect Usage of Braces";
		case CANNOT_READ_MEMORY:
			return "Cannot Read Memory At the Effective Address";
		default:
			return "Unknown Error";
		}	
	}
private:
	ERROR_MSG m_Error;	
};


template <class T>
class Expression {
public:
	typedef T (*variable_getter_t)(const QString &, bool &, ExpressionError &, void *);
	typedef T (*memory_reader_t)(T, bool &, ExpressionError &, void *);
	
public:
	Expression(const QString &s, variable_getter_t vg, void *vg_param, memory_reader_t mr, void *mr_param);
	
private:
	struct Token {
		Token()						: m_Operator(NONE), m_Type(UNKNOWN) { }
		Token(const Token& other)	: m_Data(other.m_Data), m_Operator(other.m_Operator), m_Type(other.m_Type) { }
		
		QString m_Data;

		enum Operator {
			NONE,
			AND,
			OR,
			XOR,
			LSHFT,
			RSHFT,
			PLUS,
			MINUS,
			MUL,
			DIV,
			MOD,
			CMP,
			LPAREN,
			RPAREN,
			LBRACE,
			RBRACE,
			NOT,
			LT,
			LE,
			GT,
			GE,
			EQ,
			NE,
			LOGICAL_AND,
			LOGICAL_OR
		} m_Operator;
		
		enum Type {
			UNKNOWN,
			OPERATOR,
			NUMBER,
			VARIABLE
		} m_Type;
		
		void set(const QString &data, Operator oper, Type type) {
			m_Data		= data;
			m_Operator	= oper;
			m_Type		= type;
		}
	};
	
private:
	T evaluateExpression() {
		T result;
		
		getToken();
		eval_exp(result);
				
		return result;
	}
	
public:
	T evaluateExpression(bool &ok, ExpressionError &error) throw() {
		try {
			ok = true;
			return evaluateExpression();
		} catch(const ExpressionError &e) {
			ok = false;
			error = e;
			return T();
		}
	}
private:
	
	void eval_exp(T &result);
	void eval_exp0(T &result);
	void eval_exp1(T &result);
	void eval_exp2(T &result);
	void eval_exp3(T &result);
	void eval_exp4(T &result);
	void eval_exp5(T &result);
	void eval_exp6(T &result);
	void eval_exp7(T &result);
	void eval_atom(T &result);
	void getToken();
	
	static bool isDelim(QChar ch) {
		return QString("[]!()=+-*/%&|^~<>\t\n\r ").contains(ch);
	}
	
private:
	QString					m_Expression;
	QString::const_iterator	m_ExpressionPtr;
	Token					m_Token;
	variable_getter_t		m_VariableGetter;
	void *					m_VariableGetterParam;
	memory_reader_t			m_MemoryReader;
	void *					m_MemoryReaderParam;
};

#include "Expression.tcc"

#endif

