//  
//  ParseExpr.cs
//  
//  Author:
//       Robert BRACCAGNI alias Gai-Luron <lfsgailuron@free.fr>
// 
//  Copyright (c) 2010 Gai-Luron
// 
//  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 3 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, see <http://www.gnu.org/licenses/>.

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;


namespace GLScript
{
    public class ParseException : Exception
    {
        public ParseException(string message) : base(message) { }
        public ParseException(string message, Exception innerException) : base(message, innerException) { }
    }

/*
    public class unionVal
    {
        public float var_fval;
        public string var_sval;
        public typVal typVal;
        public string nameVar;
        public ArrayList ArgsVals = new ArrayList();
        public unionVal(float pfval, string psval, typVal ptypval)
        {
            this.fval = pfval;
            this.sval = psval;
            this.typVal = ptypval;
        }
        public float fval
        {
            get
            {
                return var_fval;
            }
            set
            {
                var_fval = value;
            }
        }
        public string sval
        {
            get
            {
                return var_sval;
            }
            set
            {
                var_sval = value;
            }

        }
    }
*/
    public delegate unionVal CallBackSetDef(string id, unionVal val, string userName );
    public delegate unionVal CallBackGetDef(string id, string userName );
    public class unionVal
    {
        public ArrayList ar_fval = new ArrayList();
        public ArrayList ar_sval = new ArrayList();
        public typVal typVal;
        public string nameVar;
        public string nameFunction;
        public bool typArray = false;
        public bool typfunction = false;
        public SetOfVars setVars;
        public ArrayList ArgsVals = new ArrayList();
        public CallBackSetDef CallBackSet = null;
        public CallBackGetDef CallBackGet = null;
        public string CallBackArg = "";

        public unionVal( unionVal pval )
        {
            float tmpf;
            for (int i = 0; i < pval.ar_fval.Count; i++)
            {
                tmpf = (float)pval.ar_fval[i];
                this.ar_fval.Add(tmpf);
            }
            string tmps;
            for (int i = 0; i < pval.ar_fval.Count; i++)
            {
                tmps = (string)pval.ar_sval[i];
                this.ar_sval.Add(tmps);
            }
			this.typVal = pval.typVal;
			this.nameVar = pval.nameVar;
			this.nameFunction = pval.nameFunction;
			this.typArray = pval.typArray;
			this.typfunction = pval.typfunction;
			this.setVars = pval.setVars;
			this.ArgsVals = pval.ArgsVals;
			this.CallBackGet = pval.CallBackGet;
            this.CallBackSet = pval.CallBackSet;
            this.CallBackArg = pval.CallBackArg;
        }
        public unionVal(float pfval, string psval, typVal ptypval)
        {
            this.fval = pfval;
            this.sval = psval;
            this.typVal = ptypval;
        }
        public unionVal(float pfval, string psval, typVal ptypval,CallBackSetDef CBSet, CallBackGetDef CBGet, string CBArg  )
        {
            this.fval = pfval;
            this.sval = psval;
            this.typVal = ptypval;
            this.CallBackSet = CBSet;
            this.CallBackGet = CBGet;
            this.CallBackArg = CBArg;
        }
        public void add(float pval)
        {
            this.ar_fval.Add(pval);
        }
        public void add(string pval)
        {
            this.ar_sval.Add(pval);
        }
        public void clear()
        {
            ar_fval.Clear();
            ar_sval.Clear();
        }
        public void strSort()
        {
            ar_sval.Sort();
        }

        public float fval
        {
            get
            {
                float fret = 0;
                try
                {
                    fret = (float)ar_fval[0];
                }
                catch
                {
                    fret = 0;
                }
                return fret;
            }
            set
            {
                ar_fval.Clear();
                add((float)value);
            }
        }
        public string sval
        {
            get
            {
                string str = "";
                try
                {
                    str = (string)ar_sval[0];
                }
                catch
                {
                    str = "\"\"";
                }
                return str;
            }
            set
            {
                ar_sval.Clear();
                add((string)value);
            }

        }

    }
    public enum typVal
    {
        num,
        str,
        var,
        arrayVar,
        ident,
        function,
        undef,
        setOfVar
    }

    public class Parseur
    {

