diff --git a/Program.cs b/Program.cs index f946490..df34652 100644 --- a/Program.cs +++ b/Program.cs @@ -7,31 +7,58 @@ namespace calculator { static void Main(string[] args) { + if (args.Length == 0) { - string input = readREPL(); + string input = REPL.read(); while (input != null) { - writeREPL(evaluate(input)); - input = readREPL(); + handleExpression(input); + input = REPL.read(); } } else - { - writeREPL(evaluate(args[0])); - } + handleExpression(args[0]); + } - static private double evaluate(string s) + static private void handleExpression(string s) { try { - string[] expr = s.Split(); - Stack st = new Stack(); + RPN calc = new RPN(s); + REPL.write(calc.evaluate()); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + } + } - for (int i = 0; i < expr.Length; i++) + class RPN + { + Stack st = new Stack(); + string[] tokens; + + public RPN(string s) + { + tokens = s.Split(); + } + public RPN(string[] ss) + { + tokens = new string[ss.Length]; + ss.CopyTo(tokens, 0); + } + + public double evaluate() + { + + for (int i = 0; i < tokens.Length; i++) + { + try { - object val = convertOne(expr[i]); + object val = convertOne(i); if (val is double number) st.Push(number); @@ -59,36 +86,57 @@ namespace calculator st.Push(Math.Pow(a, b)); break; default: - throw new Exception("Got unknown operator"); + throw new Exception("got unknown operator"); } } catch (InvalidOperationException) { - throw new Exception(oper + " operation requires two operands"); + throw new Exception("operator requires 2 arguments"); } } - else throw new Exception("Stack corrupted"); } + catch (Exception e) + { + throw new Exception(positionPointer(i, 2) + ' ' + e.Message); + } + } - return st.Pop(); - } - catch (Exception e) - { - Console.WriteLine(e.Message); - Environment.Exit(1); - return -1; - } + if (st.Count != 1) throw new Exception("Expression is not finished"); + + return st.Pop(); } - static private object convertOne(string s) + private string positionPointer(int pos, int gap) { + string prepend = ""; + for (int i = 1; i <= gap && pos - i >= 0; i++) + prepend = tokens[pos - i] + ' ' + prepend; + if (pos > gap) prepend = "... " + prepend; + + string append = " "; + for (int i = 1; i <= gap && pos + i < tokens.Length; i++) + append += tokens[pos + i] + ' '; + + if (pos < tokens.Length - 2) append += "..."; + + string arrow = "^".PadLeft(prepend.Length + 1); + + return prepend + tokens[pos] + append + '\n' + arrow; + } + + private object convertOne(int i) + { + string s = tokens[i]; double res; if (Double.TryParse(s, out res)) return res; else if (s.Length == 1) return s[0]; - else throw new Exception("Got multiple characters operator"); + else throw new Exception("got multiple characters operator"); } + } - static private string readREPL() + class REPL + { + static public string read() { Console.Write(">> "); string input = Console.ReadLine(); @@ -107,7 +155,7 @@ namespace calculator } } - static private void writeREPL(T o) + static public void write(T o) { Console.WriteLine(o); }