예제 #1
0
파일: MainForm.cs 프로젝트: i-e-b/DBSS
        /// <summary>
        /// Recalculate a cell's value from it's formula
        /// </summary>
        private ResultSet RefreshCell(int x, int y, bool formulaChanged)
        {
            var gc = bigGrid1.Items[x, y] as GridCell ?? new GridCell();
            var rs = new ResultSet {Result = gc.Value};

            if (formulaChanged) {// Clear out old refs and add new ones:
                rs = RecalculateFromCell(x, y);

                var data = new SheetDataTableAdapters.DependsAdapter();
                ulong key = bigGrid1.Items.GetUniqueKey(x, y);
                data.ClearDependenciesForHash((long)key);
                foreach (var refr in rs.References) {
                    data.AddDependency((long)key, (long)bigGrid1.Items.GetUniqueKey(refr.X, refr.Y));
                }

                UpdateCell(gc, x, y);
                return rs;
            }

            Stack<string> rpn = null;
            try {
                rpn = calculator.InfixToPostfix(gc.Formula ?? "");
            } catch (Exception ex) {
                gc.Value = "Formula Error: " + ex.Message;
            }
            if (rpn != null && rpn.Count > 0) { // formula is non-empty
                try {
                    rs = calculator.EvaluatePostfix(rpn, y, x);
                    gc.Value = rs.Result;
                } catch (Exception ex) {
                    gc.Value = "Calculation Error: " + ex.Message;
                }
            }
            UpdateCell(gc,x,y);
            return rs;
        }
예제 #2
0
파일: Calculator.cs 프로젝트: i-e-b/DBSS
        /// <summary>
        /// Evaluate the result of a postfix expression string.
        /// Expected to be space-delimited
        /// </summary>
        public ResultSet EvaluatePostfix(Stack<string> postfix, int row, int column)
        {
            // very simple for the moment, doesn't handle variables or functions

            var @out = new ResultSet();

            var values = new Stack<CValue>();
            values.Push(new CValue((decimal)0.0)); // quick hack to deal with leading uniary operators

            foreach (string token in postfix/*.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)*/) {
                if (String.IsNullOrEmpty(token)) continue;
                decimal value;
                if (decimal.TryParse(token, out value)) {
                    values.Push(new CValue(value));
                    continue;
                }
                CValue l, r;

                switch (token.ToLowerInvariant()) {
                    case "+":
                        r = values.Pop(); l = values.Pop();
                        values.Push(l + r);
                        break;
                    case "-":
                        r = values.Pop(); l = values.Pop();
                        values.Push(l - r);
                        break;
                    case "*":
                        r = values.Pop(); l = values.Pop();
                        values.Push(l * r);
                        break;
                    case "/":
                        r = values.Pop(); l = values.Pop();
                        values.Push(l / r);
                        break;
                    case "^":
                        r = values.Pop(); l = values.Pop();
                        values.Push(CValue.Pow(l, r));
                        break;
                    case "%":
                        r = values.Pop(); l = values.Pop();
                        values.Push(l % r);
                        break;
                    case "!":
                        l = CValue.Floor(values.Pop());
                        decimal f = 1;
                        for (var c = (int)l.NumericValue; c > 0; c--) { f *= c; }
                        values.Push(new CValue(f));
                        break;

                    // not used in postfix notation:
                    case ",":
                    case "(":
                    case ")":
                        throw new Exception("Unexpected token in Postfix");

                    default:
                        if (token.StartsWith("['") && token.EndsWith("']")) {
                            // it's a string literal. Like this: ['String literal']
                            values.Push(new CValue(token.Substring(2, token.Length - 4)));
                        } else {
                            @out.References.AddRange(
                                funcs.HandleFunction(token, values, column, row)
                                );
                        }
                        break;
                }

            } // end foreach

            @out.Result = values.Pop().ToString();

            return @out;
        }