        private enum tokenExpr
        {
            notfound, // is the priority of the operator, less than high
            assign,
            and,
            or,
            boolAnd,
            boolOr,
            equal,
            diff,
            moreThan,
            lessThan,
            moreThanEqual,
            lessThanEqual,
            concat,
			plus,
            minus,
            mult,
            div,
			pow,
			not,
			neg,
			pos,
			nbVal,
        }
        private Parseur expra;
        private Parseur exprb;
        private tokenExpr operateur;
        

        public unionVal val = new unionVal(0, "", typVal.undef);
/*
        public Parseur( string fileName, string strSrc )
        {
            TokenBuffer tkbuff = new TokenBuffer(strSrc,fileName, 1);
            goParse(tkbuff, 0, tkbuff.TokenList.Count - 1);
        }
*/
        public Parseur( TokenBuffer ptokens)
        {
            goParse(ptokens, 0, ptokens.TokenList.Count - 1);
        }
        public Parseur( TokenBuffer ptokens, int pstartBloc, int pendBloc )
        {
            goParse(ptokens, pstartBloc, pendBloc );
        }
		private tokenExpr toTokenExpr( int typ )
		{
			
			switch( typ ){
				case Scanner.E_ASSIGN:
					return tokenExpr.assign;
				case Scanner.E_AND:
					return tokenExpr.and;
				case Scanner.E_OR:
					return tokenExpr.or;
				case Scanner.E_BOOL_AND:
					return tokenExpr.boolAnd;
				case Scanner.E_BOOL_OR:
					return tokenExpr.boolOr;
				case Scanner.E_EQUAL:
					return tokenExpr.equal;
				case Scanner.E_DIFF:
					return tokenExpr.diff;
				case Scanner.E_MORE_EQUAL:
					return tokenExpr.moreThanEqual;
				case Scanner.E_LESS_EQUAL:
					return tokenExpr.lessThanEqual;
				case Scanner.E_MORE:
					return tokenExpr.moreThan;
				case Scanner.E_LESS:
					return tokenExpr.lessThan;
				case Scanner.E_POINT:
					return tokenExpr.concat;
				case Scanner.E_PLUS:
					return tokenExpr.plus;
				case Scanner.E_MOINS:
					return tokenExpr.minus;
				case Scanner.E_MULT:
					return tokenExpr.mult;
				case Scanner.E_DIV:
					return tokenExpr.div;
				case Scanner.E_POW:
					return tokenExpr.pow;
				case Scanner.E_NOT:
					return tokenExpr.not;
				case Scanner.E_NEG:
					return tokenExpr.neg;
				case Scanner.E_POS:
					return tokenExpr.pos;
				default:
					return tokenExpr.notfound;
			}

		}
		private void goParse(TokenBuffer tokens, int startBloc, int endBloc)
		{
			token myToken;

			this.expra = null;
			this.exprb = null;
			this.operateur = tokenExpr.notfound;

			int nbToken = endBloc - startBloc + 1;
			switch (nbToken)
			{
				case 0:
					this.val.sval = "\"\"";
					this.val.typVal = typVal.str;
					break;
				case 1:
					myToken = (token)tokens.TokenList[startBloc];
					if (myToken.typ == Scanner.E_STRING)
					{
						this.val.sval = myToken.value;
						this.val.typVal = typVal.str;
					}
					else if (myToken.typ == Scanner.E_VAR)
					{
						this.val.typVal = typVal.var;
						this.val.sval = myToken.value.Substring(1);
						this.val.nameVar = myToken.value.Substring(1);
					}
					else if (myToken.typ == Scanner.E_INTEGER || myToken.typ == Scanner.E_FLOAT)
					{
						this.val.fval = float.Parse(myToken.value);
						this.val.typVal = typVal.num;
					}
					else if (myToken.typ == Scanner.E_IDENT)
					{
						this.val.typVal = typVal.str;
						this.val.sval = "\"" + myToken.value + "\"";
					}
					if (myToken.typ == Scanner.E_ARVAR)
					{
						this.val.typVal = typVal.arrayVar;
						this.val.sval = myToken.value.Substring(1, myToken.value.IndexOf('[') - 1);
						this.val.nameVar = this.val.sval;
						for (int i = 0; i < myToken.args.Count; i++)
						{
							TokenBuffer tkBuff = (TokenBuffer)myToken.args[i];
							this.val.ArgsVals.Add(new Parseur(tkBuff, 0, tkBuff.TokenList.Count - 1));
						}
					}

                    //Detect a function
					if (myToken.typ == Scanner.E_FUNCTION)
					{
						this.val.typVal = typVal.function;
						this.val.sval = "";
						this.val.nameFunction = myToken.value.Substring(0, myToken.value.IndexOf('(')).Trim();
						for (int i = 0; i < myToken.args.Count; i++)
						{
							TokenBuffer tkBuff = (TokenBuffer)myToken.args[i];
							this.val.ArgsVals.Add(new Parseur(tkBuff, 0, tkBuff.TokenList.Count - 1));
						}
					}
					break;
				default:
					myToken = (token)tokens.TokenList[startBloc];
					this.val.typVal = typVal.undef;
					int p = 0;
					int cp0 = 0;

					//on split par la plus petite priorité disponible
					int splitAt = -1;
					tokenExpr minPriorityToken = tokenExpr.nbVal;
					for (int i = startBloc; i <= endBloc; i++) // Onrecherche le token de plus basse priorité présent dans la liste
					{
						myToken = (token)tokens.TokenList[i];
						if (myToken.typ == Scanner.E_END)
							break;
						if (p == 0)
						{
							cp0++;
						}
						if (myToken.typ == Scanner.E_PAR_OPEN)
							p++;
						else if (myToken.typ == Scanner.E_PAR_CLOSE)
							p--;
						else if (p == 0) // Si pas dans une expression parenthèse, chercher le prochain caractère de split
						{
							tokenExpr token = toTokenExpr(myToken.typ);
							if (token != tokenExpr.notfound)
							{
								if ((int)token < (int)minPriorityToken)
								{
									minPriorityToken = token;
									splitAt = i;
								}
							}
						}
					}
                   
					if (splitAt != -1) // S'il y a un split du aux opérateurs
					{
						this.operateur = minPriorityToken;
						this.expra = new Parseur(tokens, startBloc, splitAt - 1);
						this.exprb = new Parseur(tokens, splitAt + 1, endBloc);
					}
					else
					{ // S'il n'y a pas de split d'opérateurs c'est qu'il y a des parenthèses, car sinon un seul token
						myToken = (token)tokens.TokenList[startBloc];
						this.expra = new Parseur(tokens, startBloc + 1, endBloc - 1);
					}
					break;
			}
		}
	/*	private void goParseold(TokenBuffer tokens, int startBloc, int endBloc)
		{
			token myToken;
			this.expra = null;
			this.exprb = null;
			this.operateur = tokenExpr.notfound;

			int nbToken = endBloc - startBloc + 1;
			if (nbToken == 0)
			{
				this.val.sval = "\"\"";
				this.val.typVal = typVal.str;
				return;
			}
			if (nbToken == 1)
			{
				myToken = (token)tokens.TokenList[startBloc];
				if (myToken.typ == Scanner.E_STRING)
				{
					this.val.sval = myToken.value;
					this.val.typVal = typVal.str;
				}
				else if (myToken.typ == Scanner.E_VAR)
				{
					this.val.typVal = typVal.var;
					this.val.sval = myToken.value.Substring(1);
					this.val.nameVar = myToken.value.Substring(1);
				}
				else if (myToken.typ == Scanner.E_INTEGER || myToken.typ == Scanner.E_FLOAT)
				{
					this.val.fval = float.Parse(myToken.value);
					this.val.typVal = typVal.num;
				}
				else if (myToken.typ == Scanner.E_IDENT)
				{
					this.val.typVal = typVal.str;
					this.val.sval = "\"" + myToken.value + "\"";
				}
				if (myToken.typ == Scanner.E_ARVAR)
				{
					this.val.typVal = typVal.arrayVar;
					this.val.sval = myToken.value.Substring(1, myToken.value.IndexOf('[') - 1);
					this.val.nameVar = this.val.sval;
					for (int i = 0; i < myToken.args.Count; i++)
					{
						TokenBuffer tkBuff = (TokenBuffer)myToken.args[i];
						this.val.ArgsVals.Add(new Parseur(tkBuff, 0, tkBuff.TokenList.Count - 1));
					}
				}
				if (myToken.typ == Scanner.E_FUNCTION)
				{
					this.val.typVal = typVal.function;
					this.val.sval = "";
					this.val.nameFunction = myToken.value.Substring(0, myToken.value.IndexOf('(')).Trim();
					for (int i = 0; i < myToken.args.Count; i++)
					{
						TokenBuffer tkBuff = (TokenBuffer)myToken.args[i];
						this.val.ArgsVals.Add(new Parseur(tkBuff, 0, tkBuff.TokenList.Count - 1));
					}
				}
				return;
			}
			myToken = (token)tokens.TokenList[startBloc];
			this.val.typVal = typVal.undef;
			int p = 0;
			int cp0 = 0;
			//on recupere la liste des operateurs
			bool[] operateurs = new bool[(int)tokenExpr.nbVal];

			for (int i = 0; i < (int)tokenExpr.nbVal; i++)
				operateurs[i] = true;

			//on recupere la liste des operateurs
			for (int i = startBloc; i <= endBloc; i++) // Onrecherche le token de plus basse priorité présent dans la liste
			{
				myToken = (token)tokens.TokenList[i];
				if (myToken.typ == Scanner.E_END)
					break;
				if (myToken.typ == Scanner.E_PAR_OPEN)
					p++;
				else if (myToken.typ == Scanner.E_PAR_CLOSE)
					p--;
				else if (p == 0)
				{
					tokenExpr token = tokenExpr.notfound;
					if (myToken.typ == Scanner.E_ASSIGN) // plus basse priorité
						token = tokenExpr.assign;
					else if (myToken.typ == Scanner.E_AND)
						token = tokenExpr.and;
					else if (myToken.typ == Scanner.E_OR)
						token = tokenExpr.or;
					else if (myToken.typ == Scanner.E_BOOL_AND)
						token = tokenExpr.boolAnd;
					else if (myToken.typ == Scanner.E_BOOL_OR)
						token = tokenExpr.boolOr;
					else if (myToken.typ == Scanner.E_EQUAL)
						token = tokenExpr.equal;
					else if (myToken.typ == Scanner.E_DIFF)
						token = tokenExpr.diff;
					else if (myToken.typ == Scanner.E_MORE_EQUAL)
						token = tokenExpr.moreThanEqual;
					else if (myToken.typ == Scanner.E_LESS_EQUAL)
						token = tokenExpr.lessThanEqual;
					else if (myToken.typ == Scanner.E_MORE)
						token = tokenExpr.moreThan;
					else if (myToken.typ == Scanner.E_LESS)
						token = tokenExpr.lessThan;
					else if (myToken.typ == Scanner.E_POINT)
						token = tokenExpr.concat;
					else if (myToken.typ == Scanner.E_PLUS)
						token = tokenExpr.plus;
					else if (myToken.typ == Scanner.E_MOINS)
						token = tokenExpr.minus;
					else if (myToken.typ == Scanner.E_MULT)
						token = tokenExpr.mult;
					else if (myToken.typ == Scanner.E_DIV)
						token = tokenExpr.div;
					else if (myToken.typ == Scanner.E_POW) //plus haute priorité
						token = tokenExpr.pow;
					if (token != tokenExpr.notfound)
					{
						for (int j = (int)token + 1; j < (int)tokenExpr.nbVal; j++) //
							operateurs[j] = false;
					}
				}
			}
			if (p != 0)
			{
				throw new ParseException("Incorrect number of parenthesis");
			}
			for (int i = endBloc; i >= startBloc; i--)
			{
				myToken = (token)tokens.TokenList[i];
				if (myToken.typ == Scanner.E_END)
					continue;

				if (p == 0)
				{
					cp0++;
				}
				tokenExpr token = tokenExpr.notfound;
				if (myToken.typ == Scanner.E_ASSIGN)
					token = tokenExpr.assign;
				else if (myToken.typ == Scanner.E_AND)
					token = tokenExpr.and;
				else if (myToken.typ == Scanner.E_OR)
					token = tokenExpr.or;
				else if (myToken.typ == Scanner.E_BOOL_AND)
					token = tokenExpr.boolAnd;
				else if (myToken.typ == Scanner.E_BOOL_OR)
					token = tokenExpr.boolOr;
				else if (myToken.typ == Scanner.E_EQUAL)
					token = tokenExpr.equal;
				else if (myToken.typ == Scanner.E_DIFF)
					token = tokenExpr.diff;
				else if (myToken.typ == Scanner.E_MORE_EQUAL)
					token = tokenExpr.moreThanEqual;
				else if (myToken.typ == Scanner.E_LESS_EQUAL)
					token = tokenExpr.lessThanEqual;
				else if (myToken.typ == Scanner.E_MORE)
					token = tokenExpr.moreThan;
				else if (myToken.typ == Scanner.E_LESS)
					token = tokenExpr.lessThan;
				else if (myToken.typ == Scanner.E_POINT)
					token = tokenExpr.concat;
				else if (myToken.typ == Scanner.E_PLUS)
					token = tokenExpr.plus;
				else if (myToken.typ == Scanner.E_MOINS)
					token = tokenExpr.minus;
				else if (myToken.typ == Scanner.E_MULT)
					token = tokenExpr.mult;
				else if (myToken.typ == Scanner.E_DIV)
					token = tokenExpr.div;
				else if (myToken.typ == Scanner.E_POW)
					token = tokenExpr.pow;

				if (myToken.typ == Scanner.E_PAR_OPEN)
					p++;
				else if (myToken.typ == Scanner.E_PAR_CLOSE)
					p--;
				else if (p == 0 && (token != tokenExpr.notfound) && (bool)operateurs[(int)token])
				{
					this.operateur = token;
					this.expra = new Parseur(tokens, startBloc, i - 1);
					this.exprb = new Parseur(tokens, i + 1, endBloc);
					break;
				}
			}

			if (this.expra == null && cp0 == 1)
			{
				myToken = (token)tokens.TokenList[startBloc];
				if ((endBloc - startBloc + 1) == 3)
				{
					token myToken2 = (token)tokens.TokenList[startBloc + 1];
					if (myToken2.typ == Scanner.E_STRING)
					{
						this.val.sval = myToken2.value;
						this.val.typVal = typVal.str;
					}
					else if (myToken2.typ == Scanner.E_VAR)
					{
						this.val.sval = myToken2.value;
						this.val.typVal = typVal.var;
					}
					else if (myToken2.typ == Scanner.E_ARVAR)
					{
						this.val.sval = myToken2.value;
						this.val.typVal = typVal.var;
					}
					else if (myToken2.typ == Scanner.E_INTEGER || myToken2.typ == Scanner.E_FLOAT)
					{
						this.val.fval = float.Parse(myToken2.value);
						this.val.typVal = typVal.num;
					}
				}
				else
				{
					this.expra = new Parseur(tokens, startBloc + 1, endBloc - 1);
				}
			}
		} */

        public string ToRPN()
        {
            if (this.val.typVal != typVal.undef)
            {
                if (this.val.typVal == typVal.num)
                    return this.val.fval.ToString();
                else if (this.val.typVal == typVal.str)
                    return this.val.sval;
                else if (this.val.typVal == typVal.var)
                    return this.val.sval;
                else if (this.val.typVal == typVal.arrayVar)
                {
                    return this.val.nameVar + "[" + "]";
                }
                else if (this.val.typVal == typVal.function)
                    return this.val.nameFunction;
            }
            else if (this.exprb == null && this.expra != null)
            {
                return this.expra.ToRPN();
            }
            else if (this.expra == null && this.exprb != null)
            {
                if (this.operateur != tokenExpr.notfound)
                    return this.exprb.ToRPN() + " " + this.operateur;
                else
                    return this.exprb.ToRPN();
            }
            else if (this.expra != null && this.exprb != null)
            {
                return this.expra.ToRPN() + " " + this.exprb.ToRPN() + " " + this.operateur;
            }
            return "";
        }
        private float numval(string str)
        {
            try
            {
                float val = float.Parse(str);
                return val;
            }
            catch
            {
                return 0;
            }
        }
        public delegate void executeParsedFunction(SetOfVars gv, SetOfVars lv, unionVal var, ArrayList ar );
        public unionVal getval(SetOfVars GVAR, SetOfVars LVAR, executeParsedFunction BC)
        {
                if (this.val.typVal != typVal.undef)
                {
                    //				if (this.val.typVal == typVal.var || this.val.typVal == typVal.arrayVar)
                    if (this.val.nameVar != null && this.val.nameVar != "")
                        replaceVarByValue(this.val, GVAR, LVAR, BC);
                    //				if (this.val.typVal == typVal.function)
                    if (this.val.nameFunction != null && this.val.nameFunction != "")
                        BC(GVAR, LVAR, this.val, retreiveArgs(GVAR, LVAR, BC));
                    return this.val;
                }
                else if (this.exprb == null)
                {
                    if (this.expra == null)
                        throw new ParseException("suspected error in order of the operators");
                    else
                        return this.expra.getval(GVAR, LVAR, BC);
                }
                unionVal reta = this.expra.getval(GVAR, LVAR, BC);
                unionVal retb = this.exprb.getval(GVAR, LVAR, BC);
                /*
                            if (this.operateur != tokenExpr.assign)
                            {
                                if (reta.typVal == typVal.var || reta.typVal == typVal.arrayVar)
                                    replaceVarByValue(reta,GVAR, LVAR,BC );
                                if (retb.typVal == typVal.var || reta.typVal == typVal.arrayVar)
                                    replaceVarByValue(retb, GVAR, LVAR,BC);
                            }
                            if (reta.typVal == typVal.function)
                                BC(GVAR, LVAR, reta, retreiveArgs(GVAR, LVAR, BC));
                            if (retb.typVal == typVal.function)
                                BC(GVAR, LVAR, retb, retreiveArgs(GVAR, LVAR, BC));
                */
                if (this.operateur == tokenExpr.equal
                    || this.operateur == tokenExpr.diff
                    || this.operateur == tokenExpr.moreThan
                    || this.operateur == tokenExpr.lessThan
                    || this.operateur == tokenExpr.moreThanEqual
                    || this.operateur == tokenExpr.lessThanEqual
                    )
                {
                    if (reta.typVal == typVal.str || retb.typVal == typVal.str)
                    {
                        if (reta.typVal != typVal.str)
                        {
                            reta.typVal = typVal.str;
                            reta.sval = "\"" + reta.fval.ToString() + "\"";
                        }
                        if (retb.typVal != typVal.str)
                        {
                            retb.typVal = typVal.str;
                            retb.sval = "\"" + retb.fval.ToString() + "\"";
                        }
                    }

                }
                if (this.operateur == tokenExpr.concat)
                {
                    if (reta.typVal == typVal.num)
                    {
                        reta.sval = "\"" + reta.fval.ToString() + "\"";
                        reta.typVal = typVal.str;
                    }
                    if (retb.typVal == typVal.num)
                    {
                        retb.sval = "\"" + retb.fval.ToString() + "\"";
                        retb.typVal = typVal.str;
                    }
                }
                if (this.operateur == tokenExpr.plus
                    || this.operateur == tokenExpr.or
                    || this.operateur == tokenExpr.and
                    || this.operateur == tokenExpr.minus
                    || this.operateur == tokenExpr.mult
                    || this.operateur == tokenExpr.div
                    || this.operateur == tokenExpr.boolAnd
                    || this.operateur == tokenExpr.boolOr
                    || this.operateur == tokenExpr.pow
                    )
                {
                    if (reta.typVal == typVal.str)
                    {
                        reta.fval = this.numval(unquote(reta.sval));
                        reta.typVal = typVal.num;
                    }
                    if (retb.typVal == typVal.str)
                    {
                        retb.fval = this.numval(unquote(retb.sval));
                        retb.typVal = typVal.num;
                    }
                }
            switch (this.operateur)
            {
                case tokenExpr.assign:
                    // Faire ici l'assignation
                    // unionVal retValue = new unionVal(retb.fval, retb.sval, retb.typVal);
                    assignValueToVar(reta, retb, GVAR, LVAR,BC);
                    return retb;
                case tokenExpr.and:
                    if (reta.fval != 0 && retb.fval != 0)
                        return new unionVal(1, "", typVal.num);
                    else
                        return new unionVal(0, "", typVal.num);
                case tokenExpr.or:
                    if (reta.fval != 0 || retb.fval != 0)
                        return new unionVal(1, "", typVal.num);
                    else
                        return new unionVal(0, "", typVal.num);
                case tokenExpr.equal:
                    if (reta.typVal == typVal.str)
                    {
                        if (reta.sval == retb.sval)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                    else
                    {
                        if (reta.fval == retb.fval)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                case tokenExpr.diff:
                    if (reta.typVal == typVal.str)
                    {
                        if (reta.sval != retb.sval)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                    else
                    {
                        if (reta.fval != retb.fval)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                case tokenExpr.moreThan:
                    if (reta.typVal == typVal.str)
                    {
                        if (string.Compare(reta.sval, retb.sval) > 0)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                    else
                    {
                        if (reta.fval > retb.fval)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                case tokenExpr.moreThanEqual:
                    if (reta.typVal == typVal.str)
                    {
                        if (string.Compare(reta.sval, retb.sval) >= 0)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                    else
                    {
                        if (reta.fval >= retb.fval)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                case tokenExpr.lessThan:
                    if (reta.typVal == typVal.str)
                    {
                        if (string.Compare(reta.sval, retb.sval) < 0)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                    else
                    {
                        if (reta.fval < retb.fval)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                case tokenExpr.lessThanEqual:
                    if (reta.typVal == typVal.str)
                    {
                        if (string.Compare(reta.sval, retb.sval) <= 0)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }
                    else
                    {
                        if (reta.fval <= retb.fval)
                            return new unionVal(1, "", typVal.num);
                        else
                            return new unionVal(0, "", typVal.num);
                    }

				case tokenExpr.neg:
					return new unionVal(-retb.fval, "", typVal.num);
				case tokenExpr.pos:
					return new unionVal(retb.fval, "", typVal.num);
				case tokenExpr.not:
					if (retb.fval > 0)
						retb.fval = 0;
					else
						retb.fval = 1;
					return new unionVal(retb.fval, "", typVal.num);
				case tokenExpr.concat:
					return new unionVal(0, "\"" + unquote(reta.sval) + unquote(retb.sval) + "\"", typVal.str);
				case tokenExpr.plus:
                        return new unionVal(reta.fval + retb.fval, "", typVal.num);
                case tokenExpr.minus:
                    return new unionVal(reta.fval - retb.fval, "", typVal.num);
                case tokenExpr.mult:
                    return new unionVal(reta.fval * retb.fval, "", typVal.num);
                case tokenExpr.div:
                    if (retb.fval == 0)
                        throw new ParseException("Division par 0");
                    return new unionVal(reta.fval / retb.fval, "", typVal.num);
                case tokenExpr.boolAnd:
                    return new unionVal((float)((int)reta.fval & (int)retb.fval), "", typVal.num);
                case tokenExpr.boolOr:
                    return new unionVal((float)((int)reta.fval | (int)retb.fval), "", typVal.num);
                case tokenExpr.pow:
                    {
                        if (retb.fval == 0)
                        {
                            return new unionVal(1, "", typVal.num);
                        }
                        else if (reta.fval == 0)
                        {
                            return new unionVal(0, "", typVal.num);
                        }
                        else if (retb.fval != Math.Ceiling(retb.fval) && reta.fval <= 0)
                        {
                            if ((1 / retb.fval) == Math.Ceiling(1 / retb.fval) && Math.Abs(1 / retb.fval) % 2 == 1)
                            {
                                return new unionVal((float)(-Math.Pow(-reta.fval, retb.fval)), "", typVal.num);
                            }
                            else
                            {
                                throw new ParseException("On ne peut pas prendre un exposant non entier sur un nombre negatif");
                            }
                        }
                        else
                        {
                            return new unionVal((float)Math.Pow(reta.fval, Math.Ceiling(retb.fval)), "", typVal.num);
                        }
                    }
                default:
                    throw new ParseException("operateur " + this.operateur + "non definit");
            }
        }
        ArrayList retreiveArgs(SetOfVars GVAR, SetOfVars LVAR, executeParsedFunction BC)
        {
            ArrayList ArRet = new ArrayList();
            for (int i = 0; i < val.ArgsVals.Count; i++)
            {
                unionVal arg = (val.ArgsVals[i] as Parseur).getval(GVAR, LVAR, BC);
                if( arg.typVal == typVal.num )
                    ArRet.Add( arg.fval.ToString());
//                    ArRet.Add( arg.fval);
                else
                    ArRet.Add(unquote( arg.sval ));
            }
            return ArRet;
        }
        void replaceVarByValue(unionVal val, SetOfVars GVAR, SetOfVars LVAR, executeParsedFunction BC)
        {
            string idVar = val.nameVar;

			for (int i = 0; i < val.ArgsVals.Count; i++)
            {
                unionVal index = (val.ArgsVals[i] as Parseur).getval(GVAR, LVAR,BC );
                if (index.typVal == typVal.num)
                    idVar = idVar + "," + index.fval.ToString();
                else
                    idVar = idVar + "," + index.sval;
            }
            unionVal myVar;
			if (GVAR.globalExist(idVar))
				myVar = (unionVal)GVAR.Get(idVar);
			else
			{
				myVar = (unionVal)LVAR.Get(idVar); // Get
			}
            if (myVar == null)
            {
                val.typVal = typVal.str;
                val.sval = "\"\"";
                val.fval = 0;
            }
            else
            {
                val.typVal = myVar.typVal;
                val.sval = myVar.sval;
                val.fval = myVar.fval;
            }
        }
        void assignValueToVar(unionVal val, unionVal retValue, SetOfVars GVAR, SetOfVars LVAR, executeParsedFunction BC)
        {
            string idVar = val.nameVar;

// Construct the id Var
            for (int i = 0; i < val.ArgsVals.Count; i++)
            {
                unionVal index = (val.ArgsVals[i] as Parseur).getval(GVAR, LVAR, BC);
                if (index.typVal == typVal.str)
                    idVar = idVar + "," + index.sval.ToString();
                else
                    idVar = idVar + "," + index.fval.ToString();
            }
// If a copy Var To Var
            if (retValue.nameVar != null && retValue.nameVar != "")
            {
                string idOrig = retValue.nameVar;
                for (int i = 0; i < retValue.ArgsVals.Count; i++)
                {
					unionVal uval = (retValue.ArgsVals[i] as Parseur).getval(GVAR, LVAR, BC);
                    if (uval.typVal == typVal.num)
                        idOrig += "," + uval.fval.ToString();
                    else
                        idOrig += "," + uval.sval;

                } 
                SetOfVars.dumpElem[] dumpList;
                if (GVAR.globalExist(idOrig))
                    dumpList = GVAR.listDump(idOrig);
                else
                    dumpList = LVAR.listDump(idOrig);

				if (GVAR.globalExist(idVar))
				{
					GVAR.unSet(idVar);
					GVAR.duplicateVar(idVar, idOrig, dumpList);
				}
				else
				{
					LVAR.unSet(idVar);
					LVAR.duplicateVar(idVar, idOrig, dumpList);
				}
            }
// Return multiple value string
            else if ( retValue.typArray == true && retValue.ar_sval.Count > 0 )
            {
                for (int i = 0; i < retValue.ar_sval.Count; i++)
                {
                    string str = (string)retValue.ar_sval[i];
                    unionVal newVal = new unionVal(0, str, typVal.str);
                    string newIdVar = idVar + "," + i.ToString();
					if (GVAR.globalExist(newIdVar))
						GVAR.Set(newIdVar, newVal);
					else
					{
						LVAR.Set(newIdVar, newVal);
					}
                }
            }
// Return multiple value num
            else if (retValue.typArray == true && retValue.ar_fval.Count > 0)
            {
                for (int i = 0; i < retValue.ar_sval.Count; i++)
                {
                    float fval = (float)retValue.ar_fval[i];
                    unionVal newVal = new unionVal(fval, "", typVal.num);
                    string newIdVar = idVar + "," + i.ToString();
                    if (GVAR.globalExist(newIdVar))
                        GVAR.Set(newIdVar, newVal);
                    else
                        LVAR.Set(newIdVar, newVal);
                }
            }
// Assign a calculated value
            else
            {
				if (GVAR.globalExist(idVar))
					GVAR.Set(idVar, retValue);
				else
					LVAR.Set(idVar, retValue); // Set
            }
        }

        private static string unquote(string str)
        {
            int l = str.Length;
            try
            {
               return str.Substring(1, l - 2);
            }
            catch
            {
                return "";
            }
        }
    }


}
