| author | cu | 
| Wed, 25 Oct 2017 00:05:59 +0100 | |
| changeset 528 | 74a6cd2d011f | 
| parent 471 | e5df48ff7033 | 
| child 529 | 3725e24f1a19 | 
| permissions | -rw-r--r-- | 
| 471 | 1 | // A parser and evaluator for the while language | 
| 2 | // | |
| 3 | ||
| 172 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 4 | import scala.language.implicitConversions | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 5 | import scala.language.reflectiveCalls | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 6 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 7 | abstract class Parser[I <% Seq[_], T] {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 8 | def parse(ts: I): Set[(T, I)] | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 9 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 10 | def parse_all(ts: I) : Set[T] = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 11 | for ((head, tail) <- parse(ts); if (tail.isEmpty)) yield head | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 12 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 13 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 14 | class SeqParser[I <% Seq[_], T, S](p: => Parser[I, T], q: => Parser[I, S]) extends Parser[I, (T, S)] {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 15 | def parse(sb: I) = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 16 | for ((head1, tail1) <- p.parse(sb); | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 17 | (head2, tail2) <- q.parse(tail1)) yield ((head1, head2), tail2) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 18 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 19 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 20 | class AltParser[I <% Seq[_], T](p: => Parser[I, T], q: => Parser[I, T]) extends Parser[I, T] {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 21 | def parse(sb: I) = p.parse(sb) ++ q.parse(sb) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 22 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 23 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 24 | class FunParser[I <% Seq[_], T, S](p: => Parser[I, T], f: T => S) extends Parser[I, S] {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 25 | def parse(sb: I) = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 26 | for ((head, tail) <- p.parse(sb)) yield (f(head), tail) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 27 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 28 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 29 | case class StringParser(s: String) extends Parser[String, String] {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 30 |   def parse(sb: String) = {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 31 | val (prefix, suffix) = sb.splitAt(s.length) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 32 | if (prefix == s) Set((prefix, suffix)) else Set() | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 33 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 34 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 35 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 36 | case object NumParser extends Parser[String, Int] {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 37 | val reg = "[0-9]+".r | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 38 |   def parse(sb: String) = reg.findPrefixOf(sb) match {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 39 | case None => Set() | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 40 |     case Some(s) => {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 41 | val (head, tail) = sb.splitAt(s.length) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 42 | Set((head.toInt, tail)) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 43 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 44 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 45 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 46 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 47 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 48 | implicit def string2parser(s : String) = StringParser(s) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 49 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 50 | implicit def ParserOps[I<% Seq[_], T](p: Parser[I, T]) = new {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 51 | def || (q : => Parser[I, T]) = new AltParser[I, T](p, q) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 52 | def ==>[S] (f: => T => S) = new FunParser[I, T, S](p, f) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 53 | def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 54 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 55 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 56 | implicit def StringOps(s: String) = new {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 57 | def || (q : => Parser[String, String]) = new AltParser[String, String](s, q) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 58 | def || (r: String) = new AltParser[String, String](s, r) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 59 | def ==>[S] (f: => String => S) = new FunParser[String, String, S](s, f) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 60 | def ~[S](q : => Parser[String, S]) = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 61 | new SeqParser[String, String, S](s, q) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 62 | def ~ (r: String) = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 63 | new SeqParser[String, String, String](s, r) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 64 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 65 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 66 | lazy val E: Parser[String, Int] = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 67 |   (T ~ "+" ~ E) ==> { case ((x, y), z) => x + z} || T  
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 68 | lazy val T: Parser[String, Int] = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 69 |   (F ~ "*" ~ T) ==> { case ((x, y), z) => x * z} || F
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 70 | lazy val F: Parser[String, Int] = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 71 |   ("(" ~ E ~ ")") ==> { case ((x, y), z) => y} || NumParser
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 72 | |
| 185 
ea8b94d4755e
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
173diff
changeset | 73 | println(E.parse_all("1*2+3"))
 | 
| 
ea8b94d4755e
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
173diff
changeset | 74 | println(E.parse_all("1+2*3"))
 | 
| 
ea8b94d4755e
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
173diff
changeset | 75 | println(E.parse_all("1+2+3"))
 | 
| 172 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 76 | println(E.parse_all("1+2+3"))
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 77 | println(E.parse_all("1+2*3+1"))
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 78 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 79 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 80 | // no left-recursion allowed | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 81 | lazy val EL: Parser[String, Int] = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 82 |   ((EL ~ "+" ~ EL) ==> { case ((x, y), z) => x + z} || 
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 83 |    (EL ~ "*" ~ EL) ==> { case ((x, y), z) => x * z} ||
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 84 |    ("(" ~ EL ~ ")") ==> { case ((x, y), z) => y} ||
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 85 | NumParser) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 86 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 87 | //println(E.parse_all("1+2+3"))
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 88 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 89 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 90 | // the abstract syntax trees for the WHILE language | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 91 | abstract class Stmt | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 92 | abstract class AExp | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 93 | abstract class BExp | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 94 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 95 | type Block = List[Stmt] | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 96 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 97 | case object Skip extends Stmt | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 98 | case class If(a: BExp, bl1: Block, bl2: Block) extends Stmt | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 99 | case class While(b: BExp, bl: Block) extends Stmt | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 100 | case class Assign(s: String, a: AExp) extends Stmt | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 101 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 102 | case class Var(s: String) extends AExp | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 103 | case class Num(i: Int) extends AExp | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 104 | case class Aop(o: String, a1: AExp, a2: AExp) extends AExp | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 105 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 106 | case object True extends BExp | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 107 | case object False extends BExp | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 108 | case class Bop(o: String, a1: AExp, a2: AExp) extends BExp | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 109 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 110 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 111 | case object IdParser extends Parser[String, String] {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 112 | val reg = "[a-z][a-z,0-9]*".r | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 113 |   def parse(sb: String) = reg.findPrefixOf(sb) match {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 114 | case None => Set() | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 115 | case Some(s) => Set(sb.splitAt(s.length)) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 116 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 117 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 118 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 119 | lazy val AExp: Parser[String, AExp] = | 
| 173 
7cfb7a6f7c99
added slides
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
172diff
changeset | 120 |   ((Te ~ "+" ~ AExp) ==> { case ((x, y), z) => Aop("+", x, z):AExp } ||
 | 
| 
7cfb7a6f7c99
added slides
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
172diff
changeset | 121 |    (Te ~ "-" ~ AExp) ==> { case ((x, y), z) => Aop("-", x, z):AExp } || Te)  
 | 
| 172 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 122 | lazy val Te: Parser[String, AExp] = | 
| 173 
7cfb7a6f7c99
added slides
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
172diff
changeset | 123 |   (Fa ~ "*" ~ Te) ==> { case ((x, y), z) => Aop("*", x, z):AExp } || Fa
 | 
| 172 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 124 | lazy val Fa: Parser[String, AExp] = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 125 |   (("(" ~ AExp ~ ")") ==> { case ((x, y), z) => y } || 
 | 
| 173 
7cfb7a6f7c99
added slides
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
172diff
changeset | 126 | IdParser ==> Var || | 
| 
7cfb7a6f7c99
added slides
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
172diff
changeset | 127 | NumParser ==> Num) | 
| 172 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 128 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 129 | // boolean expressions | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 130 | lazy val BExp: Parser[String, BExp] = | 
| 471 | 131 |   ((AExp ~ "=" ~ AExp) ==> { case ((x, y), z) => Bop("=", x, z):BExp } || 
 | 
| 132 |    (AExp ~ "!=" ~ AExp) ==> { case ((x, y), z) => Bop("!=", x, z):BExp } || 
 | |
| 133 |    (AExp ~ "<" ~ AExp) ==> { case ((x, y), z) => Bop("<", x, z):BExp } || 
 | |
| 134 |    (AExp ~ ">" ~ AExp) ==> { case ((x, y), z) => Bop(">", x, z):BExp } || 
 | |
| 135 |    ("true" ==> ((_) => True:BExp )) || 
 | |
| 136 |    ("false" ==> ((_) => False:BExp )) ||
 | |
| 172 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 137 |    ("(" ~ BExp ~ ")") ==> { case ((x, y), z) => y})
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 138 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 139 | lazy val Stmt: Parser[String, Stmt] = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 140 |   (("skip" ==> ((_) => Skip: Stmt)) ||
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 141 |    (IdParser ~ ":=" ~ AExp) ==> { case ((x, y), z) => Assign(x, z): Stmt } ||
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 142 |    ("if" ~ BExp ~ "then" ~ Block ~ "else" ~ Block) ==>
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 143 |     { case (((((x,y),z),u),v),w) => If(y, u, w): Stmt } ||
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 144 |    ("while" ~ BExp ~ "do" ~ Block) ==> { case (((x, y), z), w) => While(y, w) }) 
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 145 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 146 | lazy val Stmts: Parser[String, Block] = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 147 |   (Stmt ~ ";" ~ Stmts) ==> { case ((x, y), z) => x :: z : Block } ||
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 148 | (Stmt ==> ((s) => List(s) : Block)) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 149 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 150 | lazy val Block: Parser[String, Block] = | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 151 |   (("{" ~ Stmts ~ "}") ==> { case ((x, y), z) => y} || 
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 152 | (Stmt ==> ((s) => List(s)))) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 153 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 154 | |
| 471 | 155 | Stmt.parse_all("x2:=5")
 | 
| 172 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 156 | Block.parse_all("{x:=5;y:=8}")
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 157 | Block.parse_all("if(false)then{x:=5}else{x:=10}")
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 158 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 159 | val fib = """{n:=10;minus1:=0;minus2:=1;temp:=0;while(n>0)do{temp:=minus2;minus2:=minus1+minus2;minus1:=temp;n:=n-1};result:=minus2}"""
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 160 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 161 | Block.parse_all(fib) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 162 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 163 | // an interpreter for the WHILE language | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 164 | type Env = Map[String, Int] | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 165 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 166 | def eval_aexp(a: AExp, env : Env) : Int = a match {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 167 | case Num(i) => i | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 168 | case Var(s) => env(s) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 169 |   case Aop("+", a1, a2) => eval_aexp(a1, env) + eval_aexp(a2, env)
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 170 |   case Aop("-", a1, a2) => eval_aexp(a1, env) - eval_aexp(a2, env)
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 171 |   case Aop("*", a1, a2) => eval_aexp(a1, env) * eval_aexp(a2, env)
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 172 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 173 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 174 | def eval_bexp(b: BExp, env: Env) : Boolean = b match {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 175 | case True => true | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 176 | case False => false | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 177 |   case Bop("=", a1, a2) => eval_aexp(a1, env) == eval_aexp(a2, env)
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 178 |   case Bop("!=", a1, a2) => !(eval_aexp(a1, env) == eval_aexp(a2, env))
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 179 |   case Bop(">", a1, a2) => eval_aexp(a1, env) > eval_aexp(a2, env)
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 180 |   case Bop("<", a1, a2) => eval_aexp(a1, env) < eval_aexp(a2, env)
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 181 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 182 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 183 | def eval_stmt(s: Stmt, env: Env) : Env = s match {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 184 | case Skip => env | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 185 | case Assign(x, a) => env + (x -> eval_aexp(a, env)) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 186 | case If(b, bl1, bl2) => if (eval_bexp(b, env)) eval_bl(bl1, env) else eval_bl(bl2, env) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 187 | case While(b, bl) => | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 188 | if (eval_bexp(b, env)) eval_stmt(While(b, bl), eval_bl(bl, env)) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 189 | else env | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 190 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 191 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 192 | def eval_bl(bl: Block, env: Env) : Env = bl match {
 | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 193 | case Nil => env | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 194 | case s::bl => eval_bl(bl, eval_stmt(s, env)) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 195 | } | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 196 | |
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 197 | def eval(bl: Block) : Env = eval_bl(bl, Map()) | 
| 
47b5c91eff47
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 198 | |
| 471 | 199 | println(eval(Block.parse_all(fib).head)("result"))
 |