Example #1
0
        private static SegmentData FindHighestPriorityOperator(IEnumerable <SegmentData> segments)
        {
            int         highestPrio         = -1;
            SegmentData highestPrioOperator = null;

            foreach (SegmentData sD in segments)
            {
                if (sD.Type != SegmentType.Operator)
                {
                    continue;
                }

                int prio = EquationOperators.GetOperatorPriority(sD.Data);
                if (highestPrioOperator == null || highestPrio < prio)
                {
                    highestPrioOperator = sD;
                    highestPrio         = prio;
                }
            }

            return(highestPrioOperator);
        }
Example #2
0
        internal static IEquation ParseEquation(string es, Action <string> errorCallback)
        {
            // remove outer ( )
            bool invalidParPlacement;

            es = RemoveOuterParentheses(es, out invalidParPlacement);
            if (invalidParPlacement)
            {
                errorCallback("Cannot parse equation, invalid parentheses placement.");
                return(null);
            }

            List <SegmentData>    segments = new List <SegmentData>();
            string                segment  = "";
            HashSet <SegmentType> potentialSegmentTypes = new HashSet <SegmentType>();

            potentialSegmentTypes.Add(SegmentType.Number);
            potentialSegmentTypes.Add(SegmentType.Variable);
            potentialSegmentTypes.Add(SegmentType.EquationVariable);
            potentialSegmentTypes.Add(SegmentType.Constant);
            potentialSegmentTypes.Add(SegmentType.Function);
            potentialSegmentTypes.Add(SegmentType.Operator);
            potentialSegmentTypes.Add(SegmentType.Equation);
            for (int j = 0; j <= es.Length; j++)
            {
                char c = j < es.Length ? es[j] : '\0';
                int  segmentStartIndex = j - segment.Length;

                SegmentData finishedSegment = null;
                if (finishedSegment == null && potentialSegmentTypes.Contains(SegmentType.Number) && IsNumberFinished(segment, c))
                {
                    finishedSegment = new SegmentData(segmentStartIndex, segment, SegmentType.Number);
                }
                else if (finishedSegment == null && potentialSegmentTypes.Contains(SegmentType.Variable) && IsVariableFinished(segment, c))
                {
                    finishedSegment = new SegmentData(segmentStartIndex, segment, SegmentType.Variable);
                }
                else if (finishedSegment == null && potentialSegmentTypes.Contains(SegmentType.EquationVariable) && IsEquationVariableFinished(segment, c))
                {
                    finishedSegment = new SegmentData(segmentStartIndex, segment, SegmentType.EquationVariable);
                }
                else if (finishedSegment == null && potentialSegmentTypes.Contains(SegmentType.Constant) && IsConstantFinished(segment, c))
                {
                    finishedSegment = new SegmentData(segmentStartIndex, segment, SegmentType.Constant);
                }
                else if (finishedSegment == null && potentialSegmentTypes.Contains(SegmentType.Function) && IsFunctionFinished(segment, c))
                {
                    finishedSegment = new SegmentData(segmentStartIndex, segment, SegmentType.Function);
                }
                else if (finishedSegment == null && potentialSegmentTypes.Contains(SegmentType.Operator) && IsOperatorFinished(segment, c))
                {
                    finishedSegment = new SegmentData(segmentStartIndex, segment, SegmentType.Operator);
                }
                else if (finishedSegment == null && potentialSegmentTypes.Contains(SegmentType.Equation) && IsEquationFinished(segment, c))
                {
                    finishedSegment = new SegmentData(segmentStartIndex, segment, SegmentType.Equation);
                }

                if (finishedSegment != null)
                {
                    segments.Add(finishedSegment);

                    potentialSegmentTypes.Clear();
                    potentialSegmentTypes.Add(SegmentType.Number);
                    potentialSegmentTypes.Add(SegmentType.Variable);
                    potentialSegmentTypes.Add(SegmentType.EquationVariable);
                    potentialSegmentTypes.Add(SegmentType.Constant);
                    potentialSegmentTypes.Add(SegmentType.Function);
                    potentialSegmentTypes.Add(SegmentType.Operator);
                    potentialSegmentTypes.Add(SegmentType.Equation);

                    segment         = "";
                    finishedSegment = null;
                }

                segment += c;

                // check possible segment types
                if (potentialSegmentTypes.Contains(SegmentType.Number) && !IsStartOfNumber(segment))
                {
                    potentialSegmentTypes.Remove(SegmentType.Number);
                }
                if (potentialSegmentTypes.Contains(SegmentType.Variable) && !IsStartOfVariable(segment))
                {
                    potentialSegmentTypes.Remove(SegmentType.Variable);
                }
                if (potentialSegmentTypes.Contains(SegmentType.EquationVariable) && !IsStartOfEquationVariable(segment))
                {
                    potentialSegmentTypes.Remove(SegmentType.EquationVariable);
                }
                if (potentialSegmentTypes.Contains(SegmentType.Constant) && !IsStartOfConstant(segment))
                {
                    potentialSegmentTypes.Remove(SegmentType.Constant);
                }
                if (potentialSegmentTypes.Contains(SegmentType.Function) && !IsStartOfFunction(segment))
                {
                    potentialSegmentTypes.Remove(SegmentType.Function);
                }
                if (potentialSegmentTypes.Contains(SegmentType.Operator) && !IsStartOfOperator(segment))
                {
                    potentialSegmentTypes.Remove(SegmentType.Operator);
                }
                if (potentialSegmentTypes.Contains(SegmentType.Equation) && !IsStartOfEquation(segment))
                {
                    potentialSegmentTypes.Remove(SegmentType.Equation);
                }

                if (c != '\0' && potentialSegmentTypes.Count == 0)
                {
                    errorCallback($"Invalid equation '{segment}' at {j}.");
                    return(null);
                }
            }

            // pre-process segments
            int k = 0;

            while (k < segments.Count)
            {
                int i = k;
                k++;

                SegmentData sD = segments[i];

                if (sD.Type != SegmentType.Function)
                {
                    continue;
                }

                if (i == segments.Count - 1)
                {
                    errorCallback($"Function '{sD.Data}' has no body.");
                    return(null);
                }

                SegmentData functionBodySegment = segments[i + 1];

                if (functionBodySegment.Type != SegmentType.Equation)
                {
                    errorCallback($"Invalid function body '{functionBodySegment.Data}' of function '{sD.Data}' at {functionBodySegment.Index}.");
                }

                segments.RemoveAt(i + 1);

                sD          = new SegmentData(sD.Index, sD.Data + functionBodySegment.Data, SegmentType.Function);
                segments[i] = sD;
            }

            k = 0;
            while (k < segments.Count)
            {
                int i = k;
                k++;

                SegmentData sD = segments[i];

                if (sD.Type != SegmentType.Operator)
                {
                    continue;
                }

                if (!EquationOperators.IsLeadingOperator(sD.Data))
                {
                    continue;
                }

                if (i > 0 && EquationOperators.IsContainedOperator(sD.Data) && IsValidOperatorParameterType(segments[i - 1].Type))
                {
                    continue;
                }

                if (i == segments.Count - 1)
                {
                    errorCallback($"Operator '{sD.Data}' has no body.");
                    return(null);
                }

                SegmentData operatorBodySegment = segments[i + 1];

                if (!IsValidOperatorParameterType(operatorBodySegment.Type))
                {
                    errorCallback($"Invalid operator '{sD.Data}' placement at {sD.Index}.");
                    return(null);
                }

                segments.RemoveAt(i + 1);

                sD = new SegmentData(sD.Index, $"op_{sD.Data}({operatorBodySegment.Data})", SegmentType.Function);
                //sD = new SegmentData(sD.Index, $"{EquationOperators.GetLeadingOperatorName(sD.Data)}({operatorBodySegment.Data})", SegmentType.Function);
                segments[i] = sD;
            }

            // process segments
            if (segments.Count == 1)
            {
                return(ParseSingleEquation(segments[0], errorCallback));
            }

            while (segments.Count > 1)
            {
                SegmentData highestOperator = FindHighestPriorityOperator(segments);
                int         segmentIndex    = segments.FindIndex(sD => sD.Index == highestOperator.Index);

                if (segmentIndex == 0 || segmentIndex == segments.Count - 1)
                {
                    errorCallback($"Invalid operator placement of '{highestOperator.Data}' at position {highestOperator.Index}. An operator cannot lead or trail the equation.");
                    return(null);
                }

                SegmentData precSegment = segments[segmentIndex - 1];
                SegmentData succSegment = segments[segmentIndex + 1];

                if (!IsValidOperatorParameterType(precSegment.Type))
                {
                    errorCallback($"Invalid first operator argument '{precSegment.Data}' at {precSegment.Index}.");
                    return(null);
                }

                if (!IsValidOperatorParameterType(succSegment.Type))
                {
                    errorCallback($"Invalid second operator argument '{succSegment.Data}' at {succSegment.Index}.");
                    return(null);
                }

                IEquation precEq = precSegment.Equation != null ? precSegment.Equation : ParseEquation(precSegment.Data, errorCallback);
                IEquation succEq = succSegment.Equation != null ? succSegment.Equation : ParseEquation(succSegment.Data, errorCallback);

                IEquation eq = CreateContainedOperatorEquation(highestOperator.Data, precEq, succEq);

                if (eq == null)
                {
                    errorCallback($"Invalid operator '{highestOperator.Data}' at {highestOperator.Index}.");
                    return(null);
                }

                SegmentData mergedSegment = new SegmentData(precSegment.Index, precSegment.Data + highestOperator.Data + succSegment.Data, SegmentType.Equation);
                mergedSegment.Equation = eq;

                segments[segmentIndex - 1] = mergedSegment;
                segments.RemoveAt(segmentIndex + 1);
                segments.RemoveAt(segmentIndex);
            }

            return(segments.Single().Equation);
        }
