#include "StdAfx.h"
#include "Evaluator.h"


namespace CLITableur
{
	/*
	* Analyseur grammatical
	*/
	#pragma region Analyseur grammatical

	#pragma region S
	Variant^ Evaluator::S()
	{
		log("S:");
		Variant^ valeur = gcnew Variant();
		valeur->nValue = 0;

		while (look_ahead() != tokens::EOF && !HasErrors)
			expression(valeur);
		return valeur;
	}
	#pragma endregion

	#pragma region expression
	void Evaluator::expression(Variant^ valeur)
	{
		log("Expression: ");

		// terme
		Variant^ p = gcnew Variant();
		Variant^ m = gcnew Variant();
		terme(valeur);

		tokens la;
		while ((la = look_ahead()) != tokens::EOF &&
			(la == tokens::PLUS || la == tokens::MOINS))
		{
			switch (la)
			{
			case tokens::PLUS:
				next();
				log(" PLUS ");
				terme(p);
				valeur->nValue += p->nValue;
				//valeur += p;
				break;

			case tokens::MOINS:
				next();
				log(" MOINS ");
				terme(m);
				valeur->nValue -= m->nValue;
				//valeur -= m;
				break;
			}
		}
	}
	#pragma endregion

	#pragma region terme
	void Evaluator::terme(Variant^ t)
	{
		Variant^ m = gcnew Variant();
		Variant^ d = gcnew Variant();
		log("Terme: ");
		tokens la;

		facteur(t); // facteur ...

		while ((la = look_ahead()) != tokens::EOF &&
			(la == tokens::MUL || la == tokens::DIV))
		{
			switch (la)
			{
			case tokens::MUL:
				next();
				log(" MUL ");
				facteur(m);
				t->nValue = t->nValue * m->nValue;
				//t = t * m;
				break;

			case tokens::DIV:
				next();
				log(" DIV ");
				facteur(d);
				t->nValue = t->nValue / d->nValue;
				//t = t / d;
				break;
			}

		}
	}
	#pragma endregion

	#pragma region facteur
	void Evaluator::facteur(Variant^ f)
	{		
		Variant^ v = gcnew Variant();
		Variant^ fa = gcnew Variant();

		Variant^ p = gcnew Variant();
		Variant^ arg0, ^arg1, ^arg2, ^arg3, ^arg4;
		arg0 = gcnew Variant();
		arg1 = gcnew Variant();
		arg2 = gcnew Variant();
		arg3 = gcnew Variant();
		arg4 = gcnew Variant();

		tokens la = look_ahead();
		log("Facteur:" + la.ToString() + "=" + current_value);
		switch (la)
		{

		case tokens::MOINS:
			next(); // -
			expression(f);
			f->nValue = - f->nValue;
			return;

		case tokens::QUOTE:
			next(); // "
			next(); // text
			f->sValue = current_value;
			next(); // "
			return;

			// text
		case tokens::TEXT:
			next();
			if (Char::IsLetter(current_value[0]))
			{
				cellule(current_value, f);
				return;
			}

			try
			{
				f->nValue = System::Double::Parse(current_value);
			}
			catch(...)
			{
				f->nValue = 0;
			}
			return;

			// "( expression )"
		case tokens::POUV:
			next();
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				return;
			}
			break;


			// "if"
		case tokens::IF:				
			next(); // if
			next(); // (

			predicat(p);

			next(); // ;
			log(" ; ");

			expression(v);
			next(); // ;
			expression(fa);
			next(); // )
			log(" ) ");
			if (p->bValue)
				f->CopyFrom(v);
			else
				f->CopyFrom(fa);
			return;				

			// "sqrt"
		case tokens::SQRT:
			next(); // sqrt
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Sqrt(f->nValue);
				return;
			}
			break;

