2

i have done a RPN class to calculate strings which end-user input like "1.0+3/2-tan(45)/(1+1)+sin(30)*abs(-1)+Abs(-10)"

Then, I want to parsing conditional statements and multi-parameters function such as "if(1>2,3/3,2*1)","max(1,2,3,4)"

So, my questions how to use IF-ELSE in the RPN?

Here's my code: enter link description here

AeroYoung
  • 31
  • 5

2 Answers2

0

For if(1>2,3/3,2*1) you would first evaluate the three argument from right to left and push their resuls on the stack so that it looked like this:

top-of-stack->false
              1
              2

Then if would be implemented in the RPN engine something like (pseudo-code):

void DoIf()
{
  if (pop()) // pop result of "if" evaluation
  {
    var result = pop(); // pop "true" result from stack
    pop(); // discard "false" result
    push(result); // push back "true" result
  }
  else
  {
    pop(); // discard "true" result, leaving "false" result on stack   
  }
}

As for multi-parameter functions, there should be no special handling needed. Just evaluate and push all arguments (right to left, typically). The implementation of the function should pop off the required number of arguments and then push its result (if any).

0

i try to parse multi-parameters function such as if\Max before RPN.Parse()

public class MultiParameterFunctionParser
    {
        public readonly List<string> Funcs = new List<string> {"IF", "MAX"};

        public string Parse(string exp)
        {
            while (IsFunction(exp,out var index,out var funcName))//
            {
                var parameters = GetParameters(exp, index, funcName, out var before, out var after);
                var list = GetParameterList(parameters);

                var value = Evaluate(list, funcName);
                exp= $"{before}({value}){after}";
            }

            return exp;
        }

        /// <summary>
        ///  Is Exp Contains a function?
        /// </summary>
        /// <param name="exp"></param>
        /// <param name="index"></param>
        /// <param name="funcName"></param>
        /// <returns></returns>
        private bool IsFunction(string exp, out int index, out string funcName)
        {
            index = -1;
            funcName = "";
            foreach (var func in Funcs)
            {
                var idx = exp.IndexOf($"{func}(", StringComparison.CurrentCultureIgnoreCase);
                if (idx == -1 || idx + 3 >= exp.Length - 1)
                    continue;
                index = idx;
                funcName = func;
                break;
            }

            return index != -1 && index + 3 < exp.Length - 1;
        }

        /// <summary>
        /// Get Parameters' string
        /// </summary>
        /// <param name="exp">8+if(12,sin(90),0)+1.2</param>
        /// <param name="index">2 if's start index</param>
        /// <param name="before">8+</param>
        /// <param name="after">+1.2</param>
        /// <returns>12,sin(90),0</returns>
        private static string GetParameters(string exp,int index, string funcName, out string before, out string after)
        {
            before = exp.Substring(0, index);

            index += funcName.Length + 1;

            var leftCount = 1; // '(' count
            var rightCount = 0;// ')' count
            var results = "";

            while (index < exp.Length && leftCount != rightCount)
            {
                var c = exp[index];
                if (c.Equals('('))
                    leftCount++;
                else if (c.Equals(')'))
                    rightCount++;

                if (leftCount > rightCount)
                    results += c;
                else
                    break;

                index++;
            }

            after = exp.Substring(index + 1, exp.Length - index - 1);

            return results;
        }

        /// <summary>
        /// Parse Parameter string to list. 
        /// </summary>
        /// <param name="exp">MAX(1,-1),1,0</param>
        /// <returns>{"MAX(1,-1)","1","0"}</returns>
        private static List<string> GetParameterList(string exp)
        {
            var count = exp.Length;

            for (var i = count - 1; i > -1 && exp.Length > 0; i--)
            {
                var c = exp[i];
                if (c != ',')
                    continue;

                var after = exp.Substring(i + 1);
                var before = exp.Substring(0,i);

                if (after.Count(a => a == '(').Equals(after.Count(a => a == ')')))
                {
                    exp = before + '#' + after;
                }
            }

            var results = exp.Split('#').ToList();

            return results;
        }

        private static double Evaluate(List<string> parameters, string funcName)
        {
            if (funcName.Equals("MAX", StringComparison.CurrentCultureIgnoreCase))
                return EvaluateMax(parameters);
            if (funcName.Equals("IF", StringComparison.CurrentCultureIgnoreCase))
                return EvaluateIF(parameters);

            return 0;
        }

        private static double EvaluateIF(List<string> parameters)
        {
            if (parameters == null || parameters.Count != 3)
                throw new Exception("EvaluateIF parameters.Count()!=3");

            var results = new List<double>();
            foreach (var parameter in parameters)
            {
                var rpn = new RPN();
                rpn.Parse(parameter);
                var obj = rpn.Evaluate();

                if (obj == null)
                {
                    throw new Exception("EvaluateIF Not Number!");
                }
                if (obj.ToString().Equals("true", StringComparison.CurrentCultureIgnoreCase))
                {
                    results.Add(1);
                }
                else if (obj.ToString().Equals("false", StringComparison.CurrentCultureIgnoreCase))
                {
                    results.Add(-1);
                }
                else
                {
                    if (double.TryParse(obj.ToString(), out var d))
                        results.Add(d);
                    else
                        throw new Exception("EvaluateIF Not Number!");
                }
            }

            return results[0] >= 0 ? results[1] : results[2];
        }

        private static double EvaluateMax(IEnumerable<string> parameters)
        {
            var results = new List<double>();
            foreach (var parameter in parameters)
            {
                var rpn = new RPN();
                rpn.Parse(parameter);
                var obj = rpn.Evaluate();
                if (double.TryParse(obj.ToString(), out var d))
                    results.Add(d);
            }

            return results.Count > 0 ? results.Max() : 0;
        }
    }
AeroYoung
  • 31
  • 5