Last active
December 16, 2015 14:20
-
-
Save zuk/5448193 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import scala.io.Source | |
| import scala.util.matching.Regex | |
| import scala.collection._ | |
| object Spreadsheet extends App { | |
| val RefFormat = new Regex("([a-z]+)([1-9]+)", "row", "col") | |
| val LineFormat = new Regex("^([a-z]+)([1-9]+):(.*)", "row", "col", "expr") | |
| val ExprInt = new Regex("(-?\\d+)", "v") | |
| val ExprFloat = new Regex("(-?\\d+\\.\\d+)", "v") | |
| if (args.length != 1) { println("You must specify an input filename!") } | |
| val filename = args(0) | |
| // the raw spreadsheet, unevaluated | |
| var ss = mutable.Map[String, mutable.Map[Int, immutable.List[String]]]() | |
| // the evaluated spreadsheet | |
| var ssEval = mutable.Map[String, mutable.Map[Int, EvalResult]]() | |
| // load and parse the input file | |
| parseFile | |
| //println(ss.mkString("\n")) | |
| evalSpreadsheet | |
| printEvalSpreadsheet | |
| def parseFile { | |
| // NOTE: we're assuming UTF-8 encoding for the text file | |
| val lines = Source.fromFile(filename, "utf-8").getLines. | |
| filterNot { line => line.matches("^\\s+$") }. // get rid of blank lines | |
| map { line => line.replaceAll("\\r\\n", "") } // strip newline/cr chars | |
| //println(lines.mkString("\n")) | |
| lines.foreach { line => | |
| // NOTE: we ignore the dimension line since it's not needed | |
| line match { | |
| case LineFormat(x, y, expr) => { | |
| val row = if (ss contains x) | |
| ss(x) | |
| else | |
| mutable.Map[Int, immutable.List[String]]() | |
| row(y.toInt) = expr.split("\\s+").toList | |
| ss(x) = row | |
| } | |
| case _ => // ignore | |
| } | |
| } | |
| } | |
| def evalSpreadsheet { | |
| ss.foreach { row => | |
| val x = row._1 | |
| if (!(ssEval contains x)) | |
| ssEval(x) = mutable.Map[Int, EvalResult]() | |
| row._2.foreach { col => | |
| val y = col._1 | |
| try { | |
| ssEval(x)(y) = evalRef(x, y) | |
| } catch { | |
| case e: Exception => ssEval(x)(y) = new EvalResult(e) | |
| } | |
| } | |
| } | |
| } | |
| def evalRef(x: String, y: Int): EvalResult = { | |
| if (!(ssEval contains x)) | |
| ssEval(x) = mutable.Map[Int, EvalResult]() | |
| if (ssEval(x) contains y) { | |
| ssEval(x)(y) | |
| } else { | |
| val res = new EvalResult(evalExpression(ss(x)(y))) | |
| ssEval(x)(y) = res | |
| res | |
| } | |
| } | |
| def evalExpression(expr: immutable.List[String], stack: mutable.Stack[Float]): Float = { | |
| if (expr.length == 0) { | |
| stack.pop() | |
| } else { | |
| stack.push(expr.head match { | |
| case ExprInt(v) => v.toInt | |
| case ExprFloat(v) => v.toFloat | |
| case "+" => applyOp(stack, (a, b) => a + b) | |
| case "-" => applyOp(stack, (a, b) => a - b) | |
| case "*" => applyOp(stack, (a, b) => a * b) | |
| case "/" => applyOp(stack, (a, b) => a / b) | |
| case RefFormat(x, y) => evalRef(x, y.toInt).result | |
| }) | |
| evalExpression(expr.tail, stack) | |
| } | |
| } | |
| def evalExpression(expr: immutable.List[String]): Float = { | |
| evalExpression(expr, new mutable.Stack[Float]()) | |
| } | |
| def applyOp(stack: mutable.Stack[Float], op: (Float, Float) => Float): Float = { | |
| val op2 = stack.pop() | |
| val op1 = stack.pop() | |
| op(op1, op2) | |
| } | |
| def printEvalSpreadsheet { | |
| ssEval.foreach { row => | |
| val x = row._1 | |
| row._2.foreach { col => | |
| val y = col._1 | |
| println(x.toString + y.toString + ":" + col._2.toString) | |
| } | |
| } | |
| } | |
| class EvalResult(res: Float, err: Exception) { | |
| def result: Float = res | |
| def this(res: Float) = this(res, null) | |
| def this(err: Exception) = this(Float.NaN, err) | |
| override def toString: String = { | |
| if (err == null) | |
| res.toString | |
| else | |
| err.toString | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment