static void Main(string[] args) { var calc = new CalcString(new PolishNotationConvertor()); calc.Operators.Add(new Operator('^', (a) => Math.Pow(a[0], a[1]), 2, Priority.Highest)); //Пример добавления нового оператора calc.Operators.Add(new Operator('%', (a) => a[0] % a[1], 2, Priority.Highest)); calc.Operators.Add(new Operator('s', (a) => Math.Sqrt(a[0]), 1, Priority.Highest)); //Добавление унарного оператора Console.Write("Введите строку для расчета. Для выхода введите \"exit\".\n> "); string s = Console.ReadLine(); while (s.ToLower() != "exit") { try { Console.WriteLine("> " + calc.Calculate(s)); } catch (Exception ex) { Console.WriteLine("Ошибка: " + ex.Message); } Console.Write("> "); s = Console.ReadLine(); } }
// Concatenates two strings. public static CalcValue BinPlusStrings(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { CalcString strLeft = left as CalcString; CalcString strRight = right as CalcString; return(new CalcString(strLeft + strRight)); }
// Returns the string, reversed. public static CalcValue PreMinusString(CalcObject param, CLLocalStore vars, CLContextProvider context) { CalcString strParam = param as CalcString; char[] chars = strParam.Value.ToCharArray(); Array.Reverse(chars); return(new CalcString(new string(chars))); }
// Multiplies a string by a number. public static CalcValue BinTimesString(CalcObject left, CalcObject right, CLLocalStore vars, CLContextProvider context) { CalcString strLeft = left as CalcString; CalcNumber numRight = right as CalcNumber; int count = (int)numRight; if (count < 0) { throw new CLException("Strings cannot be repeated negative times."); } string strRet = ""; for (int i = 0; i < count; i++) { strRet += strLeft; } return(new CalcString(strRet)); }
// 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()); } }
private void calc(string input) { if (CurrentValue == "NaN") { CurrentValue = ""; } Regex isNumber = new Regex(@"^\d$"); if (isNumber.IsMatch(input)) { CurrentValue += input; CurrentValue = format(CurrentValue); } else if (input == "🗑") { Historique.Clear(); } else if (input == "C") { CalcString = ""; CurrentValue = ""; } else if (input == "CE") { CurrentValue = ""; } else if (input == "=") { if (CalcString.Length > 0) { if (CurrentValue.Length == 0 && CalcString.Substring(CalcString.Length - 1) != "!" && CalcString.Substring(CalcString.Length - 1) != ")") { CalcString = CalcString.Substring(0, CalcString.Length - 1); } CalcString += CurrentValue; if (CalcString.Count(x => x == '(') > CalcString.Count(x => x == ')')) { int numberOfOpen = CalcString.Count(x => x == '('); int numberOfClose = CalcString.Count(x => x == ')'); int rest = numberOfOpen - numberOfClose; for (int i = 0; i < rest; i++) { CalcString += ')'; } } CalcString = CalcString.Replace(",", "."); org.mariuszgromada.math.mxparser.Expression expression = new org.mariuszgromada.math.mxparser.Expression(new string(CalcString.ToCharArray().Where(c => !Char.IsWhiteSpace(c)).ToArray())); double result = expression.calculate(); CurrentValue = format(result.ToString()); Historique.Add(new Calcul(CalcString, format(result.ToString()))); CalcString = ""; } } else if (input == ",") { if (CurrentValue.IndexOf(',') == -1 && CurrentValue.Length != 0) { CurrentValue += input; } } else if (input == "(") { CalcString += input; } else if (input == ")") { CalcString += CurrentValue + ")"; CurrentValue = ""; } else { // Supprime la virgule en fin de lignesi un opérateur est choisie if (CurrentValue.Length > 0 && CurrentValue.Substring(CurrentValue.Length - 1) == ",") { CurrentValue = CurrentValue.Substring(0, CurrentValue.Length - 1); } // Ajoute un opérateur s'il y a déjà une valeur enregistré if (CurrentValue != "" || (CalcString.Length > 0 && CalcString.Substring(CalcString.Length - 1) == "!") || (CalcString.Length > 0 && CalcString.Substring(CalcString.Length - 1) == ")")) { CalcString += CurrentValue + input; CurrentValue = ""; } else if (CalcString.Length > 0) { CalcString = CalcString.Substring(0, CalcString.Length - 1) + input; } if (input == "-" && CalcString.Length == 0) { CalcString = "0-"; } } }
public void CreateCalcStringNullTest() { calc = new CalcString(null); }