| 742 |      1 | // Parser Combinators:
 | 
|  |      2 | // Simple Version for WHILE-language
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      3 | //====================================
 | 
| 742 |      4 | //
 | 
|  |      5 | // with some added convenience for
 | 
|  |      6 | // map-parsers and grammar rules
 | 
|  |      7 | //
 | 
|  |      8 | // call with
 | 
|  |      9 | //
 | 
|  |     10 | //    amm comb2.sc
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     11 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     12 | 
 | 
| 742 |     13 | // more convenience for the map parsers later on;
 | 
|  |     14 | // it allows writing nested patterns as
 | 
|  |     15 | // case x ~ y ~ z => ...
 | 
|  |     16 | 
 | 
| 849 |     17 | 
 | 
|  |     18 | 
 | 
| 803 |     19 | case class ~[+A, +B](x: A, y: B)
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     20 | 
 | 
| 742 |     21 | // constraint for the input
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     22 | type IsSeq[A] = A => Seq[_]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     23 | 
 | 
| 742 |     24 | 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     25 | abstract class Parser[I : IsSeq, T]{
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     26 |   def parse(in: I): Set[(T, I)]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     27 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     28 |   def parse_all(in: I) : Set[T] =
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     29 |     for ((hd, tl) <- parse(in); 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     30 |         if tl.isEmpty) yield hd
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     31 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     32 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     33 | // parser combinators
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     34 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     35 | // sequence parser
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     36 | class SeqParser[I : IsSeq, T, S](p: => Parser[I, T], 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     37 |                                  q: => Parser[I, S]) extends Parser[I, ~[T, S]] {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     38 |   def parse(in: I) = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     39 |     for ((hd1, tl1) <- p.parse(in); 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     40 |          (hd2, tl2) <- q.parse(tl1)) yield (new ~(hd1, hd2), tl2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     41 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     42 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     43 | // alternative parser
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     44 | class AltParser[I : IsSeq, T](p: => Parser[I, T], 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     45 |                               q: => Parser[I, T]) extends Parser[I, T] {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     46 |   def parse(in: I) = p.parse(in) ++ q.parse(in)   
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     47 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     48 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     49 | // map parser
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     50 | class MapParser[I : IsSeq, T, S](p: => Parser[I, T], 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     51 |                                  f: T => S) extends Parser[I, S] {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     52 |   def parse(in: I) = for ((hd, tl) <- p.parse(in)) yield (f(hd), tl)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     53 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     54 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     55 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     56 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     57 | // atomic parser for (particular) strings
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     58 | case class StrParser(s: String) extends Parser[String, String] {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     59 |   def parse(sb: String) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     60 |     val (prefix, suffix) = sb.splitAt(s.length)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     61 |     if (prefix == s) Set((prefix, suffix)) else Set()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     62 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     63 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     64 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     65 | // atomic parser for identifiers (variable names)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     66 | case object IdParser extends Parser[String, String] {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     67 |   val reg = "[a-z][a-z,0-9]*".r
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     68 |   def parse(sb: String) = reg.findPrefixOf(sb) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     69 |     case None => Set()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     70 |     case Some(s) => Set(sb.splitAt(s.length))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     71 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     72 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     73 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     74 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     75 | // atomic parser for numbers (transformed into ints)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     76 | case object NumParser extends Parser[String, Int] {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     77 |   val reg = "[0-9]+".r
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     78 |   def parse(sb: String) = reg.findPrefixOf(sb) match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     79 |     case None => Set()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     80 |     case Some(s) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     81 |       val (hd, tl) = sb.splitAt(s.length)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     82 |       Set((hd.toInt, tl)) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     83 |     }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     84 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     85 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     86 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     87 | // the following string interpolation allows us to write 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     88 | // StrParser(_some_string_) more conveniently as 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     89 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     90 | // p"<_some_string_>" 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     91 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     92 | implicit def parser_interpolation(sc: StringContext) = new {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     93 |     def p(args: Any*) = StrParser(sc.s(args:_*))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     94 | }    
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     95 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     96 | // more convenient syntax for parser combinators
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     97 | implicit def ParserOps[I : IsSeq, T](p: Parser[I, T]) = new {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     98 |   def ||(q : => Parser[I, T]) = new AltParser[I, T](p, q)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     99 |   def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    100 |   def map[S](f: => T => S) = new MapParser[I, T, S](p, f)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    101 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    102 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    103 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    104 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    105 | // the abstract syntax trees for the WHILE language
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    106 | abstract class Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    107 | abstract class AExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    108 | abstract class BExp 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    109 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    110 | type Block = List[Stmt]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    111 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    112 | case object Skip extends Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    113 | case class If(a: BExp, bl1: Block, bl2: Block) extends Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    114 | case class While(b: BExp, bl: Block) extends Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    115 | case class Assign(s: String, a: AExp) extends Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    116 | case class Write(s: String) extends Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    117 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    118 | case class Var(s: String) extends AExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    119 | case class Num(i: Int) extends AExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    120 | case class Aop(o: String, a1: AExp, a2: AExp) extends AExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    121 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    122 | case object True extends BExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    123 | case object False extends BExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    124 | case class Bop(o: String, a1: AExp, a2: AExp) extends BExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    125 | case class And(b1: BExp, b2: BExp) extends BExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    126 | case class Or(b1: BExp, b2: BExp) extends BExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    127 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    128 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    129 | // arithmetic expressions
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    130 | lazy val AExp: Parser[String, AExp] = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    131 |   (Te ~ p"+" ~ AExp).map[AExp]{ case x ~ _ ~ z => Aop("+", x, z) } ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    132 |   (Te ~ p"-" ~ AExp).map[AExp]{ case x ~ _ ~ z => Aop("-", x, z) } || Te
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    133 | lazy val Te: Parser[String, AExp] = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    134 |   (Fa ~ p"*" ~ Te).map[AExp]{ case x ~ _ ~ z => Aop("*", x, z) } || 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    135 |   (Fa ~ p"/" ~ Te).map[AExp]{ case x ~ _ ~ z => Aop("/", x, z) } || Fa  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    136 | lazy val Fa: Parser[String, AExp] = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    137 |    (p"(" ~ AExp ~ p")").map{ case _ ~ y ~ _ => y } || 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    138 |    IdParser.map(Var) || 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    139 |    NumParser.map(Num)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    140 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    141 | // boolean expressions with some simple nesting
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    142 | lazy val BExp: Parser[String, BExp] = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    143 |    (AExp ~ p"==" ~ AExp).map[BExp]{ case x ~ _ ~ z => Bop("==", x, z) } || 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    144 |    (AExp ~ p"!=" ~ AExp).map[BExp]{ case x ~ _ ~ z => Bop("!=", x, z) } || 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    145 |    (AExp ~ p"<" ~ AExp).map[BExp]{ case x ~ _ ~ z => Bop("<", x, z) } || 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    146 |    (AExp ~ p">" ~ AExp).map[BExp]{ case x ~ _ ~ z => Bop(">", x, z) } ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    147 |    (p"(" ~ BExp ~ p")" ~ p"&&" ~ BExp).map[BExp]{ case _ ~ y ~ _ ~ _ ~ v => And(y, v) } ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    148 |    (p"(" ~ BExp ~ p")" ~ p"||" ~ BExp).map[BExp]{ case _ ~ y ~ _ ~ _ ~ v => Or(y, v) } ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    149 |    (p"true".map[BExp]{ _ => True }) || 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    150 |    (p"false".map[BExp]{ _ => False }) ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    151 |    (p"(" ~ BExp ~ p")").map[BExp]{ case _ ~ x ~ _ => x }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    152 | 
 | 
| 742 |    153 | // a single statement 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    154 | lazy val Stmt: Parser[String, Stmt] =
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    155 |   ((p"skip".map[Stmt]{_ => Skip }) ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    156 |    (IdParser ~ p":=" ~ AExp).map[Stmt]{ case x ~ _ ~ z => Assign(x, z) } ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    157 |    (p"write(" ~ IdParser ~ p")").map[Stmt]{ case _ ~ y ~ _ => Write(y) } ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    158 |    (p"if" ~ BExp ~ p"then" ~ Block ~ p"else" ~ Block)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    159 |      .map[Stmt]{ case _ ~ y ~ _ ~ u ~ _ ~ w => If(y, u, w) } ||
 | 
| 812 |    160 |    (p"while" ~ BExp ~ p"do" ~ Block).map[Stmt]{ case _ ~ y ~ _ ~ w => While(y, w) })   
 | 
|  |    161 |  
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    162 |  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    163 | // statements
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    164 | lazy val Stmts: Parser[String, Block] =
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    165 |   (Stmt ~ p";" ~ Stmts).map[Block]{ case x ~ _ ~ z => x :: z } ||
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    166 |   (Stmt.map[Block]{ s => List(s) })
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    167 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    168 | // blocks (enclosed in curly braces)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    169 | lazy val Block: Parser[String, Block] =
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    170 |   ((p"{" ~ Stmts ~ p"}").map{ case _ ~ y ~ _ => y } || 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    171 |    (Stmt.map(s => List(s))))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    172 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    173 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    174 | // Examples
 | 
| 803 |    175 | Stmt.parse_all("x2:=5+3")
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    176 | Block.parse_all("{x:=5;y:=8}")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    177 | Block.parse_all("if(false)then{x:=5}else{x:=10}")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    178 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    179 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    180 | val fib = """n := 10;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    181 |              minus1 := 0;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    182 |              minus2 := 1;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    183 |              temp := 0;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    184 |              while (n > 0) do {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    185 |                  temp := minus2;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    186 |                  minus2 := minus1 + minus2;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    187 |                  minus1 := temp;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    188 |                  n := n - 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    189 |              };
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    190 |              result := minus2""".replaceAll("\\s+", "")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    191 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    192 | Stmts.parse_all(fib)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    193 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    194 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    195 | // an interpreter for the WHILE language
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    196 | type Env = Map[String, Int]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    197 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    198 | def eval_aexp(a: AExp, env: Env) : Int = a match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    199 |   case Num(i) => i
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    200 |   case Var(s) => env(s)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    201 |   case Aop("+", a1, a2) => eval_aexp(a1, env) + eval_aexp(a2, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    202 |   case Aop("-", a1, a2) => eval_aexp(a1, env) - eval_aexp(a2, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    203 |   case Aop("*", a1, a2) => eval_aexp(a1, env) * eval_aexp(a2, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    204 |   case Aop("/", a1, a2) => eval_aexp(a1, env) / eval_aexp(a2, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    205 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    206 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    207 | def eval_bexp(b: BExp, env: Env) : Boolean = b match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    208 |   case True => true
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    209 |   case False => false
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    210 |   case Bop("==", a1, a2) => eval_aexp(a1, env) == eval_aexp(a2, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    211 |   case Bop("!=", a1, a2) => !(eval_aexp(a1, env) == eval_aexp(a2, env))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    212 |   case Bop(">", a1, a2) => eval_aexp(a1, env) > eval_aexp(a2, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    213 |   case Bop("<", a1, a2) => eval_aexp(a1, env) < eval_aexp(a2, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    214 |   case And(b1, b2) => eval_bexp(b1, env) && eval_bexp(b2, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    215 |   case Or(b1, b2) => eval_bexp(b1, env) || eval_bexp(b2, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    216 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    217 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    218 | def eval_stmt(s: Stmt, env: Env) : Env = s match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    219 |   case Skip => env
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    220 |   case Assign(x, a) => env + (x -> eval_aexp(a, env))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    221 |   case If(b, bl1, bl2) => if (eval_bexp(b, env)) eval_bl(bl1, env) else eval_bl(bl2, env) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    222 |   case While(b, bl) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    223 |     if (eval_bexp(b, env)) eval_stmt(While(b, bl), eval_bl(bl, env))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    224 |     else env
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    225 |   case Write(x) => { println(env(x)) ; env }  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    226 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    227 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    228 | def eval_bl(bl: Block, env: Env) : Env = bl match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    229 |   case Nil => env
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    230 |   case s::bl => eval_bl(bl, eval_stmt(s, env))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    231 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    232 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    233 | def eval(bl: Block) : Env = eval_bl(bl, Map())
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    234 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    235 | // parse + evaluate fib program; then lookup what is
 | 
| 742 |    236 | // stored under the variable "result" 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    237 | println(eval(Stmts.parse_all(fib).head)("result"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    238 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    239 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    240 | // more examles
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    241 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    242 | // calculate and print all factors bigger 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    243 | // than 1 and smaller than n
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    244 | println("Factors")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    245 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    246 | val factors =  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    247 |    """n := 12;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    248 |       f := 2;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    249 |       while (f < n / 2 + 1) do {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    250 |         if ((n / f) * f == n) then  { write(f) } else { skip };
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    251 |         f := f + 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    252 |       }""".replaceAll("\\s+", "")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    253 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    254 | println(eval(Stmts.parse_all(factors).head))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    255 | 
 | 
| 742 |    256 | 
 | 
| 732 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    257 | // calculate all prime numbers up to a number 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    258 | println("Primes")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    259 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    260 | val primes =  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    261 |    """end := 100;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    262 |       n := 2;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    263 |       while (n < end) do {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    264 |         f := 2;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    265 |         tmp := 0;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    266 |         while ((f < n / 2 + 1) && (tmp == 0)) do {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    267 |           if ((n / f) * f == n) then  { tmp := 1 } else { skip };
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    268 |           f := f + 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    269 |         };
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    270 |         if (tmp == 0) then { write(n) } else { skip };
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    271 |         n  := n + 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    272 |       }""".replaceAll("\\s+", "")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    273 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    274 | println(eval(Stmts.parse_all(primes).head))
 | 
| 828 |    275 | 
 | 
|  |    276 | 
 | 
|  |    277 | 
 | 
|  |    278 | 
 | 
|  |    279 | 
 | 
|  |    280 | // runs with amm2 and amm3
 |