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