| author | Christian Urban <christian.urban@kcl.ac.uk> | 
| Fri, 24 Oct 2025 10:45:17 +0100 | |
| changeset 1017 | b0d44eb1ecc7 | 
| parent 742 | b5b5583a3a08 | 
| permissions | -rw-r--r-- | 
| 92 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 1 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 2 | // regular expressions including NOT | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 3 | abstract class Rexp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 4 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 5 | case object NULL extends Rexp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 6 | case object EMPTY extends Rexp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 7 | case object ALLC extends Rexp // recognises any character | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 8 | case class CHAR(c: Char) extends Rexp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 9 | case class ALT(r1: Rexp, r2: Rexp) extends Rexp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 10 | case class SEQ(r1: Rexp, r2: Rexp) extends Rexp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 11 | case class STAR(r: Rexp) extends Rexp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 12 | case class NOT(r: Rexp) extends Rexp // negation of a regular expression | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 13 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 14 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 15 | // nullable function: tests whether the regular | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 16 | // expression can recognise the empty string | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 17 | def nullable (r: Rexp) : Boolean = r match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 18 | case NULL => false | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 19 | case EMPTY => true | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 20 | case ALLC => false | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 21 | case CHAR(_) => false | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 22 | case ALT(r1, r2) => nullable(r1) || nullable(r2) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 23 | case SEQ(r1, r2) => nullable(r1) && nullable(r2) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 24 | case STAR(_) => true | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 25 | case NOT(r) => !(nullable(r)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 26 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 27 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 28 | // tests whether a regular expression | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 29 | // cannot recognise more | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 30 | def no_more (r: Rexp) : Boolean = r match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 31 | case NULL => true | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 32 | case EMPTY => false | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 33 | case ALLC => false | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 34 | case CHAR(_) => false | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 35 | case ALT(r1, r2) => no_more(r1) && no_more(r2) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 36 | case SEQ(r1, r2) => if (nullable(r1)) (no_more(r1) && no_more(r2)) else no_more(r1) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 37 | case STAR(_) => false | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 38 | case NOT(r) => !(no_more(r)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 39 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 40 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 41 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 42 | // derivative of a regular expression w.r.t. a character | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 43 | def der (c: Char, r: Rexp) : Rexp = r match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 44 | case NULL => NULL | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 45 | case EMPTY => NULL | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 46 | case ALLC => EMPTY | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 47 | case CHAR(d) => if (c == d) EMPTY else NULL | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 48 | case ALT(r1, r2) => ALT(der(c, r1), der(c, r2)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 49 | case SEQ(r1, r2) => | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 50 | if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 51 | else SEQ(der(c, r1), r2) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 52 | case STAR(r) => SEQ(der(c, r), STAR(r)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 53 | case NOT(r) => NOT(der (c, r)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 54 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 55 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 56 | // regular expression for specifying | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 57 | // ranges of characters | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 58 | def Range(s : List[Char]) : Rexp = s match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 59 | case Nil => NULL | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 60 | case c::Nil => CHAR(c) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 61 | case c::s => ALT(CHAR(c), Range(s)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 62 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 63 | def RANGE(s: String) = Range(s.toList) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 64 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 65 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 66 | // one or more | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 67 | def PLUS(r: Rexp) = SEQ(r, STAR(r)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 68 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 69 | // many alternatives | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 70 | def Alts(rs: List[Rexp]) : Rexp = rs match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 71 | case Nil => NULL | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 72 | case r::Nil => r | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 73 | case r::rs => ALT(r, Alts(rs)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 74 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 75 | def ALTS(rs: Rexp*) = Alts(rs.toList) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 76 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 77 | // repetitions | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 78 | def Seqs(rs: List[Rexp]) : Rexp = rs match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 79 | case Nil => NULL | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 80 | case r::Nil => r | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 81 | case r::rs => SEQ(r, Seqs(rs)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 82 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 83 | def SEQS(rs: Rexp*) = Seqs(rs.toList) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 84 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 85 | // some convenience for typing in regular expressions | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 86 | def charlist2rexp(s : List[Char]) : Rexp = s match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 87 | case Nil => EMPTY | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 88 | case c::Nil => CHAR(c) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 89 | case c::s => SEQ(CHAR(c), charlist2rexp(s)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 90 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 91 | implicit def string2rexp(s : String) : Rexp = charlist2rexp(s.toList) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 92 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 93 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 94 | type Rule[T] = (Rexp, List[Char] => T) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 95 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 96 | case class Tokenizer[T](rules: List[Rule[T]], excl: List[T] = Nil) {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 97 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 98 | def munch(r: Rexp, action: List[Char] => T, s: List[Char], t: List[Char]) : Option[(List[Char], T)] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 99 |     s match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 100 | case Nil if (nullable(r)) => Some(Nil, action(t)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 101 | case Nil => None | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 102 | case c::s if (no_more(der (c, r)) && nullable(r)) => Some(c::s, action(t)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 103 | case c::s if (no_more(der (c, r))) => None | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 104 | case c::s => munch(der (c, r), action, s, t ::: List(c)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 105 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 106 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 107 |   def one_token(s: List[Char]) : Either[(List[Char], T), String] = {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 108 |     val somes = rules.map { (r) => munch(r._1, r._2, s, Nil) }.flatten
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 109 | if (somes == Nil) Right(s.mkString) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 110 | else Left(somes sortBy (_._1.length) head) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 111 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 112 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 113 |   def tokenize(cs: List[Char]) : List[T] = cs match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 114 | case Nil => Nil | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 115 |     case _ => one_token(cs) match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 116 | case Left((rest, token)) => token :: tokenize(rest) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 117 |       case Right(s) => { println("Cannot tokenize: \"" + s + "\""); Nil } 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 118 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 119 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 120 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 121 | def fromString(s: String) : List[T] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 122 | tokenize(s.toList).filterNot(excl.contains(_)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 123 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 124 | def fromFile(name: String) : List[T] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 125 | fromString(io.Source.fromFile(name).mkString) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 126 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 127 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 128 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 129 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 130 | // parser combinators with input type I and return type T | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 131 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 132 | abstract class Parser[I <% Seq[_], T] {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 133 | def parse(ts: I): Set[(T, I)] | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 134 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 135 | def parse_all(ts: I) : Set[T] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 136 | for ((head, tail) <- parse(ts); if (tail.isEmpty)) yield head | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 137 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 138 |   def parse_single(ts: I) : T = parse_all(ts).toList match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 139 | case t::Nil => t | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 140 |     case _ => { println ("Parse Error") ; sys.exit(-1) }
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 141 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 142 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 143 | def || (right : => Parser[I, T]) : Parser[I, T] = new AltParser(this, right) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 144 | def ==>[S] (f: => T => S) : Parser [I, S] = new FunParser(this, f) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 145 | def ~[S] (right : => Parser[I, S]) : Parser[I, (T, S)] = new SeqParser(this, right) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 146 | def ~>[S] (right : => Parser[I, S]) : Parser[I, S] = this ~ right ==> (_._2) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 147 | def <~[S] (right : => Parser[I, S]) : Parser[I, T] = this ~ right ==> (_._1) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 148 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 149 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 150 | class SeqParser[I <% Seq[_], T, S](p: => Parser[I, T], q: => Parser[I, S]) extends Parser[I, (T, S)] {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 151 | def parse(sb: I) = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 152 | for ((head1, tail1) <- p.parse(sb); | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 153 | (head2, tail2) <- q.parse(tail1)) yield ((head1, head2), tail2) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 154 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 155 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 156 | class AltParser[I <% Seq[_], T](p: => Parser[I, T], q: => Parser[I, T]) extends Parser[I, T] {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 157 | def parse(sb: I) = p.parse(sb) ++ q.parse(sb) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 158 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 159 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 160 | class FunParser[I <% Seq[_], T, S](p: => Parser[I, T], f: T => S) extends Parser[I, S] {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 161 | def parse(sb: I) = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 162 | for ((head, tail) <- p.parse(sb)) yield (f(head), tail) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 163 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 164 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 165 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 166 | // A parser and evaluator for teh while language | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 167 | // | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 168 | //:load matcher.scala | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 169 | //:load parser3.scala | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 170 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 171 | // some regular expressions | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 172 | val SYM = RANGE("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz_")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 173 | val DIGIT = RANGE("0123456789")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 174 | val ID = SEQ(SYM, STAR(ALT(SYM, DIGIT))) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 175 | val NUM = PLUS(DIGIT) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 176 | val KEYWORD = ALTS("skip", "while", "do", "if", "then", "else", "true", "false", "write") 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 177 | val SEMI: Rexp = ";" | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 178 | val OP: Rexp = ALTS(":=", "=", "-", "+", "*", "!=", "<", ">")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 179 | val WHITESPACE = PLUS(RANGE(" \n"))
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 180 | val RPAREN: Rexp = ")" | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 181 | val LPAREN: Rexp = "("
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 182 | val BEGIN: Rexp = "{"
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 183 | val END: Rexp = "}" | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 184 | val COMMENT = SEQS("/*", NOT(SEQS(STAR(ALLC), "*/", STAR(ALLC))), "*/")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 185 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 186 | // tokens for classifying the strings that have been recognised | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 187 | abstract class Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 188 | case object T_WHITESPACE extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 189 | case object T_COMMENT extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 190 | case object T_SEMI extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 191 | case object T_LPAREN extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 192 | case object T_RPAREN extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 193 | case object T_BEGIN extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 194 | case object T_END extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 195 | case class T_ID(s: String) extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 196 | case class T_OP(s: String) extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 197 | case class T_NUM(s: String) extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 198 | case class T_KWD(s: String) extends Token | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 199 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 200 | val lexing_rules: List[Rule[Token]] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 201 | List((KEYWORD, (s) => T_KWD(s.mkString)), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 202 | (ID, (s) => T_ID(s.mkString)), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 203 | (OP, (s) => T_OP(s.mkString)), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 204 | (NUM, (s) => T_NUM(s.mkString)), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 205 | (SEMI, (s) => T_SEMI), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 206 | (LPAREN, (s) => T_LPAREN), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 207 | (RPAREN, (s) => T_RPAREN), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 208 | (BEGIN, (s) => T_BEGIN), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 209 | (END, (s) => T_END), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 210 | (WHITESPACE, (s) => T_WHITESPACE), | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 211 | (COMMENT, (s) => T_COMMENT)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 212 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 213 | // the tokenizer | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 214 | val Tok = Tokenizer(lexing_rules, List(T_WHITESPACE, T_COMMENT)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 215 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 216 | // the abstract syntax trees | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 217 | abstract class Stmt | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 218 | abstract class AExp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 219 | abstract class BExp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 220 | type Block = List[Stmt] | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 221 | case object Skip extends Stmt | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 222 | case class If(a: BExp, bl1: Block, bl2: Block) extends Stmt | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 223 | case class While(b: BExp, bl: Block) extends Stmt | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 224 | case class Assign(s: String, a: AExp) extends Stmt | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 225 | case class Write(s: String) extends Stmt | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 226 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 227 | case class Var(s: String) extends AExp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 228 | case class Num(i: Int) extends AExp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 229 | case class Aop(o: String, a1: AExp, a2: AExp) extends AExp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 230 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 231 | case object True extends BExp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 232 | case object False extends BExp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 233 | case class Relop(o: String, a1: AExp, a2: AExp) extends BExp | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 234 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 235 | // atomic parsers | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 236 | case class TokParser(tok: Token) extends Parser[List[Token], Token] {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 237 |   def parse(ts: List[Token]) = ts match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 238 | case t::ts if (t == tok) => Set((t, ts)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 239 | case _ => Set () | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 240 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 241 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 242 | implicit def token2tparser(t: Token) = TokParser(t) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 243 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 244 | case object NumParser extends Parser[List[Token], Int] {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 245 |   def parse(ts: List[Token]) = ts match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 246 | case T_NUM(s)::ts => Set((s.toInt, ts)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 247 | case _ => Set () | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 248 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 249 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 250 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 251 | case object IdParser extends Parser[List[Token], String] {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 252 |   def parse(ts: List[Token]) = ts match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 253 | case T_ID(s)::ts => Set((s, ts)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 254 | case _ => Set () | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 255 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 256 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 257 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 258 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 259 | // arithmetic expressions | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 260 | lazy val AExp: Parser[List[Token], AExp] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 261 |   (T ~ T_OP("+") ~ AExp) ==> { case ((x, y), z) => Aop("+", x, z): AExp } ||
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 262 |   (T ~ T_OP("-") ~ AExp) ==> { case ((x, y), z) => Aop("-", x, z): AExp } || T  
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 263 | lazy val T: Parser[List[Token], AExp] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 264 |   (F ~ T_OP("*") ~ T) ==> { case ((x, y), z) => Aop("*", x, z): AExp } || F
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 265 | lazy val F: Parser[List[Token], AExp] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 266 | (T_LPAREN ~> AExp <~ T_RPAREN) || | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 267 | IdParser ==> Var || | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 268 | NumParser ==> Num | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 269 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 270 | // boolean expressions | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 271 | lazy val BExp: Parser[List[Token], BExp] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 272 |   (T_KWD("true") ==> ((_) => True: BExp)) || 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 273 |   (T_KWD("false") ==> ((_) => False: BExp)) ||
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 274 | (T_LPAREN ~> BExp <~ T_RPAREN) || | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 275 |   (AExp ~ T_OP("=") ~ AExp) ==> { case ((x, y), z) => Relop("=", x, z): BExp } || 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 276 |   (AExp ~ T_OP("!=") ~ AExp) ==> { case ((x, y), z) => Relop("!=", x, z): BExp } || 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 277 |   (AExp ~ T_OP("<") ~ AExp) ==> { case ((x, y), z) => Relop("<", x, z): BExp } || 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 278 |   (AExp ~ T_OP(">") ~ AExp) ==> { case ((x, y), z) => Relop("<", z, x): BExp } 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 279 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 280 | lazy val Stmt: Parser[List[Token], Stmt] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 281 |   (T_KWD("skip") ==> ((_) => Skip: Stmt)) ||
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 282 |   (IdParser ~ T_OP(":=") ~ AExp) ==> { case ((x, y), z) => Assign(x, z): Stmt } ||
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 283 |   (T_KWD("if") ~ BExp ~ T_KWD("then") ~ Block ~ T_KWD("else") ~ Block) ==>
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 284 |     { case (((((x,y),z),u),v),w) => If(y, u, w): Stmt } ||
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 285 |   (T_KWD("while") ~ BExp ~ T_KWD("do") ~ Block) ==> { case (((x, y), z), w) => While(y, w) } || 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 286 |   (T_KWD("write") ~ IdParser) ==> { case (x, y) => Write(y) } 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 287 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 288 | lazy val Stmts: Parser[List[Token], Block] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 289 |   (Stmt ~ T_SEMI ~ Stmts) ==> { case ((x, y), z) => x :: z : Block } ||
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 290 | (Stmt ==> ((s) => List(s) : Block)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 291 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 292 | lazy val Block: Parser[List[Token], Block] = | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 293 | (T_BEGIN ~> Stmts <~ T_END) || | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 294 | (Stmt ==> ((s) => List(s))) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 295 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 296 | // compiler | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 297 | val beginning = """ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 298 | .class public XXX.XXX | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 299 | .super java/lang/Object | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 300 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 301 | .method public <init>()V | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 302 | aload_0 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 303 | invokenonvirtual java/lang/Object/<init>()V | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 304 | return | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 305 | .end method | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 306 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 307 | .method public static write(I)V | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 308 | .limit locals 5 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 309 | .limit stack 5 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 310 | iload 0 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 311 | getstatic java/lang/System/out Ljava/io/PrintStream; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 312 | swap | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 313 | invokevirtual java/io/PrintStream/println(I)V | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 314 | return | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 315 | .end method | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 316 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 317 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 318 | .method public static main([Ljava/lang/String;)V | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 319 | .limit locals 200 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 320 | .limit stack 200 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 321 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 322 | """ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 323 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 324 | val ending = """ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 325 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 326 | return | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 327 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 328 | .end method | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 329 | """ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 330 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 331 | // for generating new labels | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 332 | var counter = -1 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 333 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 334 | def Fresh(x: String) = {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 335 | counter += 1 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 336 | x ++ "_" ++ counter.toString() | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 337 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 338 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 339 | type Env = Map[String, String] | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 340 | type Instrs = List[String] | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 341 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 342 | def compile_aexp(a: AExp, env : Env) : Instrs = a match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 343 |   case Num(i) => List("ldc " + i.toString + "\n")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 344 |   case Var(s) => List("iload " + env(s) + "\n")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 345 |   case Aop("+", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("iadd\n")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 346 |   case Aop("-", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("isub\n")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 347 |   case Aop("*", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("imul\n")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 348 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 349 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 350 | def compile_bexp(b: BExp, env : Env, jmp: String) : Instrs = b match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 351 | case True => Nil | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 352 |   case False => List("goto " + jmp + "\n")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 353 |   case Relop("=", a1, a2) => 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 354 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("if_icmpne " + jmp + "\n")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 355 |   case Relop("!=", a1, a2) => 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 356 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("if_icmpeq " + jmp + "\n")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 357 |   case Relop("<", a1, a2) => 
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 358 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("if_icmpge " + jmp + "\n")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 359 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 360 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 361 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 362 | def compile_stmt(s: Stmt, env: Env) : (Instrs, Env) = s match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 363 | case Skip => (Nil, env) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 364 |   case Assign(x, a) => {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 365 | val index = if (env.isDefinedAt(x)) env(x) else env.keys.size.toString | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 366 | (compile_aexp(a, env) ++ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 367 |      List("istore " + index + "\n"), env + (x -> index))
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 368 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 369 |   case If(b, bl1, bl2) => {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 370 |     val if_else = Fresh("If_else")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 371 |     val if_end = Fresh("If_end")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 372 | val (instrs1, env1) = compile_bl(bl1, env) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 373 | val (instrs2, env2) = compile_bl(bl2, env1) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 374 | (compile_bexp(b, env, if_else) ++ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 375 | instrs1 ++ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 376 |      List("goto " + if_end + "\n") ++
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 377 |      List("\n" + if_else + ":\n\n") ++
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 378 | instrs2 ++ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 379 |      List("\n" + if_end + ":\n\n"), env2)
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 380 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 381 |   case While(b, bl) => {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 382 |     val loop_begin = Fresh("Loop_begin")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 383 |     val loop_end = Fresh("Loop_end")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 384 | val (instrs1, env1) = compile_bl(bl, env) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 385 |     (List("\n" + loop_begin + ":\n\n") ++
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 386 | compile_bexp(b, env, loop_end) ++ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 387 | instrs1 ++ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 388 |      List("goto " + loop_begin + "\n") ++
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 389 |      List("\n" + loop_end + ":\n\n"), env1)
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 390 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 391 | case Write(x) => | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 392 |     (List("iload " + env(x) + "\n" + "invokestatic XXX/XXX/write(I)V\n"), env)
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 393 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 394 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 395 | def compile_bl(bl: Block, env: Env) : (Instrs, Env) = bl match {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 396 | case Nil => (Nil, env) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 397 |   case s::bl => {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 398 | val (instrs1, env1) = compile_stmt(s, env) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 399 | val (instrs2, env2) = compile_bl(bl, env1) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 400 | (instrs1 ++ instrs2, env2) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 401 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 402 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 403 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 404 | def compile(input: String) : String = {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 405 |   val class_name = input.split('.')(0)
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 406 | val tks = Tok.fromFile(input) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 407 | val ast = Stmts.parse_single(tks) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 408 | val instructions = compile_bl(ast, Map.empty)._1 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 409 |   (beginning ++ instructions.mkString ++ ending).replaceAllLiterally("XXX", class_name)
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 410 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 411 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 412 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 413 | def compile_to(input: String, output: String) = {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 414 | val fw = new java.io.FileWriter(output) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 415 | fw.write(compile(input)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 416 | fw.close() | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 417 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 418 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 419 | // | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 420 | val tks = Tok.fromString("x := x + 1")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 421 | val ast = Stmt.parse_single(tks) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 422 | println(compile_stmt(ast, Map("x" -> "n"))._1.mkString)
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 423 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 424 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 425 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 426 | //examples | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 427 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 428 | compile_to("loops.while", "loops.j")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 429 | //compile_to("fib.while", "fib.j")
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 430 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 431 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 432 | // testing cases for time measurements | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 433 | /* | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 434 | def time_needed[T](i: Int, code: => T) = {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 435 | val start = System.nanoTime() | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 436 | for (j <- 1 to i) code | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 437 | val end = System.nanoTime() | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 438 | (end - start)/(i * 1.0e9) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 439 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 440 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 441 | // for testing | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 442 | import scala.sys.process._ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 443 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 444 | val test_prog = """ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 445 | start := XXX; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 446 | x := start; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 447 | y := start; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 448 | z := start; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 449 | while 0 < x do {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 450 |  while 0 < y do {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 451 |   while 0 < z do {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 452 | z := z - 1 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 453 | }; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 454 | z := start; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 455 | y := y - 1 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 456 | }; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 457 | y := start; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 458 | x := x - 1 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 459 | }; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 460 | write x; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 461 | write y; | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 462 | write z | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 463 | """ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 464 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 465 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 466 | def compile_test(n: Int) : Unit = {
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 467 | val class_name = "LOOP" | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 468 |   val tks = Tok.fromString(test_prog.replaceAllLiterally("XXX", n.toString))
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 469 | val ast = Stmts.parse_single(tks) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 470 | val instructions = compile_bl(ast, Map.empty)._1 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 471 |   val assembly = (beginning ++ instructions.mkString ++ ending).replaceAllLiterally("XXX", class_name)
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 472 | val fw = new java.io.FileWriter(class_name + ".j") | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 473 | fw.write(assembly) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 474 | fw.close() | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 475 |   val test = ("java -jar jvm/jasmin-2.4/jasmin.jar " + class_name + ".j").!!
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 476 |   println(n + " " + time_needed(2, ("java " + class_name + "/" + class_name).!!))
 | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 477 | } | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 478 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 479 | List(1, 5000, 10000, 50000, 100000, 250000, 500000, 750000, 1000000).map(compile_test(_)) | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 480 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 481 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 482 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 483 | // javabyte code assmbler | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 484 | // | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 485 | // java -jar jvm/jasmin-2.4/jasmin.jar loops.j | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 486 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 487 | */ | 
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 488 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 489 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 490 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 491 | |
| 
e85600529ca5
moved scala files
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 492 |