Skip to content

Instantly share code, notes, and snippets.

@kmizu
Created February 28, 2010 01:18
Show Gist options
  • Save kmizu/317099 to your computer and use it in GitHub Desktop.
Save kmizu/317099 to your computer and use it in GitHub Desktop.
import scala.util.parsing.combinator.{Parsers, ImplicitConversions}
import scala.util.parsing.input.CharArrayReader
import scala.util.parsing.input.CharSequenceReader
object GrassParser extends Parsers {
sealed abstract class I
type Code = List[I]
type Env = List[V]
type Ret = List[F]
case class App(m: Int, n: Int) extends I
case class Abs(n: Int, c: Code) extends I
sealed abstract class V
case class F(c: Code, e: Env) extends V
case class Chr(code: Char) extends V
case object Out extends V
case object Succ extends V
case object In extends V
type Elem = Char
val tokens = Set('W', 'W', 'w', 'w', 'v', 'V')
lazy val s = elem("", e => e != CharSequenceReader.EofCh && !tokens(e))*
lazy val ws = ((elem('w') | 'w') <~ s) ^^ (_ => 'w')
lazy val wb = ((elem('W') | 'W') <~ s) ^^ (_ => 'W')
lazy val v = ((elem('v') | 'V') <~ s) ^^ (_ => 'v')
lazy val app = wb.+ ~ ws.+ ^^ {e => App(e._1.size, e._2.size)}
lazy val abs = ws.+ ~ app.* ^^ {e => Abs(e._1.size, e._2)}
lazy val prog = abs ~ (v ~> (abs ^^ (List(_)) | app.+)).* ^^ {
case a ~ b => a::(b.flatten[I])
}
}
import GrassParser._
class GrassInterpreter {
def run(prog: String) {
GrassParser.prog(new CharArrayReader(prog.toCharArray)) match {
case GrassParser.Success(code, _) =>
eval(code, Out::Succ::Chr('w')::In::Nil, F(App(1, 1)::Nil, Nil)::F(Nil, Nil)::Nil)
case _ => error("parse failure")
}
}
private[this] def eval(c: Code, e: Env, d: Ret) {
(c, e, d) match {
case (App(m, n)::c, e, d) =>
(e(m - 1), e(n - 1)) match {
case (F(cm, em), arg) => eval(cm, arg::em, F(c, e)::d)
case (Chr(ch1), Chr(ch2)) =>
if(ch1 == ch2) eval(c, F(Abs(1, App(3, 2)::Nil)::Nil, F(Nil, Nil)::Nil)::e, d)
else eval(c, F(Abs(1, Nil)::Nil, Nil)::e, d)
case (Out, arg@Chr(ch)) =>
System.out.print(ch)
eval(c, arg::e, d)
case (In, arg) =>
val ch = System.in.read()
if(ch == -1) eval(c, arg::e, d)
else eval(c, Chr(ch.toChar)::e, d)
case (Succ, Chr(ch)) =>
if(ch == 255) eval(c, Chr(0)::e, d)
else eval(c, Chr((ch + 1).toChar)::e, d)
case _ => error("runtime error!")
}
case (Abs(n, c_dash)::c, e, d) =>
if(n == 1) eval(c, F(c_dash, e)::e, d)
else eval(c, F(Abs(n - 1, c_dash)::Nil, e)::e, d)
case (Nil, f::e, F(c_dash, e_dash)::d) =>
eval(c_dash, f::e_dash, d)
case (Nil, f::Nil, Nil) => f
case _ => error("runtime error!")
}
}
}
object Grass {
def main(args: Array[String]) {
import java.io.File
import scala.io.Source
val src = Source.fromFile(new File(args(0)))
val input = src.getLines().mkString("")
new GrassInterpreter().run(input)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment