public void InitDefaults() { this.Add("about", new StaticFunction("About", delegate(object[] ps) { return("@Calculator - a Tiny Expression Evaluator v1.0\r\nby Herre Kuijpers - Copyright © 2011 under the CPOL license"); }, 0, 0)); this.Add("help", new StaticFunction("Help", Help, 0, 0)); // high precision functions this.Add("abs", new StaticFunction("Abs", delegate(object[] ps) { return(Math.Abs(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("acos", new StaticFunction("Acos", delegate(object[] ps) { return(Math.Acos(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("asin", new StaticFunction("Asin", delegate(object[] ps) { return(Math.Asin(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("atan", new StaticFunction("Atan", delegate(object[] ps) { return(Math.Atan(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("atan2", new StaticFunction("Atan2", delegate(object[] ps) { return(Math.Atan2(Convert.ToDouble(ps[0]), Convert.ToDouble(ps[1]))); }, 2, 2)); this.Add("ceiling", new StaticFunction("Ceiling", delegate(object[] ps) { return(Math.Ceiling(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("cos", new StaticFunction("Cos", delegate(object[] ps) { return(Math.Cos(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("cosh", new StaticFunction("Cosh", delegate(object[] ps) { return(Math.Cosh(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("exp", new StaticFunction("Exp", delegate(object[] ps) { return(Math.Exp(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("int", new StaticFunction("int", delegate(object[] ps) { return((int)Math.Floor(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("fact", new StaticFunction("Fact", Fact, 1, 1)); // factorials 1*2*3*4... this.Add("floor", new StaticFunction("Floor", delegate(object[] ps) { return(Math.Floor(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("log", new StaticFunction("Log", Log, 1, 2)); // log allows 1 or 2 parameters this.Add("ln", new StaticFunction("Ln", delegate(object[] ps) { return(Math.Log(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("pow", new StaticFunction("Pow", delegate(object[] ps) { if ( (Convert.ToInt64(ps[0]) != Convert.ToDouble(ps[0])) || (Convert.ToInt64(ps[1]) != Convert.ToDouble(ps[1])) ) { return(Math.Pow(Convert.ToDouble(ps[0]), Convert.ToDouble(ps[1]))); } else // use integral maths instead to avoid silent overflow { long number = Convert.ToInt64(ps[0]); long power = Convert.ToInt64(ps[1]); long result = 1L; for (long i = 0; i < power; i++) { result *= number; } return(result); } }, 2, 2)); this.Add("round", new StaticFunction("Round", delegate(object[] ps) { return(Math.Round(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("sign", new StaticFunction("Sign", delegate(object[] ps) { return(Math.Sign(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("sin", new StaticFunction("Sin", delegate(object[] ps) { return(Math.Sin(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("sinh", new StaticFunction("Sinh", delegate(object[] ps) { return(Math.Sinh(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("sqr", new StaticFunction("Sqr", delegate(object[] ps) { return(Convert.ToDouble(ps[0]) * Convert.ToDouble(ps[0])); }, 1, 1)); this.Add("sqrt", new StaticFunction("Sqrt", delegate(object[] ps) { return(Math.Sqrt(Convert.ToDouble(ps[0]))); }, 1, 1)); this.Add("trunc", new StaticFunction("Trunc", delegate(object[] ps) { return(Math.Truncate(Convert.ToDouble(ps[0]))); }, 1, 1)); // array functions this.Add("avg", new StaticFunction("Avg", Avg, 1, int.MaxValue)); this.Add("stdev", new StaticFunction("StDev", StDev, 1, int.MaxValue)); this.Add("var", new StaticFunction("Var", Var, 1, int.MaxValue)); this.Add("max", new StaticFunction("Max", Max, 1, int.MaxValue)); this.Add("median", new StaticFunction("Min", Median, 1, int.MaxValue)); this.Add("min", new StaticFunction("Min", Min, 1, int.MaxValue)); //boolean functions this.Add("not", new StaticFunction("Not", delegate(object[] ps) { return(!Convert.ToBoolean(ps[0])); }, 1, 1)); this.Add("if", new StaticFunction("If", delegate(object[] ps) { return(Convert.ToBoolean(ps[0]) ? ps[1] : ps[2]); }, 3, 3)); this.Add("and", new StaticFunction("And", delegate(object[] ps) { return(Convert.ToBoolean(ps[0]) && Convert.ToBoolean(ps[1])); }, 2, 2)); this.Add("or", new StaticFunction("Or", delegate(object[] ps) { return(Convert.ToBoolean(ps[0]) || Convert.ToBoolean(ps[1])); }, 2, 2)); // string functions this.Add("left", new StaticFunction("Left", delegate(object[] ps) { int len = Convert.ToInt32(ps[1]) < ps[0].ToString().Length ? Convert.ToInt32(ps[1]) : ps[0].ToString().Length; return(ps[0].ToString().Substring(0, len)); }, 2, 2)); this.Add("right", new StaticFunction("Right", delegate(object[] ps) { int len = Convert.ToInt32(ps[1]) < ps[0].ToString().Length ? Convert.ToInt32(ps[1]) : ps[0].ToString().Length; return(ps[0].ToString().Substring(ps[0].ToString().Length - len, len)); }, 2, 2)); this.Add("mid", new StaticFunction("Mid", delegate(object[] ps) { int idx = Convert.ToInt32(ps[1]) < ps[0].ToString().Length ? Convert.ToInt32(ps[1]) : ps[0].ToString().Length; int len = Convert.ToInt32(ps[2]) < ps[0].ToString().Length - idx ? Convert.ToInt32(ps[2]) : ps[0].ToString().Length - idx; return(ps[0].ToString().Substring(idx, len)); }, 3, 3)); this.Add("hex", new StaticFunction("Hex", delegate(object[] ps) { return(String.Format("0x{0:X}", Convert.ToInt32(ps[0].ToString()))); }, 1, 1)); this.Add("format", new StaticFunction("Format", delegate(object[] ps) { return(string.Format(ps[0].ToString(), ps[1])); }, 2, 2)); this.Add("len", new StaticFunction("Len", delegate(object[] ps) { return(Convert.ToDouble(ps[0].ToString().Length)); }, 1, 1)); this.Add("lower", new StaticFunction("Lower", delegate(object[] ps) { return(ps[0].ToString().ToLowerInvariant()); }, 1, 1)); this.Add("upper", new StaticFunction("Upper", delegate(object[] ps) { return(ps[0].ToString().ToUpperInvariant()); }, 1, 1)); this.Add("val", new StaticFunction("Val", delegate(object[] ps) { return(Convert.ToDouble(ps[0])); }, 1, 1)); }
protected override void DoAction(int action) { #pragma warning disable 162, 1522 switch (action) { case 4: // statement -> ASSIGN, NAME, EQUAL, expression, SEMICOLON #line 33 "Parser.gppg" { MainX.VariableMap[ValueStack[ValueStack.Depth - 4].name] = ValueStack[ValueStack.Depth - 2].value; } #line default break; case 5: // statement -> READ, optional_output, name_list, SEMICOLON #line 37 "Parser.gppg" { try { string buffer = Console.In.ReadLine(); string[] textArray = buffer.Split(','); if (ValueStack[ValueStack.Depth - 2].nameList.Count != textArray.Length) { Console.Error.WriteLine("Invalid number of values."); Environment.Exit(-1); } for (int index = 0; index < ValueStack[ValueStack.Depth - 2].nameList.Count; ++index) { string name = ValueStack[ValueStack.Depth - 2].nameList[index], text = textArray[index]; double value = double.Parse(text); // double value = double.Parse(text, NumberStyles.Any, CultureInfo.InvariantCulture); MainX.VariableMap[name] = value; } } catch (Exception exception) { Console.Error.WriteLine("Invalid input: " + exception.ToString()); Environment.Exit(-1); } } #line default break; case 6: // statement -> WRITE, optional_output, expression_list, SEMICOLON #line 60 "Parser.gppg" { bool first = true; foreach (double value in ValueStack[ValueStack.Depth - 2].valueList) { Console.Out.Write((first ? "" : ", ") + value); first = false; } Console.Out.WriteLine(); } #line default break; case 7: // statement -> NEWLINE, SEMICOLON #line 70 "Parser.gppg" { Console.Out.WriteLine(); } #line default break; case 9: // optional_output -> TEXT, COMMA #line 76 "Parser.gppg" { Console.Out.Write(ValueStack[ValueStack.Depth - 2].text); } #line default break; case 10: // name_list -> NAME #line 81 "Parser.gppg" { CurrentSemanticValue.nameList = new List <string>(); CurrentSemanticValue.nameList.Add(ValueStack[ValueStack.Depth - 1].name); } #line default break; case 11: // name_list -> name_list, COMMA, NAME #line 85 "Parser.gppg" { CurrentSemanticValue.nameList = ValueStack[ValueStack.Depth - 3].nameList; CurrentSemanticValue.nameList.Add(ValueStack[ValueStack.Depth - 1].name); } #line default break; case 12: // expression_list -> expression #line 91 "Parser.gppg" { CurrentSemanticValue.valueList = new List <double>(); CurrentSemanticValue.valueList.Add(ValueStack[ValueStack.Depth - 1].value); } #line default break; case 13: // expression_list -> expression_list, COMMA, expression #line 95 "Parser.gppg" { CurrentSemanticValue.valueList = ValueStack[ValueStack.Depth - 3].valueList; CurrentSemanticValue.valueList.Add(ValueStack[ValueStack.Depth - 1].value); } #line default break; case 14: // expression -> binary_expression #line 101 "Parser.gppg" { CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 1].value; } #line default break; case 15: // expression -> expression, PLUS, binary_expression #line 104 "Parser.gppg" { CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 3].value + ValueStack[ValueStack.Depth - 1].value; } #line default break; case 16: // expression -> expression, MINUS, binary_expression #line 107 "Parser.gppg" { CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 3].value - ValueStack[ValueStack.Depth - 1].value; } #line default break; case 17: // binary_expression -> unary_expression #line 112 "Parser.gppg" { CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 1].value; } #line default break; case 18: // binary_expression -> binary_expression, TIMES, unary_expression #line 115 "Parser.gppg" { CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 3].value * ValueStack[ValueStack.Depth - 1].value; } #line default break; case 19: // binary_expression -> binary_expression, DIVIDE, unary_expression #line 118 "Parser.gppg" { if (ValueStack[ValueStack.Depth - 1].value == 0) { Console.Error.WriteLine("Division by Zero."); Environment.Exit(-1); } CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 3].value / ValueStack[ValueStack.Depth - 1].value; } #line default break; case 20: // unary_expression -> primary_expression #line 128 "Parser.gppg" { CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 1].value; } #line default break; case 21: // unary_expression -> PLUS, unary_expression #line 131 "Parser.gppg" { CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 1].value; } #line default break; case 22: // unary_expression -> MINUS, unary_expression #line 134 "Parser.gppg" { CurrentSemanticValue.value = -ValueStack[ValueStack.Depth - 1].value; } #line default break; case 23: // unary_expression -> SIN, unary_expression #line 137 "Parser.gppg" { CurrentSemanticValue.value = Math.Sin(ValueStack[ValueStack.Depth - 1].value); } #line default break; case 24: // unary_expression -> COS, unary_expression #line 140 "Parser.gppg" { CurrentSemanticValue.value = Math.Cos(ValueStack[ValueStack.Depth - 1].value); } #line default break; case 25: // unary_expression -> TAN, unary_expression #line 143 "Parser.gppg" { CurrentSemanticValue.value = Math.Tan(ValueStack[ValueStack.Depth - 1].value); } #line default break; case 26: // unary_expression -> LOG, unary_expression #line 146 "Parser.gppg" { if (ValueStack[ValueStack.Depth - 1].value <= 0) { Console.Error.WriteLine("Logarithm of Non-Positive Value."); Environment.Exit(-1); } CurrentSemanticValue.value = Math.Log(ValueStack[ValueStack.Depth - 1].value); } #line default break; case 27: // unary_expression -> EXP, unary_expression #line 154 "Parser.gppg" { CurrentSemanticValue.value = Math.Exp(ValueStack[ValueStack.Depth - 1].value); } #line default break; case 28: // unary_expression -> LOG10, unary_expression #line 157 "Parser.gppg" { if (ValueStack[ValueStack.Depth - 1].value <= 0) { Console.Error.WriteLine("Logarithm of Non-Positive Value."); Environment.Exit(-1); } CurrentSemanticValue.value = Math.Log10(ValueStack[ValueStack.Depth - 1].value); } #line default break; case 29: // unary_expression -> EXP10, unary_expression #line 165 "Parser.gppg" { CurrentSemanticValue.value = Math.Pow(10, ValueStack[ValueStack.Depth - 1].value); } #line default break; case 30: // unary_expression -> SQRT, unary_expression #line 168 "Parser.gppg" { if (ValueStack[ValueStack.Depth - 1].value < 0) { Console.Error.WriteLine("Square Root of Negativ Value."); Environment.Exit(-1); } CurrentSemanticValue.value = Math.Sqrt(ValueStack[ValueStack.Depth - 1].value); } #line default break; case 31: // primary_expression -> LEFT_PAREN, expression, RIGHT_PAREN #line 178 "Parser.gppg" { CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 2].value; } #line default break; case 32: // primary_expression -> NAME #line 181 "Parser.gppg" { if (MainX.VariableMap.ContainsKey(ValueStack[ValueStack.Depth - 1].name)) { CurrentSemanticValue.value = MainX.VariableMap[ValueStack[ValueStack.Depth - 1].name]; } else { Console.Error.WriteLine("Unknown Name: \"" + ValueStack[ValueStack.Depth - 1].name + "\"."); Environment.Exit(-1); } } #line default break; case 33: // primary_expression -> VALUE #line 190 "Parser.gppg" { CurrentSemanticValue.value = ValueStack[ValueStack.Depth - 1].value; } #line default break; } #pragma warning restore 162, 1522 }
private void convert_click(object sender, EventArgs e) { if (txt_display.Text != "NaN" && txt_display.Text != "" && txt_display.Text != "∞" && txt_display.Text != "-∞") { Button b = (Button)sender; converation = b.Text; //if (converation == "1∕x") //{ // result = 1 / (Double.Parse(txt_display.Text)); // txt_showops.Text = txt_showops + "1/" + txt_display.Text; // operation_str = txt_showops + result.ToString(); // txt_display.Text = result.ToString(); // enter_operation = true; // enter_value = true; // txt_history.Text = txt_showops.Text + " = " + result.ToString() + "\n" + txt_history.Text.ToString(); // result = new double(); //} //else if (converation == "x²") { result = Math.Pow(Double.Parse(txt_display.Text), 2); // txt_showops.Text = txt_showops + "1/" + txt_display.Text; // operation_str = txt_showops + result.ToString(); operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + txt_display.Text + "²"; txt_history.Text = txt_display.Text + "²" + " = " + result.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = result.ToString(); enter_operation = true; enter_value = false; result = new double(); } else if (converation == "✓") { result = Math.Sqrt(Double.Parse(txt_display.Text)); operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + " ✓" + txt_display.Text; txt_history.Text = " ✓" + txt_display.Text + " = " + result.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = result.ToString(); enter_operation = true; enter_value = false; result = new double(); } else if (converation == "±") { if (txt_display.Text != "") { result = -Double.Parse(txt_display.Text); txt_display.Text = result.ToString(); enter_operation = true; } } else if (converation == "n!") { int n = int.Parse(txt_display.Text); if (txt_display.Text != "-1") { operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + txt_display.Text + "!"; txt_history.Text = txt_display.Text + "! = " + n.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = n.ToString(); } else { txt_display.Text = "NaN"; } enter_operation = true; enter_value = false; result = new double(); } else if (converation == "10^x") { result = Math.Pow(10, Double.Parse(txt_display.Text)); operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + "10 ^ " + txt_display.Text; txt_history.Text = "10 ^ " + txt_display.Text + " = " + result.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = result.ToString(); enter_operation = true; enter_value = false; result = new double(); } else if (converation == "ln") { result = Math.Log(Double.Parse(txt_display.Text)); operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + "Ln(" + txt_display.Text + ")"; txt_history.Text = "Ln(" + txt_display.Text + ") = " + result.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = result.ToString(); enter_operation = true; enter_value = false; result = new double(); } else if (converation == "Log") { result = Math.Log10(Double.Parse(txt_display.Text)); operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + "Log(" + txt_display.Text + ")"; txt_history.Text = "Log(" + txt_display.Text + ") = " + result.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = result.ToString(); enter_operation = true; enter_value = false; result = new double(); } else if (converation == "Exp") { result = Math.Exp(Double.Parse(txt_display.Text)); operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + "Exp(" + txt_display.Text + ")"; txt_history.Text = "Exp(" + txt_display.Text + ") = " + result.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = result.ToString(); enter_operation = true; enter_value = false; result = new double(); } else if (converation == "sin") { if (degree) { if (int.Parse(txt_display.Text) % 180 != 0) { result = Math.Sin(Math.PI * Double.Parse(txt_display.Text) / 180.0); } else { result = 0; } } //RAD else { double degrees = Math.Round((180 / Math.PI) * double.Parse(txt_display.Text), 0); if (degrees % 180 != 0) { result = Math.Sin(Math.PI * degrees / 180.0); //result = Math.PI * result; } else { result = 0; } } operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + "sin(" + txt_display.Text + ")"; txt_history.Text = "sin(" + txt_display.Text + ") = " + result.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = result.ToString(); enter_operation = true; enter_value = false; result = new double(); } else if (converation == "cos") { if (degree) { if (int.Parse(txt_display.Text) % 90 != 0 || int.Parse(txt_display.Text) % 180 == 0) { result = Math.Cos(Math.PI * Double.Parse(txt_display.Text) / 180.0); } else { result = 0; } } //RAD else { double degrees = Math.Round((180 / Math.PI) * double.Parse(txt_display.Text), 0); if (degrees % 90 != 0 && degrees % 180 == 0) { result = Math.Cos(Math.PI * degrees / 180.0); //result = Math.PI * result; } else { result = 0; } } operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + "cos(" + txt_display.Text + ")"; txt_history.Text = "cos(" + txt_display.Text + ") = " + result.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = result.ToString(); enter_operation = true; enter_value = true; result = new double(); } else if (converation == "tan") { if (degree) { result = Math.Tan(Math.PI * Double.Parse(txt_display.Text) / 180.0); } else { result = Math.Tan(Double.Parse(txt_display.Text)); } operation_str = txt_showops.Text; txt_showops.Text = txt_showops.Text + "tan(" + txt_display.Text + ")"; txt_history.Text = "tan(" + txt_display.Text + ") = " + result.ToString() + "\n" + txt_history.Text.ToString(); txt_display.Text = result.ToString(); enter_operation = true; enter_value = false; result = new double(); } else if (converation == "sinh") { result = Math.Sinh(Double.Parse(txt_display.Text)); txt_showops.Text = "sinh( " + txt_display.Text + " )"; txt_display.Text = result.ToString(); txt_history.Text = txt_showops.Text + " = " + txt_display.Text + "\n" + txt_history.Text.ToString(); enter_operation = true; enter_value = true; result = new double(); } else if (converation == "cosh") { result = Math.Cosh(Double.Parse(txt_display.Text)); txt_showops.Text = "cosh( " + txt_display.Text + " )"; txt_display.Text = result.ToString(); txt_history.Text = txt_showops.Text + " = " + txt_display.Text + "\n" + txt_history.Text.ToString(); enter_operation = true; enter_value = true; result = new double(); } else if (converation == "tanh") { result = Math.Tanh(Double.Parse(txt_display.Text)); txt_showops.Text = "tanh( " + txt_display.Text + " )"; txt_display.Text = result.ToString(); txt_history.Text = txt_showops.Text + " = " + txt_display.Text + "\n" + txt_history.Text.ToString(); enter_operation = true; enter_value = true; result = new double(); } } }
// Methods // Todo: We're missing type-checking and appropriate error handling! // Todo: Switch to an type operator based computation! // Todo: Introduce Implicit Casting! public object Evaluate() { var stack = new SpecializedStack <Operand>(); var variables = new Dictionary <string, Operand>(); foreach (var token in _lexer.GetTokens()) { switch (token.Kind) { // Arithmetic Operators case TokenKind.Add: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber((decimal)left.Value + (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.Subtract: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber((decimal)left.Value - (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.Multiply: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber((decimal)left.Value * (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.Divide: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber((decimal)left.Value / (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.ClearStackAndVariables: { variables.Clear(); stack.Clear(); break; } case TokenKind.ClearStack: { stack.Clear(); break; } case TokenKind.ClearVariables: { variables.Clear(); break; } case TokenKind.BooleanNot: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Boolean) { stack.Push(Operand.FromBoolean(!(bool)operand.Value)); } else { throw new FormatException(); } break; } case TokenKind.Modulus: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber((decimal)left.Value % (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.Increment: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber((decimal)operand.Value + 1)); } else { throw new FormatException(); } break; } case TokenKind.Decrement: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber((decimal)operand.Value - 1)); } else { throw new FormatException(); } break; } // Bitwise Operators case TokenKind.BitwiseAnd: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { // Todo: Let's pretend we can always convert to a long. stack.Push(Operand.FromNumber((long)(decimal)left.Value & (long)(decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.BitwiseOr: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { // Todo: Let's pretend we can always convert to a long. stack.Push(Operand.FromNumber((long)(decimal)left.Value | (long)(decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.BitwiseXor: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { // Todo: Let's pretend we can always convert to a long. stack.Push(Operand.FromNumber((long)(decimal)left.Value ^ (long)(decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.BitwiseNot: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend we can always convert to a long. stack.Push(Operand.FromNumber(~(long)(decimal)operand.Value)); } else { throw new FormatException(); } break; } case TokenKind.BitwiseShiftLeft: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { // Todo: Let's pretend we can always convert to an int/long. stack.Push(Operand.FromNumber((long)(decimal)left.Value << (int)(decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.BitwiseShiftRight: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { // Todo: Let's pretend we can always convert to an int/long. stack.Push(Operand.FromNumber((long)(decimal)left.Value >> (int)(decimal)right.Value)); } else { throw new FormatException(); } break; } // Boolean Operators case TokenKind.BooleanAnd: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Boolean && right.Kind == OperandKind.Boolean) { stack.Push(Operand.FromBoolean((bool)left.Value && (bool)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.BooleanOr: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Boolean && right.Kind == OperandKind.Boolean) { stack.Push(Operand.FromBoolean((bool)left.Value || (bool)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.BooleanXor: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Boolean && right.Kind == OperandKind.Boolean) { var leftValue = (bool)left.Value; var rightValue = (bool)right.Value; stack.Push(Operand.FromBoolean((leftValue && leftValue == false) || (leftValue == false && leftValue))); } else { throw new FormatException(); } break; } // Comparison Operators case TokenKind.LessThan: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromBoolean((decimal)left.Value < (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.LessThanOrEqualTo: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromBoolean((decimal)left.Value <= (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.EqualTo: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromBoolean((decimal)left.Value == (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.GreaterThan: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromBoolean((decimal)left.Value > (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.GreaterThanOrEqualTo: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromBoolean((decimal)left.Value >= (decimal)right.Value)); } else { throw new FormatException(); } break; } case TokenKind.NotEqualTo: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromBoolean((decimal)left.Value != (decimal)right.Value)); } else { throw new FormatException(); } break; } // Trigonometric Functions case TokenKind.Acos: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Acos((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Asin: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Asin((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Atan: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Atan((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Cos: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Cos((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Cosh: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Cosh((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Sin: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Sin((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Sinh: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Sinh((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Tanh: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Tanh((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } // Numeric Utilities case TokenKind.Ceil: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber(Math.Ceiling((decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Floor: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber(Math.Floor((decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Round: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber(Math.Round((decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.IntegerPart: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber(Math.Truncate((decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.FloatingPart: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { var value = (decimal)operand.Value; stack.Push(Operand.FromNumber(value - Math.Truncate(value))); } else { throw new FormatException(); } break; } case TokenKind.Sign: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: I'm not sure I understand the documentation on this one! var value = (decimal)operand.Value; stack.Push(Operand.FromNumber(value < 0 ? -1 : 0)); } else { throw new FormatException(); } break; } case TokenKind.Absolute: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber(Math.Abs((decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Max: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber(Math.Max((decimal)left.Value, (decimal)right.Value))); } else { throw new FormatException(); } break; } case TokenKind.Min: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber(Math.Min((decimal)left.Value, (decimal)right.Value))); } else { throw new FormatException(); } break; } // Display Modes case TokenKind.DisplayAsHex: { DisplayMode = EvaluatorDisplayMode.Hexadecimal; break; } case TokenKind.DisplayAsDecimal: { DisplayMode = EvaluatorDisplayMode.Decimal; break; } case TokenKind.DisplayAsBinary: { DisplayMode = EvaluatorDisplayMode.Binary; break; } case TokenKind.DisplayAsOctal: { DisplayMode = EvaluatorDisplayMode.Octal; break; } // Constants case TokenKind.PushE: { stack.Push(Operand.FromNumber((decimal)Math.E)); break; } case TokenKind.PushPi: { stack.Push(Operand.FromNumber((decimal)Math.PI)); break; } case TokenKind.PushRandom: { stack.Push(Operand.FromNumber((decimal)_random.Next())); break; } // Mathematic Functions case TokenKind.Exp: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Exp((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Fact: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber(BuiltIn.Factorial((decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Sqrt: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Sqrt((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Ln: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Log((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Log: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to double! stack.Push(Operand.FromNumber((decimal)Math.Log10((double)(decimal)operand.Value))); } else { throw new FormatException(); } break; } case TokenKind.Pow: { var right = stack.Pop(); var left = stack.Pop(); if (left.Kind == OperandKind.Number && right.Kind == OperandKind.Number) { stack.Push(Operand.FromNumber((decimal)Math.Pow((double)(decimal)left.Value, (double)(decimal)right.Value))); } else { throw new FormatException(); } break; } // Networking case TokenKind.HostToNetworkLong: case TokenKind.HostToNetworkShort: case TokenKind.NetworkToHostLong: case TokenKind.NetworkToHostShort: { throw new NotImplementedException(); } // Stack Manipulation case TokenKind.Pick: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to int! stack.Push(stack.Pick((int)operand.Value)); } else { throw new FormatException(); } break; } case TokenKind.Repeat: { // Todo: Complete! throw new NotImplementedException(); } case TokenKind.Depth: { stack.Push(Operand.FromNumber(stack.Count)); break; } case TokenKind.Drop: { stack.Pop(); break; } case TokenKind.DropN: { var operand = stack.Pop(); if (operand.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to int! for (int i = 0; i < (int)operand.Value; i++) { stack.Pop(); } } else { throw new FormatException(); } break; } case TokenKind.Dup: { stack.Push(stack.Peek()); break; } case TokenKind.DupN: { var op1 = stack.Pop(); var op2 = stack.Peek(); if (op1.Kind == OperandKind.Number) { // Todo: Let's pretend it's ok to convert to int! for (int i = 0; i < (int)op1.Value; i++) { stack.Push(op2); } } else { throw new FormatException(); } break; } case TokenKind.Roll: case TokenKind.RollDownwards: case TokenKind.ToggleStack: case TokenKind.Swap: { // Todo: Implement! throw new NotImplementedException(); } // Macros and Variables case TokenKind.Macro: //case TokenKind.Variable: { // Todo: Implement! throw new NotImplementedException(); } // Operand case TokenKind.Operand: { stack.Push(Operand.FromNumber((decimal)token.Value)); break; } default: break; } } return(stack.Count > 0 ? stack.Pop().Value : null); }