Example #3
0
        private static IEquation ParseSingleEquation(SegmentData sD, Action <string> errorCallback)
        {
            string s = sD.Data;

            switch (sD.Type)
            {
            case SegmentType.Number:
                return(new Constant(float.Parse(s)));

            case SegmentType.Variable:
                return(new Variable(int.Parse(s.Substring(1, s.Length - 2))));

            case SegmentType.EquationVariable:
                return(new EquationVariable(int.Parse(s.Substring(1, s.Length - 2))));

            case SegmentType.Constant:
                return(EquationFunctions.CreateFunction(s, new IEquation[0]));

            case SegmentType.Function: {
                int functionBodyStartIndex = s.IndexOf('(');
                int functionBodyEndIndex   = s.LastIndexOf(')');

                if (functionBodyStartIndex == -1)
                {
                    errorCallback($"Function call '{s}' at {sD.Index} has no body.");
                    return(null);
                }

                string functionName = s.Substring(0, functionBodyStartIndex);
                string functionBody = s.Substring(functionBodyStartIndex, s.Length - functionBodyStartIndex);
                bool   isOperator   = functionName.StartsWith("op_");
                if (isOperator)
                {
                    functionName = functionName.Substring(3, functionName.Length - 3);
                }

                if (functionBodyEndIndex == -1)
                {
                    errorCallback($"Function body '{functionBody}' of function '{functionName}' at {sD.Index} has no end to its body.");
                    return(null);
                }

                if (functionBodyEndIndex != s.Length - 1)
                {
                    errorCallback($"Function body '{functionBody}' of function '{functionName}' at {sD.Index} has an invalid body.");
                    return(null);
                }

                bool invalidParPlacement;
                functionBody = RemoveOuterParentheses(functionBody, out invalidParPlacement);

                if (invalidParPlacement)
                {
                    errorCallback($"Invalid parenthesis placement in function body '{functionBody}' of function '{functionName}' at {sD.Index}.");
                    return(null);
                }

                //int functionParameterCount;
                //if (isOperator)
                //    functionParameterCount = EquationOperators.GetOperatorParameterCount(functionName);
                //else
                //    functionParameterCount = EquationFunctions.GetFunctionParameterCount(functionName);

                string[] parametersS            = SplitParameters(functionBody);
                int      functionParameterCount = parametersS.Length;

                //if (functionParameterCount != parametersS.Length) {
                //    errorCallback($"Cannot parse function '{s}', invalid number of parameters ({parametersS.Length} - expected {functionParameterCount}.");
                //    return null;
                //}

                IEquation[] parameterEquations = new IEquation[functionParameterCount];
                for (int fpc = 0; fpc < functionParameterCount; fpc++)
                {
                    parameterEquations[fpc] = ParseEquation(parametersS[fpc], errorCallback);
                }

                IEquation functionEquation;
                if (isOperator)
                {
                    functionEquation = EquationOperators.CreateOperator(functionName, parameterEquations);
                }
                else
                {
                    functionEquation = EquationFunctions.CreateFunction(functionName, parameterEquations);
                }

                if (functionEquation == null)
                {
                    errorCallback($"No function of name '{functionName}' with {functionParameterCount} parameters exists. Error at {sD.Index}.");
                    return(null);
                }

                return(functionEquation);
            }
            }

            errorCallback($"Cannot parse equation '{s}' at {sD.Index}.");
            return(null);
        }