			// "abs"
		case tokens::ABS:
			next(); // abs
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Abs(f->nValue);
				return;
			}
			break;

			// "arr"
		case tokens::ARR:
			next(); // arr
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Floor(f->nValue);
				return;
			}
			break;

			// "ln"
		case tokens::LN:
			next(); // ln
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Log(f->nValue);
				return;
			}
			break;

			// "log"
		case tokens::LOG10:
			next(); // log
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Log10(f->nValue);
				return;
			}
			break;

			// "fac"
		case tokens::FAC:
			next(); // fac
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				int i=(int)f->nValue;
				while(--i>0)
					f->nValue = f->nValue * i;
				return;
			}
			break;

			// "exp"
		case tokens::EXP:
			next(); // exp
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Exp(f->nValue);
				return;
			}
			break;

			// "cos"
		case tokens::COS:
			next(); // cos
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Cos(f->nValue);
				return;
			}
			break;

			// "sin"
		case tokens::SIN:
			next(); // sin
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Sin(f->nValue);
				return;
			}
			break;

			// "tan"
		case tokens::TAN:
			next(); // tan
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Tan(f->nValue);
				return;
			}
			break;

			// "cos"
		case tokens::ACOS:
			next(); // acos
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Acos(f->nValue);
				return;
			}
			break;

			// "asin"
		case tokens::ASIN:
			next(); // asin
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Asin(f->nValue);
				return;
			}
			break;

			// "atan"
		case tokens::ATAN:
			next(); // tan
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Atan(f->nValue);
				return;
			}
			break;

			// "cosh"
		case tokens::COSH:
			next(); // cosh
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Cosh(f->nValue);
				return;
			}
			break;

			// "sinh"
		case tokens::SINH:
			next(); // sinh
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Sinh(f->nValue);
				return;
			}
			break;

			// "tanh"
		case tokens::TANH:
			next(); // tanh
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Tanh(f->nValue);
				return;
			}
			break;
			
			// "deg"
		case tokens::DEG:
			next(); // deg
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = 360 * f->nValue / (2*Math::PI);
				return;
			}
			break;

			// "rad"
		case tokens::RAD:
			next(); // rad
			next(); // (
			expression(f);
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = f->nValue * (2*Math::PI) / 360;
				return;
			}
			break;
			
				// "pmnt"
		case tokens::PMNT:
			next(); // pmnt
			next(); // (
			expression(arg0);
			next(); // :
			expression(arg1);
			next(); // :
			expression(arg2);
			next(); // :
			expression(arg3);			
			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				double c, m, t, i, n, cp;
				c = arg0->nValue;
				i = arg1->nValue;
				cp = arg2->nValue;
				n = arg3->nValue;

				t = i / cp;
				m = c * t / (1-Math::Pow(1 + t, -n));

				f->nValue = m;
				return;
			}
			break;

			// "amor"
		case tokens::AMOR:
			next(); // pmnt
			next(); // (
			expression(arg0);
			next(); // :
			expression(arg1);
			next(); // :
			expression(arg2);
			next(); // :
			expression(arg3);			
			next(); // :
			expression(arg4);			

			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				double c, m, t, i, n, cp, p;
				c = arg0->nValue;
				i = arg1->nValue;
				cp = arg2->nValue;
				n = arg3->nValue;
				p = arg4->nValue;

				t = i / cp;
				m = c * t / (1-Math::Pow(1 + t, -n));
				while(p-->0)
				{
					c = c * (1 + t) - m;
				}

				f->nValue = c;
				return;
			}
			break;

				// "inter"
		case tokens::INTER:
			next(); // inter
			next(); // (
			expression(arg0);
			next(); // :
			expression(arg1);
			next(); // :
			expression(arg2);
			next(); // :
			expression(arg3);			
			next(); // :
			expression(arg4);			

			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				double c, m, t, i, n, cp, p;
				c = arg0->nValue;
				i = arg1->nValue;
				cp = arg2->nValue;
				n = arg3->nValue;
				p = arg4->nValue;

				t = i / cp;
				m = c * t / (1-Math::Pow(1 + t, -n));
				double inter = 0;
				while(p-->0)
				{
					inter = c * (t);
					c = c * (1 + t) - m;
				}

				f->nValue = inter;
				return;
			}
			break;

				// "pi"
		case tokens::PI:
			next(); // pi
			f->nValue = Math::PI;
			return;			


			// "pow"
		case tokens::POW:
			next(); // pow
			next(); // (
			expression(f);

			next(); // ;
			expression(v);

			if (look_ahead() == tokens::PFERM)
			{
				next();
				log(" ) ");
				f->nValue = Math::Pow(f->nValue,v->nValue);
				return;
			}
			break;

			
			// "sum"
		case tokens::SUM:
			next(); // sum					
			if (next() == tokens::POUV)
			{
				next(); // cellule
				String^ depart = current_value;

				if (next() == tokens::DEUXPOINT)
				{
					next(); // cellule
					String^ arrive = current_value;
					if (next() == tokens::PFERM)
					{
						sum(depart, arrive, f);
						return;
					}
				}
			}
			break;


			// "avg"
		case tokens::AVG:
			next(); // avg					
			if (next() == tokens::POUV)
			{
				next(); // cellule
				String^ depart = current_value;

				if (next() == tokens::DEUXPOINT)
				{
					next(); // cellule
					String^ arrive = current_value;
					if (next() == tokens::PFERM)
					{
						avg(depart, arrive, f);
						return;
					}
				}
			}
			break;                

			// "min"
		case tokens::MIN:
			next(); // min					
			if (next() == tokens::POUV)
			{
				next(); // cellule
				String^ depart = current_value;

				if (next() == tokens::DEUXPOINT)
				{
					next(); // cellule
					String^ arrive = current_value;
					if (next() == tokens::PFERM)
					{
						min(depart, arrive, f);
						return;
					}
				}
			}
			break;

			// "max"
		case tokens::MAX:
			next(); // max					
			if (next() == tokens::POUV)
			{
				next(); // cellule
				String^ depart = current_value;

				if (next() == tokens::DEUXPOINT)
				{
					next(); // cellule
					String^ arrive = current_value;
					if (next() == tokens::PFERM)
					{
						max(depart, arrive, f);
						return;
					}
				}
			}
			break;               

			// "var"
		case tokens::VAR:
			next(); // var
			if (next() == tokens::POUV)
			{
				next(); // cellule
				String^ depart = current_value;

				if (next() == tokens::DEUXPOINT)
				{
					next(); // cellule
					String^ arrive = current_value;
					if (next() == tokens::PFERM)
					{
						var(depart, arrive, f);
						return;
					}
				}
			}
			break;                
		}

		addError("Facteur: Erreur de syntaxe près de " + current_value);
	}      
	#pragma endregion
	
	#pragma region predicat
	void Evaluator::predicat(Variant^ p)
	{
		//double g = 0, d = 0;
		Variant^ g = gcnew Variant();
		Variant^ d = gcnew Variant();
		expression(g);
		tokens la = look_ahead();
		switch (la)
		{
		case tokens::EQ:
			next();
			expression(d);
			p->bValue = (g->nValue == d->nValue);
			return;

		case tokens::NEQ:
			next();
			expression(d);
			p->bValue = (g->nValue != d->nValue);
			return;

		case tokens::LT:
			next();
			expression(d);
			p->bValue = (g->nValue < d->nValue);
			return;

		case tokens::GT:
			next();
			expression(d);
			p->bValue = (g->nValue > d->nValue);
			return;

		case tokens::LEQ:
			next();
			expression(d);
			p->bValue = (g->nValue <= d->nValue);
			return;

		case tokens::GEQ:
			next();
			expression(d);
			p->bValue = (g->nValue >= d->nValue);
			return;
		}
	}
	#pragma endregion

	#pragma region cellule
	void Evaluator::cellule(String^ name, Variant^ f)
	{
		double value = 0;		

		// un événement cherche la valeur de la cellule sans ajouter une référence à Cells
		OnGetCellValue(name, value); 
		f->nValue = value;
	}
	#pragma endregion

	#pragma region sum
	void Evaluator::sum(String^ depart, String^ arrive, Variant^ c)
	{
		log("sum({0}:{1})", depart, arrive);		

		int col1 = 0, col2 = 0;
		int row1 = 0, row2 = 0;
		CellNameToColRow(depart, col1, row1);
		CellNameToColRow(arrive, col2, row2);

		array<double,2> ^ vals;
		vals = gcnew array<double,2>(col2-col1 +1,row2-row1 +1);		
		range(depart, arrive, vals);

		c->nValue = 0;
		for (int i = 0; i <= col2-col1; i++)
			for (int j = 0; j <= row2-row1; j++)
			{				
				c->nValue = c->nValue + vals[i,j];
			}		
	}
	#pragma endregion
	
	#pragma region range
	void Evaluator::range(String^ depart,String^ arrive,array<double,2> ^ vals)
	{
		int col1 = 0, col2 = 0;
		int row1 = 0, row2 = 0;
		CellNameToColRow(depart, col1, row1);
		CellNameToColRow(arrive, col2, row2);
				
		for (int i = col1; i <= col2; i++)
			for (int j = row1; j <= row2; j++)
			{
				double value = 0;
				String^ name = ColRowToName(i, j);				
				OnGetCellValue(name, value);
				
				vals[i-col1,j-row1] = value;
			}
	}
	#pragma endregion
	
	#pragma region ColRowName
	// détermine le nom de la cellule à partir de col et row
	// col : 0.... n-1
	// row : 0.... n-1
	String^ Evaluator::ColRowToName(int col, int row)
	{
		StringBuilder^ name = gcnew StringBuilder();
		if (col < 26)
		{
			name->Append((wchar_t)(col + 'A'));
		}
		else
		{
			int c1 = col / 26;
			name->Append((wchar_t)(c1-1 + 'A'));

			col = col - 26 * c1;
			name->Append((wchar_t)(col + 'A'));
		}

		name->Append((row + 1).ToString());
		return name->ToString();
	}        
	#pragma endregion

	#pragma region regionCellNameToColRow
	void Evaluator::CellNameToColRow(String^ depart, int & col, int & row)
	{
		if (depart == nullptr || depart->Length == 0)
			return;

		if (!Char::IsLetter(depart[0]))
		{
			addError("Format de celule incorrect " + depart);
			return;
		}

		col = depart->ToUpper()[0] - 'A' +1;
		if (Char::IsLetter(depart[1]))
		{
			// AA...			
			col *= 26;
			col += depart->ToUpper()[1] - 'A' +1;

			try
			{
				row = int::Parse(depart->Substring(2));
			}
			catch(...)
			{
				row = 0;
				addError("Format de cellule incorrect " + depart);
			}
		}
		else
		{
			// A...
			try
			{
				row = int::Parse(depart->Substring(1));
			}
			catch(...)
			{
				row = 0;
				addError("Format de cellule incorrect " + depart);
			}
		}		

		// 0 based index
		col--;
		row--;
	}
	#pragma endregion

	#pragma region avg
	void Evaluator::avg(String^ depart, String^ arrive, Variant^ c)
	{
		log("avg({0}:{1})", depart, arrive);
		int col1 = 0, col2 = 0;
		int row1 = 0, row2 = 0;
		CellNameToColRow(depart,  col1,  row1);
		CellNameToColRow(arrive,  col2,  row2);

		array<double,2> ^ vals;
		vals = gcnew array<double,2>(col2-col1 +1,row2-row1 +1);		
		range(depart, arrive, vals);

		c->nValue = 0;
		
		double d = 0;
		for (int i = 0; i <= col2-col1; i++)
			for (int j = 0; j <= row2-row1; j++)
			{
				c->nValue = c->nValue + vals[i,j];
				d = d + 1;
			}
			if (d > 0)
				c->nValue = c->nValue / d;
	}
	#pragma endregion

	#pragma region min
	void Evaluator::min(String^ depart, String^ arrive, Variant^ c)
	{
		log("min({0}:{1})", depart, arrive);
		int col1 = 0, col2 = 0;
		int row1 = 0, row2 = 0;
		CellNameToColRow(depart, col1, row1);
		CellNameToColRow(arrive, col2, row2);

		array<double,2> ^ vals;
		vals = gcnew array<double,2>(col2-col1 +1,row2-row1 +1);		
		range(depart, arrive, vals);

		c->nValue = 0;
		
		bool first = false;
		for (int i = 0; i <= col2-col1; i++)
			for (int j = 0; j <= row2-row1; j++)
			{
				double value = vals[i,j];				
				if (!first)
				{
					first = true;
					c->nValue = value;
				}
				else
					if (value < c->nValue)
						c->nValue = value;
			}
	}
	#pragma endregion

	#pragma region max
	void Evaluator::max(String^ depart, String^ arrive, Variant^ c)
	{
		log("max({0}:{1})", depart, arrive);
		int col1 = 0, col2 = 0;
		int row1 = 0, row2 = 0;
		CellNameToColRow(depart, col1, row1);
		CellNameToColRow(arrive, col2, row2);

		array<double,2> ^ vals;
		vals = gcnew array<double,2>(col2-col1 +1,row2-row1 +1);		
		range(depart, arrive, vals);

		c->nValue = 0;
		
		bool first = false;
		for (int i = 0; i <= col2-col1; i++)
			for (int j = 0; j <= row2-row1; j++)
			{
				double value = vals[i,j];
				
				if (!first)
				{
					first = true;
					c->nValue = value;
				}
				else
					if (value > c->nValue)
						c->nValue = value;
			}
	}
	#pragma endregion

	#pragma region var
	void Evaluator::var(String^ depart, String^ arrive, Variant^ c)
	{
		log("sum({0}:{1})", depart, arrive);
		int col1 = 0, col2 = 0;
		int row1 = 0, row2 = 0;
		CellNameToColRow(depart, col1, row1);
		CellNameToColRow(arrive, col2, row2);

		array<double,2> ^ vals;
		vals = gcnew array<double,2>(col2-col1 +1,row2-row1 +1);		
		range(depart, arrive, vals);

		c->nValue = 0;

		Variant^ av = gcnew Variant();
		avg(depart, arrive, av);

		int n = 0;
		for (int i = 0; i <= col2-col1; i++)
			for (int j = 0; j <= row2-row1; j++)
			{
				double value = vals[i,j];				
				c->nValue += Math::Pow(value - av->nValue, 2);
				n++;
			}

			c->nValue = c->nValue / (n - 1);
	}
	#pragma endregion

	#pragma region log
	void Evaluator::log(String^ message, ... array<System::Object^> ^ p )
	{
		if (debug)
			Console::WriteLine(message, p);
	}
	#pragma endregion
	
	#pragma region parse
	String^ Evaluator::parse()
	{
		errors = gcnew StringBuilder();
		// S est l'axiome (le point de départ)
		Variant^ res = S();
		switch(res->Type)
		{
		case Variant::VType::NUMBER:
			return "" + res->nValue;

		default:
			return res->sValue;
		}		
	}	
	#pragma endregion

	#pragma region Errors
	StringBuilder^ Evaluator::getErrors()
	{        
		return errors; 
	}

	void Evaluator::setErreors(StringBuilder^ value) 
	{ 
		errors = value; 
	}

	void Evaluator::addError(String^ message) 
	{
		hasErrors = true;
		errors->Append(message);
		errors->Append("\n");
	}        
	#pragma endregion 

	#pragma region Evaluator
	Evaluator::Evaluator() 
	{
		text = "";
		debug = false;
		reader = nullptr;
		errors = gcnew StringBuilder();
		has_next = false;
	}
	#pragma endregion 

	#pragma region Text / Reader
	String^ Evaluator::getText() 
	{
		return text; 
	}

	void Evaluator::setText(String^ value)
	{            
		text = value;
		reader = gcnew StringReader(text);            
	}

	StringReader^ Evaluator::getReader() 
	{
		return reader; 
	}

	void Evaluator::setReader(StringReader^ value)
	{
		reader = value; 
	}
	#pragma endregion 

	#pragma endregion 

	/*
	* Analyseur lexical
	*/
	#pragma region Analyseur lexical
	#pragma region back
	void Evaluator::back()
	{
		next_value = current_value;
		next_token = current_token;
		has_next = true;
	}
	#pragma endregion 

	#pragma region look_ahead
	Evaluator::tokens Evaluator::look_ahead()
	{
		// lit le prochain token sans le consommer
		tokens t = next();
		if (t != Evaluator::tokens::EOF)
			back();
		return t;
	}
	#pragma endregion 

	#pragma region next
	Evaluator::tokens Evaluator::next()
	{
		// avance d'un token		
		if (has_next)
		{
			has_next = false;
			current_token = next_token;
			current_value = next_value;
			return current_token;
		}

		StringBuilder^ token = gcnew StringBuilder();
		int c;
		while ((c = reader->Read()) != -1)
		{
			switch (c)
			{
				// "default"
			default:
				token->Append((wchar_t)c);
				switch (reader->Peek())
				{
					// séparateur : indique la fin du token
				case ' ':
				case -1:
				case '+':
				case '*':
				case '/':
				case '-':
				case '(':
				case ')':
				case ':':
				case ';':
				case '<':
				case '>':
				case '=':
				case '\"':

					current_value = token->ToString();
					String^ t = token->ToString()->ToLower();
					
					if( t == "sum") {
						current_token = tokens::SUM;
						return current_token;
					}

					if( t== "avg" ) {
						current_token = tokens::AVG;
						return current_token;
					}

					if( t== "min") {
						current_token = tokens::MIN;
						return current_token;
					}

					if( t== "max") {
						current_token = tokens::MAX;
						return current_token;
					}

					if( t== "var") {
						current_token = tokens::VAR;
						return current_token;
					}

					if( t== "sqrt") {
						current_token = tokens::SQRT;
						return current_token;
					}

					if( t== "if" ) {
						current_token = tokens::IF;
						return current_token;
					}

					if( t=="abs") {
						current_token = tokens::ABS;
						return current_token;
					}

					if( t=="arr") {
						current_token = tokens::ARR;
						return current_token;
					}


					if( t=="ln") {
						current_token = tokens::LN;
						return current_token;
					}


					if( t=="log") {
						current_token = tokens::LOG10;
						return current_token;
					}


					if( t=="exp") {
						current_token = tokens::EXP;
						return current_token;
					}


					if( t=="pow") {
						current_token = tokens::POW;
						return current_token;
					}
		
					if( t=="fac") {
						current_token = tokens::FAC;
						return current_token;
					}


					if( t=="cos") {
						current_token = tokens::COS;
						return current_token;
					}


					if( t=="sin") {
						current_token = tokens::SIN;
						return current_token;
					}


					if( t=="tan") {
						current_token = tokens::TAN;
						return current_token;
					}
							
					if( t=="cosh") {
						current_token = tokens::COSH;
						return current_token;
					}


					if( t=="sinh") {
						current_token = tokens::SINH;
						return current_token;
					}

					if( t=="tanh") {
						current_token = tokens::TANH;
						return current_token;
					}									

					if( t=="acos") {
						current_token = tokens::ACOS;
						return current_token;
					}


					if( t=="asin") {
						current_token = tokens::ASIN;
						return current_token;
					}

					if( t=="atan") {
						current_token = tokens::ATAN;
						return current_token;
					}

					if( t=="deg") {
						current_token = tokens::DEG;
						return current_token;
					}

					if( t=="rad") {
						current_token = tokens::RAD;
						return current_token;
					}

					if( t=="pi") {
						current_token = tokens::PI;
						return current_token;
					}

					
					if( t=="pmnt") {
						current_token = tokens::PMNT;
						return current_token;
					}

					if( t=="amor") {
						current_token = tokens::AMOR;
						return current_token;
					}

					if( t=="inter") {
						current_token = tokens::INTER;
						return current_token;
					}

					// fin de token : c'est du texte text
					current_token = tokens::TEXT;
					return current_token;
				}
				break;

			case ' ':
				// ignorer
				break;

				// ":"
			case ':':
				current_token = tokens::DEUXPOINT;
				current_value = "=";
				return current_token;

			case '\"':
				current_token = tokens::QUOTE;
				current_value = "\"";
				return current_token;

				// "("
			case '(':
				current_token = tokens::POUV;
				current_value = "(";
				return current_token;

				// ")"
			case ')':
				current_token = tokens::PFERM;
				current_value = ")";
				return current_token;                    

				// "+"
			case '+':
				current_token = tokens::PLUS;
				current_value = "+";
				return current_token;                    

				// "-"
			case '-':
				current_token = tokens::MOINS;
				current_value = "-";
				return current_token;

				// "/"
			case '/':
				current_token = tokens::DIV;
				current_value = "/";
				return current_token;

				// "*"
			case '*':
				current_token = tokens::MUL;
				current_value = "*";
				return current_token;                    

				// ";"
			case ';':
				current_token = tokens::SEMI;
				current_value = ";";
				return current_token;                    

				// "<"
			case '<':
				switch (reader->Peek())
				{
				case '=':
					reader->Read();
					current_token = tokens::LEQ;
					current_value = "<=";
					return current_token;

				case '>':
					reader->Read();
					current_token = tokens::NEQ;
					current_value = "<>";
					return current_token;

				default:
					current_token = tokens::LT;
					current_value = "<";
					return current_token;
				}

				// ">"
			case '>':
				switch (reader->Peek())
				{
				case '=':
					reader->Read();
					current_token = tokens::GEQ;
					current_value = ">=";
					return current_token;

				default:
					current_token = tokens::GT;
					current_value = ">";
					return current_token;
				}                    

				// "="
			case '=':
				current_token = tokens::EQ;
				current_value = ";";
				return current_token;                    
			}
		}

		return tokens::EOF;
	}
	#pragma endregion 

	#pragma region GetNames
	array<String^>^ Evaluator::GetNames(String^ formula)
	{
		List<String^>^ res = gcnew List<String^>();

		String^ sep = "[\\+=\\-/\\(\\):]";
		String^ masque = "([a-zA-Z][a-zA-Z]?\\d\\d?\\d?)";

		Regex^ rg = gcnew Regex(sep + "?" + masque + sep + "?");
		MatchCollection^ mc = rg->Matches(formula);
		for(int i=0;i<mc->Count;i++)
			//foreach (Match m in mc)
		{
			Match^ m=mc[i];
			if (m->Groups->Count > 1)
				res->Add(m->Groups[1]->Value);
		}
		return res->ToArray();
	}	
	#pragma endregion 
	#pragma endregion 
}
