示例#1
0
        public static CLBinaryOperator LoadBinaryPower(int priority = PowerPriority, bool valOnLeft = true, bool valOnRight = true)
        {
            BinaryPower = CLOperators.BinaryOperators.GetOrNull("^");
            if (BinaryPower == null)
            {
                BinaryPower = new CLBinaryOperator("^", priority, valOnLeft, valOnRight);
                CLOperators.SetFromRight(PowerPriority);
            }
            BinaryPower.AddFunction(tNum, tNum, BinPowerNumbers);
            BinaryPower.AddFunction(tLst, tNum, (left, right, vars, context) => BinPowerNumbers(ListToNum(left), right, vars, context));
            BinaryPower.AddFunction(tNum, tLst, (left, right, vars, context) => BinPowerNumbers(left, ListToNum(right), vars, context));
            BinaryPower.AddFunction(tLst, tLst, (left, right, vars, context) => BinPowerNumbers(ListToNum(left), ListToNum(right), vars, context));

            return(BinaryPower);
        }
        // Parses a single "operation chain"
        private static CalcObject ParseChain(List <CLObjectPiece> pieces)
        {
            // First, we can't parse an empty list.
            if (pieces.Count == 0)
            {
                throw new CLSyntaxException("Empty list received.", 0);
            }

            LinkedList <CLExpressionBuilder> exps = new LinkedList <CLExpressionBuilder>();
            CalcObject hold      = null;
            bool       valueLast = false;

            // Loop through all the pieces now.
            while (pieces.Count != 0)
            {
                CLObjectPiece piece = pieces[0];

                // Get the next value, if there is one.
                CalcObject obj = null;
                bool       err = false;

                // If it's a ()[]},
                if (piece.Type == CLObjectPieceType.Spacer)
                {
                    if (piece.Contents == "(")
                    {
                        if (!valueLast)
                        {
                            obj = ParseParentheses(pieces);
                        }
                        else
                        {
                            err = true;
                        }
                    }
                    else if (piece.Contents == "[")
                    {
                        if (!valueLast)
                        {
                            obj = ParseList(pieces);
                        }
                        else
                        {
                            err = true;
                        }
                    }
                    else /* ], ), }, , */
                    {
                        // Send control back up a parser level
                        break;
                    }
                }
                else if (piece.Type == CLObjectPieceType.FunctionName)
                {
                    if (!valueLast)
                    {
                        obj = ParseFunction(pieces);
                    }
                    else
                    {
                        err = true;
                    }
                }
                else if (piece.Type == CLObjectPieceType.Number)
                {
                    if (!valueLast)
                    {
                        obj = new CalcNumber(Decimal.Parse(piece.Contents));
                        pieces.RemoveAt(0);
                    }
                    else
                    {
                        err = true;
                    }
                }
                else if (piece.Type == CLObjectPieceType.String)
                {
                    if (!valueLast)
                    {
                        // Strip the quotes
                        string check = piece.Contents.Substring(1, piece.Contents.Length - 2);
                        // Parse special characters
                        check = check.Replace(@"\\", "\uF000")
                                .Replace(@"\n", "\n")
                                .Replace(@"\t", "\t")
                                .Replace(@"\", "")
                                .Replace("\uF000", @"\");
                        obj = new CalcString(check);
                        pieces.RemoveAt(0);
                    }
                    else
                    {
                        err = true;
                    }
                }

                if (err)
                {
                    throw new CLSyntaxException("Two consecutive values", piece.Position);
                }

                // If there's a value, put it in the most recent expression
                if (obj != null)
                {
                    valueLast = true;

                    // If there's no expression, just hold the value.
                    if (exps.Count == 0)
                    {
                        hold = obj;
                    }
                    else
                    {
                        // Put it on the most recent expression
                        CLExpressionBuilder exp = exps.Last.Value;
                        exp.Right = obj;
                    }

                    continue;
                }

                // Otherwise, this piece must be an operator.
                CLExpressionBuilder expNew = new CLExpressionBuilder();
                CLOperator          op     = null;
                valueLast = false;

                if (piece.Type == CLObjectPieceType.BinaryOperator)
                {
                    op = CLOperators.BinaryOperators[piece.Contents];
                }
                else if (piece.Type == CLObjectPieceType.PrefixOperator)
                {
                    op = CLOperators.PrefixOperators[piece.Contents];
                }
                else if (piece.Type == CLObjectPieceType.PostfixOperator)
                {
                    op = CLOperators.PostfixOperators[piece.Contents];
                }

                expNew.Operator = op;

                // If it's the first operator...
                if (exps.Count == 0)
                {
                    // ... use the held value if one exists
                    if (hold != null)
                    {
                        expNew.Left = hold;
                    }
                    exps.AddLast(expNew);
                }
                // Otherwise...
                else
                {
                    // For prefix operators we don't need to check priorities to the
                    // left. They can just stack on in.
                    if (op is CLPrefixOperator)
                    {
                        exps.Last.Value.Right = expNew;
                        exps.AddLast(expNew);
                    }
                    else
                    {
                        CLExpressionBuilder expOld  = null;
                        CLExpressionBuilder expNext = null;
                        // This code removes expressions from the stack that are a
                        // higher priority than the one being removed, or that are
                        // postfix.
                        while (exps.Count != 0)
                        {
                            expNext = exps.Last.Value;
                            if (
                                // The next expression is a postfix expression.
                                expNext.Operator is CLPostfixOperator ||
                                // The next expression on the stack is still higher
                                // priority
                                expNext.Operator.Priority > op.Priority ||
                                // The next expression on the stack is equal priority,
                                // but evaluated left-to-right
                                (expNext.Operator.Priority == op.Priority &&
                                 !CLOperators.IsFromRight(op.Priority))
                                )
                            {
                                expOld = exps.Last.Value;
                                exps.RemoveLast();
                                expNext = null;
                            }
                            else
                            {
                                break;
                            }
                        }

                        // The last removed expression becomes the left of this one.
                        // (If there's no such expression, then the right of the next
                        // expression on the stack becomes our left.)
                        if (expOld != null)
                        {
                            expNew.Left = expOld;
                        }
                        else
                        {
                            expNew.Left = expNext.Right;
                        }

                        // Then, this expression becomes the right of the next one.
                        if (expNext != null)
                        {
                            expNext.Right = expNew;
                        }

                        exps.AddLast(expNew);
                    }
                }

                pieces.RemoveAt(0);
            }

            if (exps.Count == 0)
            {
                return(hold);
            }
            else
            {
                return(exps.First.Value.Build());
            }
        }
        public static List <CLObjectPiece> Lex(string input)
        {
            List <CLObjectPiece> ret = new List <CLObjectPiece>();
            string last = "";
            int    pos  = 0;

            while (input.Length > 0)
            {
                int   move  = 0;
                Match match = null;

                // See if it's whitespace before any tokens.
                if (CLUtils.RegexMatches(rgxWhitespace, input, out match))
                {
                    move = match.Length;
                }

                // Is it a number?
                else if (CLUtils.RegexMatches(rgxNumber, input, out match))
                {
                    last = match.Value;
                    ret.Add(new CLObjectPiece(last, CLObjectPieceType.Number, pos));
                    move = match.Length;
                }

                // Is it a separator?
                else if (CLUtils.RegexMatches(rgxSeparator, input, out match))
                {
                    last = match.Value;
                    ret.Add(new CLObjectPiece(last, CLObjectPieceType.Spacer, pos));
                    move = match.Length;
                }

                // Is it a comment?
                else if (CLUtils.RegexMatches(rgxComment, input, out match))
                {
                    move = match.Length;
                    // comments aren't included in the syntax tree
                }

                // Is it a name?
                else if (CLUtils.RegexMatches(rgxName, input, out match))
                {
                    last = match.Value;
                    ret.Add(new CLObjectPiece(last, CLObjectPieceType.FunctionName, pos));
                    move = match.Length;
                }

                // ... Is it an operator, or group thereof?
                else if (CLUtils.RegexMatches(rgxOperator, input, out match))
                {
                    string opers = rgxWhitespaceReplace.Replace(match.Value, "");
                    move = match.Length;

                    string next = "";
                    if (input.Length > move)
                    {
                        next = input.Substring(move, 1);
                    }

                    // If the operator immediately follows a separator,
                    //   it must be a prefix operator.
                    bool prefix = (last == "" || last == "[" || last == "," || last == "(");

                    // If the operator immediately precedes a separator,
                    //   it must be a postfix operator.
                    bool postfix = (next == "" || next == "]" || next == "," || next == ")" || next == "}");

                    // It can't be both (as in the only thing between two separators).
                    if (prefix && postfix)
                    {
                        throw new CLSyntaxException("A value was expected between brackets.", pos);
                    }

                    // There might be multiple operators in a row, so let's be sure to get them all.
                    List <CLObjectPiece> pcs = CLOperators.GetOpers(opers, prefix, postfix, pos);
                    ret.AddRange(pcs);

                    last = match.Value;
                }

                // No match? That's a paddlin.
                else
                {
                    throw new CLSyntaxException("I don't know what this means.", pos);
                }

                // Discard what we've found.
                input = input.Substring(move);
                pos  += move;
            }

            return(ret);
        }