scala/ScalaBook/chapter-04/ramint.scala

import scala.util.parsing.combinator._
trait Command
case class Commands(cmds: List[Command]) extends Command
case class IFcomm(cond: String, 
                  then_part: Commands, 
                  else_part: Commands) extends Command
case class WHILEcomm(cond: String, do_part: Commands) extends Command
case class WRITEcomm(outvar: String) extends Command
case class READcomm(invar: String) extends Command
case class ASSIGNMENTcomm(ass_var: String, action: String) extends Command

object RAMparser extends JavaTokenParsers {
  def commands = rep(command) ^^ { case cmds => Commands(cmds) } 
  def command  = ifcommand | whilecommand | writecommand | 
                 readcommand | assignment | failure("unexpected symbol")
  def ifcommand: Parser[Command]  = ("if" ~ ident ~ "=" ~ "0" ~ "then" ~ commands ~ optElse ~ "end") ^^ 
                                     { case "if" ~ id ~ "=" ~ "0" ~ "then" ~ thenpart ~ elsepart ~ "end" => 
                                       IFcomm(id,thenpart,elsepart)}
  def optElse: Parser[Commands]  = opt("else"~commands) ^^ { case None => Commands(Nil)
                                                             case Some("else"~cmds) => cmds} 
  def whilecommand: Parser[Command]  = ("while" ~ ident ~ "=" ~ "0" ~ "do" ~ commands ~ "end") ^^ 
                                  {case "while"~id~"="~"0"~"do"~cmds~"end" => WHILEcomm(id,cmds) }
  def writecommand = ("write" ~ ident) ^^ { case "write"~id => WRITEcomm(id) }
  def readcommand = ("read" ~ ident) ^^ { case "read"~id => READcomm(id) }
  def assignment = (ident ~ ("++" | "--")) ^^ { case id~op => ASSIGNMENTcomm(id,op) }
}

var ST: Map[String,Int] = Map() 
def eval(commands: List[Command]): Unit = {
  if (! commands.isEmpty) {
    commands.head match {
      case IFcomm(condvar,thenPart,elsePart) => if (! ST.contains(condvar) ) 
                                                  ST += (condvar -> 0)
                                                if ( ST(condvar) == 0 )
                                                  eval(thenPart.cmds)
                                                else
                                                  eval(elsePart.cmds)
      case WHILEcomm(condvar, doCMDs) => if (! ST.contains(condvar) ) ST += (condvar -> 0)
                                         while ( ST(condvar) == 0 ) {                                         
                                           eval(doCMDs.cmds)
                                         }
      case WRITEcomm(myvar) => if (! ST.contains(myvar) ) {
                                 ST += (myvar -> 0)
                               }
                               println(ST(myvar))
      case READcomm(myvar)  => if (! ST.contains(myvar) ) {
                                 ST += (myvar -> 0)
                               }
                               print("? ")
                               var x = readInt()                               
                               if (x < 0) {
                                 println("***ERROR: Number cannot be negative")
                                 return
                               } 
                               else
                                 ST += (myvar -> x)
      case ASSIGNMENTcomm(invar,act) => if (! ST.contains(invar) ) {
                                          ST += (invar -> 0)
                                        } 
                                       if (act == "++") 
                                          ST += (invar -> (ST(invar)+1))
                                        else {
                                           if ( ST(invar) > 0 )
                                             ST += (invar -> (ST(invar)-1))
                                        } 
    }
    eval(commands.tail)
  } 
}

import java.io.FileReader

if (args.isEmpty) 
  println("Usage: ramint input_file")
else if (args.length > 1) 
  println("Usage: ramint input_file")
else {
  try {
    val reader = new FileReader(args(0))
    val result = 
      RAMparser.parseAll(RAMparser.commands, reader)
    if ( result.successful) {
      val parseTree = result.get 
      eval(parseTree.cmds)
    }
    else
      println(result)
  } catch {
    case e : Exception => 
       println("File "+args(0)+" does not exist") 
       exit()
  } 
}