RPN Calculator in Scala

The program starts by creating a stack variable st where intermediate values go in the course of evaluating an RPN expression.

The reading and processing of the input are performed in an ‘infinite’ loop. In fact the loop does end by calling exit upon detection of null instead of an actual string – signifying end-of-input – as the value received in s from readLine.

A non-null string s is being split into an array of tokens tks by first replacing all tab characters with spaces and then telling split to use spaces as delimiters. As empty tokens appear wherever there are two or more spaces in a row, the former get removed by calling filter.

The tks array is processed by means of a for loop where individual tokens tk are extracted in sequence.

A token tk is tried as a number at first. If it fails to parse as such, toDouble raises an exception, and the catch part of the try statement reacts by checking whether tk is an operator character; if so, the corresponding operation is performed, provided there are arguments for it kept on the stack st. In case the latter does not hold, one of the two calls of pop fails with generating an exception.

The initial zero values for x and y in the for's body are immaterial but required by the language's rules.

A successfully processed token eventually leads to a value x, either directly read or computed, being pushed on the stack. For a token that is neither a number nor an operator, however, an exception is thrown explicitly. An exception is also raised if, after all the tokens successfully get processed, st happens to hold more than one number. Thus all kinds of syntax errors that may be there in an RPN expression result in an exception being raised. As the whole evaluation of an input line takes place within a try statement, any such exception is caught and handled by printing an error message instead of a numeric result.

The names Stack and exit are qualified by prefixing them by the corresponding package names. Others, namely readLine and println are not explicitly qualified. They are provided (along with a number of other definitions of basic entities) by an implicitly imported object called Predef.

As given here, the program can be run by the Scala interpreter but not compiled. If a form suitable for compiling is needed, a couple of lines must be added to put an object context around the code.

var st = new scala.collection.mutable.Stack[Double]
while (true) {
  var s = readLine
  if (s==null) sys.exit()
  val tks = s.replaceAllLiterally("\t"," ").split(" ").filter(_!="")
  try {
    for (tk <- tks) {
      var x = 0.;  var y = 0.
      try {x = tk.toDouble}
      catch {case _ => {
               y = st.pop;  x = st.pop
               tk match {case "+" => x += y  case "-" => x -= y
                         case "*" => x *= y  case "/" => x /= y
                         case _ => throw new Error}}}
    if (st.length>1) throw new Error
    if (!st.isEmpty) println(st.pop)
  catch {case _ => {println("error"); st.clear}}