class RPN private(private val stack:List[Float]) { def this() = this(Nil) private def op2(func : (Float, Float) => Float) : RPN = { return stack match { case x :: y :: tail => new RPN((func(y, x)) :: tail) case tail => throw new IllegalStateException("Stack is empty") } } def number(x: Float) = new RPN(stack = x :: stack) def plus = op2(_ + _) def minus = op2(_ - _) def times = op2(_ * _) def divide = op2(_ / _) def result = if (!stack.isEmpty && stack.tail.isEmpty) stack.head else throw new IllegalStateException("Stack does not contain exactly one element") } class RPNParser { private val numberRegex = """^([0-9,.]+)$""".r; private def applyRPNPart(part: String, rpn: RPN): RPN = part match { case numberRegex(y) => rpn.number(y.toFloat) case "+" => rpn.plus case "-" => rpn.minus case "*" => rpn.times case "/" => rpn.divide case x => throw new IllegalArgumentException(x+" is not valid") } def calculate(expression: String): Float = { return calc(expression.split("""\s+""").toList, new RPN) } private def calc(parts: List[String], rpn: RPN): Float = { if (parts.isEmpty) { return rpn.result } else { try { return calc(parts.tail, applyRPNPart(parts.head, rpn)) } catch { case e @ (_:IllegalStateException|_:IllegalArgumentException) => throw new RuntimeException(e.getMessage()+ " in: "+parts.:\("")((x, y) => x+" "+y)) } } } } object Main { private def processTerm(term: String): Unit = { try { println(new RPNParser().calculate(term)) } catch { case e: RuntimeException => println(e.getMessage) } } def main(args: Array[String]): Unit = { var ok: Boolean = false do { val term = readLine("> ") ok = term != null && !term.isEmpty() if (ok) processTerm(term) } while (ok) } }