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); }