| author | Christian Urban <christian.urban@kcl.ac.uk> | 
| Mon, 22 Nov 2021 11:35:38 +0000 | |
| changeset 851 | 2918388fe4ab | 
| parent 704 | 27959a711959 | 
| child 906 | e7e7fe274f5c | 
| permissions | -rw-r--r-- | 
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 1 | import scala.language.implicitConversions | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 2 | import scala.language.reflectiveCalls | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 3 | import scala.util._ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 4 | import scala.annotation.tailrec | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 5 | import scala.sys.process._ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 6 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 7 | abstract class Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 8 | case object NULL extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 9 | case object EMPTY extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 10 | case class CHAR(c: Char) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 11 | case class ALT(r1: Rexp, r2: Rexp) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 12 | case class RANGE(cs: List[Char]) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 13 | case class SEQ(r1: Rexp, r2: Rexp) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 14 | case class PLUS(r: Rexp) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 15 | case class STAR(r: Rexp) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 16 | case class NTIMES(r: Rexp, n: Int) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 17 | case class NUPTOM(r: Rexp, n: Int, m: Int) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 18 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 19 | object RANGE {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 20 | def apply(s: String) : RANGE = RANGE(s.toList) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 21 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 22 | def NMTIMES(r: Rexp, n: Int, m: Int) = {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 23 |   if(m < n) throw new IllegalArgumentException("the number m cannot be smaller than n.")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 24 | else NUPTOM(r, n, m - n) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 25 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 26 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 27 | case class NOT(r: Rexp) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 28 | case class OPT(r: Rexp) extends Rexp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 29 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 30 | // some convenience for typing in regular expressions | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 31 | def charlist2rexp(s : List[Char]) : Rexp = s match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 32 | case Nil => EMPTY | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 33 | case c::Nil => CHAR(c) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 34 | case c::s => SEQ(CHAR(c), charlist2rexp(s)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 35 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 36 | implicit def string2rexp(s : String) : Rexp = charlist2rexp(s.toList) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 37 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 38 | implicit def RexpOps (r: Rexp) = new {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 39 | def | (s: Rexp) = ALT(r, s) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 40 | def % = STAR(r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 41 | def ~ (s: Rexp) = SEQ(r, s) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 42 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 43 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 44 | implicit def stringOps (s: String) = new {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 45 | def | (r: Rexp) = ALT(s, r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 46 | def | (r: String) = ALT(s, r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 47 | def % = STAR(s) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 48 | def ~ (r: Rexp) = SEQ(s, r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 49 | def ~ (r: String) = SEQ(s, r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 50 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 51 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 52 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 53 | // nullable function: tests whether the regular | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 54 | // expression can recognise the empty string | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 55 | def nullable (r: Rexp) : Boolean = r match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 56 | case NULL => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 57 | case EMPTY => true | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 58 | case CHAR(_) => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 59 | case ALT(r1, r2) => nullable(r1) || nullable(r2) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 60 | case SEQ(r1, r2) => nullable(r1) && nullable(r2) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 61 | case STAR(_) => true | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 62 | case PLUS(r) => nullable(r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 63 | case NTIMES(r, i) => if (i == 0) true else nullable(r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 64 | case NUPTOM(r, i, j) => if (i == 0) true else nullable(r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 65 | case RANGE(_) => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 66 | case NOT(r) => !(nullable(r)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 67 | case OPT(_) => true | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 68 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 69 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 70 | // derivative of a regular expression w.r.t. a character | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 71 | def der (c: Char, r: Rexp) : Rexp = r match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 72 | case NULL => NULL | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 73 | case EMPTY => NULL | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 74 | case CHAR(d) => if (c == d) EMPTY else NULL | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 75 | case ALT(r1, r2) => ALT(der(c, r1), der(c, r2)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 76 | case SEQ(r1, r2) => | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 77 | if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 78 | else SEQ(der(c, r1), r2) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 79 | case STAR(r) => SEQ(der(c, r), STAR(r)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 80 | case PLUS(r) => SEQ(der(c, r), STAR(r)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 81 | case NTIMES(r, i) => | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 82 | if (i == 0) NULL else der(c, SEQ(r, NTIMES(r, i - 1))) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 83 | case NUPTOM(r, i, j) => | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 84 | if (i == 0 && j == 0) NULL else | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 85 | if (i == 0) ALT(der(c, NTIMES(r, j)), der(c, NUPTOM(r, 0, j - 1))) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 86 | else der(c, SEQ(r, NUPTOM(r, i - 1, j))) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 87 | case RANGE(cs) => if (cs contains c) EMPTY else NULL | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 88 | case NOT(r) => NOT(der (c, r)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 89 | case OPT(r) => der(c, r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 90 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 91 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 92 | def zeroable (r: Rexp) : Boolean = r match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 93 | case NULL => true | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 94 | case EMPTY => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 95 | case CHAR(_) => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 96 | case ALT(r1, r2) => zeroable(r1) && zeroable(r2) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 97 | case SEQ(r1, r2) => zeroable(r1) || zeroable(r2) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 98 | case STAR(_) => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 99 | case PLUS(r) => zeroable(r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 100 | case NTIMES(r, i) => if (i == 0) false else zeroable(r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 101 | case NUPTOM(r, i, j) => if (i == 0) false else zeroable(r) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 102 | case RANGE(_) => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 103 | case NOT(r) => !(zeroable(r)) // bug: incorrect definition for NOT | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 104 | case OPT(_) => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 105 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 106 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 107 | // derivative w.r.t. a string (iterates der) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 108 | def ders (s: List[Char], r: Rexp) : Rexp = s match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 109 | case Nil => r | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 110 | case c::s => ders(s, der(c, r)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 111 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 112 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 113 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 114 | // regular expressions for the While language | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
227diff
changeset | 115 | val SYM = RANGE("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_".toList)
 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
227diff
changeset | 116 | val DIGIT = RANGE("0123456789".toList)
 | 
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 117 | val ID = SYM ~ (SYM | DIGIT).% | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 118 | val NUM = PLUS(DIGIT) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 119 | val KEYWORD : Rexp = "skip" | "while" | "do" | "if" | "then" | "else" | "read" | "write" | "true" | "false" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 120 | val SEMI: Rexp = ";" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 121 | val OP: Rexp = ":=" | "==" | "-" | "+" | "*" | "!=" | "<" | ">" | "%" | "/" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 122 | val WHITESPACE = PLUS(" " | "\n" | "\t")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 123 | val RPAREN: Rexp = ")" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 124 | val LPAREN: Rexp = "("
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 125 | val BEGIN: Rexp = "{"
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 126 | val END: Rexp = "}" | 
| 227 
93bd75031ced
added handout
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
219diff
changeset | 127 | val ALL = SYM | DIGIT | OP | " " | ":" | ";" | "\"" | "(" | ")" | "{" | "}" 
 | 
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 128 | val ALL2 = ALL | "\n" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 129 | val COMMENT2 = ("/*" ~ NOT(ALL.% ~ "*/" ~ ALL.%) ~ "*/")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 130 | val COMMENT = ("/*" ~ ALL2.% ~ "*/") | ("//" ~ ALL.% ~ "\n")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 131 | val STRING = "\"" ~ ALL.% ~ "\"" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 132 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 133 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
227diff
changeset | 134 | // token for While language | 
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 135 | abstract class Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 136 | case object T_WHITESPACE extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 137 | case object T_SEMI extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 138 | case object T_LPAREN extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 139 | case object T_RPAREN extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 140 | case object T_BEGIN extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 141 | case object T_END extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 142 | case object T_COMMENT extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 143 | case class T_ID(s: String) extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 144 | case class T_OP(s: String) extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 145 | case class T_NUM(s: String) extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 146 | case class T_KWD(s: String) extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 147 | case class T_STRING(s: String) extends Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 148 | case class T_ERR(s: String) extends Token // special error token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 149 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 150 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 151 | type TokenFun = String => Token | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 152 | type LexRules = List[(Rexp, TokenFun)] | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 153 | val While_lexing_rules: LexRules = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 154 | List((KEYWORD, (s) => T_KWD(s)), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 155 | (ID, (s) => T_ID(s)), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 156 | (COMMENT, (s) => T_COMMENT), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 157 | (OP, (s) => T_OP(s)), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 158 | (NUM, (s) => T_NUM(s)), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 159 | (SEMI, (s) => T_SEMI), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 160 | (LPAREN, (s) => T_LPAREN), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 161 | (RPAREN, (s) => T_RPAREN), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 162 | (BEGIN, (s) => T_BEGIN), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 163 | (END, (s) => T_END), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 164 | (STRING, (s) => T_STRING(s.drop(1).dropRight(1))), | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 165 | (WHITESPACE, (s) => T_WHITESPACE)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 166 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 167 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 168 | // calculates derivatives until all of them are zeroable | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 169 | @tailrec | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 170 | def munch(s: List[Char], | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 171 | pos: Int, | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 172 | rs: LexRules, | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 173 |           last: Option[(Int, TokenFun)]): Option[(Int, TokenFun)] = {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 174 |   rs match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 175 | case Nil => last | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 176 | case rs if (s.length <= pos) => last | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 177 |   case rs => {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 178 |     val ders = rs.map({case (r, tf) => (der(s(pos), r), tf)})
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 179 |     val rs_nzero = ders.filterNot({case (r, _) => zeroable(r)})
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 180 |     val rs_nulls = ders.filter({case (r, _) => nullable(r)})
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 181 | val new_last = if (rs_nulls != Nil) Some((pos, rs_nulls.head._2)) else last | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 182 | munch(s, 1 + pos, rs_nzero, new_last) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 183 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 184 | }} | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 185 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 186 | // iterates the munching function and returns a Token list | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 187 | def tokenize(s: String, rs: LexRules) : List[Token] = munch(s.toList, 0, rs, None) match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 188 | case None if (s == "") => Nil | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 189 | case None => List(T_ERR(s"Lexing error: $s")) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 190 |   case Some((n, tf)) => {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 191 | val (head, tail) = s.splitAt(n + 1) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 192 | tf(head)::tokenize(tail, rs) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 193 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 194 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 195 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 196 | def tokenizer(s:String) : List[Token] = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 197 |   tokenize(s, While_lexing_rules).filter {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 198 |     case T_ERR(s) => { println(s); sys.exit(-1) }
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 199 | case T_WHITESPACE => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 200 | case T_COMMENT => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 201 | case _ => true | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 202 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 203 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 204 | def fromFile(name: String) : String = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 205 | io.Source.fromFile(name).mkString | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 206 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 207 | // tokenizer tests | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 208 | //println(tokenizer(fromFile("loops.while")).mkString("\n"))
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 209 | //println(tokenizer(fromFile("fib.while")).mkString("\n"))
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 210 | //println(tokenizer(fromFile("collatz.while")).mkString("\n"))
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 211 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 212 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 213 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 214 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 215 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 216 | // Parser - Abstract syntax trees | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 217 | abstract class Stmt | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 218 | abstract class AExp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 219 | abstract class BExp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 220 | type Block = List[Stmt] | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 221 | case object Skip extends Stmt | 
| 
1459e6e29621
added comp
 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 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 223 | case class While(b: BExp, bl: Block) extends Stmt | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 224 | case class Assign(s: String, a: AExp) extends Stmt | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 225 | case class Read(s: String) extends Stmt | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 226 | case class Write(s: String) extends Stmt | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 227 | case class WriteS(s: String) extends Stmt | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 228 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 229 | case class Var(s: String) extends AExp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 230 | case class Num(i: Int) extends AExp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 231 | case class Aop(o: String, a1: AExp, a2: AExp) extends AExp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 232 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 233 | case object True extends BExp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 234 | case object False extends BExp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 235 | case class Bop(o: String, a1: AExp, a2: AExp) extends BExp | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 236 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 237 | // Parser combinators | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 238 | abstract class Parser[I <% Seq[_], T] {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 239 | def parse(ts: I): Set[(T, I)] | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 240 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 241 | def parse_all(ts: I) : Set[T] = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 242 | for ((head, tail) <- parse(ts); if (tail.isEmpty)) yield head | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 243 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 244 |   def parse_single(ts: I) : T = parse_all(ts).toList match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 245 | case List(t) => t | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 246 |     case _ => { println ("Parse Error") ; sys.exit(-1) }
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 247 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 248 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 249 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 250 | class SeqParser[I <% Seq[_], T, S](p: => Parser[I, T], q: => Parser[I, S]) extends Parser[I, (T, S)] {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 251 | def parse(sb: I) = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 252 | for ((head1, tail1) <- p.parse(sb); | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 253 | (head2, tail2) <- q.parse(tail1)) yield ((head1, head2), tail2) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 254 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 255 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 256 | class AltParser[I <% Seq[_], T](p: => Parser[I, T], q: => Parser[I, T]) extends Parser[I, T] {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 257 | def parse(sb: I) = p.parse(sb) ++ q.parse(sb) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 258 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 259 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 260 | class FunParser[I <% Seq[_], T, S](p: => Parser[I, T], f: T => S) extends Parser[I, S] {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 261 | def parse(sb: I) = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 262 | for ((head, tail) <- p.parse(sb)) yield (f(head), tail) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 263 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 264 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 265 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 266 | case class TokParser(tok: Token) extends Parser[List[Token], Token] {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 267 |   def parse(ts: List[Token]) = ts match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 268 | case t::ts if (t == tok) => Set((t, ts)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 269 | case _ => Set () | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 270 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 271 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 272 | implicit def token2tparser(t: Token) = TokParser(t) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 273 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 274 | case object NumParser extends Parser[List[Token], Int] {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 275 |   def parse(ts: List[Token]) = ts match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 276 | case T_NUM(s)::ts => Set((s.toInt, ts)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 277 | case _ => Set () | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 278 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 279 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 280 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 281 | case object IdParser extends Parser[List[Token], String] {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 282 |   def parse(ts: List[Token]) = ts match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 283 | case T_ID(s)::ts => Set((s, ts)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 284 | case _ => Set () | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 285 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 286 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 287 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 288 | case object StringParser extends Parser[List[Token], String] {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 289 |   def parse(ts: List[Token]) = ts match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 290 | case T_STRING(s)::ts => Set((s, ts)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 291 | case _ => Set () | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 292 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 293 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 294 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 295 | implicit def ParserOps[I<% Seq[_], T](p: Parser[I, T]) = new {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 296 | def || (q : => Parser[I, T]) = new AltParser[I, T](p, q) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 297 | def ==>[S] (f: => T => S) = new FunParser[I, T, S](p, f) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 298 | def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 299 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 300 | implicit def TokOps(t: Token) = new {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 301 | def || (q : => Parser[List[Token], Token]) = new AltParser[List[Token], Token](t, q) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 302 | def ==>[S] (f: => Token => S) = new FunParser[List[Token], Token, S](t, f) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 303 | def ~[S](q : => Parser[List[Token], S]) = new SeqParser[List[Token], Token, S](t, q) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 304 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 305 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 306 | // arithmetic expressions | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 307 | lazy val AExp: Parser[List[Token], AExp] = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 308 |   (T ~ T_OP("+") ~ AExp) ==> { case ((x, y), z) => Aop("+", x, z): AExp } ||
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 309 |   (T ~ T_OP("-") ~ AExp) ==> { case ((x, y), z) => Aop("-", x, z): AExp } || T  
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 310 | lazy val T: Parser[List[Token], AExp] = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 311 |   (F ~ T_OP("*") ~ T) ==> { case ((x, y), z) => Aop("*", x, z): AExp } || 
 | 
| 219 
599e6a6ab6c6
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
212diff
changeset | 312 |   (F ~ T_OP("/") ~ T) ==> { case ((x, y), z) => Aop("/", x, z): AExp } || 
 | 
| 
599e6a6ab6c6
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
212diff
changeset | 313 |   (F ~ T_OP("%") ~ T) ==> { case ((x, y), z) => Aop("%", x, z): AExp } || F
 | 
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 314 | lazy val F: Parser[List[Token], AExp] = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 315 |   (T_LPAREN ~ AExp ~ T_RPAREN) ==> { case ((x, y), z) => y: AExp }|| 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 316 |   IdParser ==> { case x => Var(x): AExp } || 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 317 |   NumParser ==> { case x => Num(x): AExp }
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 318 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 319 | // boolean expressions | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 320 | lazy val BExp: Parser[List[Token], BExp] = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 321 |   (AExp ~ T_OP("==") ~ AExp) ==> { case ((x, y), z) => Bop("==", x, z): BExp } || 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 322 |   (AExp ~ T_OP("!=") ~ AExp) ==> { case ((x, y), z) => Bop("!=", x, z): BExp } || 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 323 |   (AExp ~ T_OP("<") ~ AExp) ==> { case ((x, y), z) => Bop("<", x, z): BExp } || 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 324 |   (AExp ~ T_OP(">") ~ AExp) ==> { case ((x, y), z) => Bop("<", z, x): BExp } || 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 325 |   (T_KWD("true") ==> ((_) => True)) || 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 326 |   (T_KWD("false") ==> ((_) => False: BExp))
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 327 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 328 | lazy val Stmt: Parser[List[Token], Stmt] = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 329 |   (T_KWD("skip") ==> ((_) => Skip: Stmt)) ||
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 330 |   (IdParser ~ T_OP(":=") ~ AExp) ==> { case ((x, y), z) => Assign(x, z): Stmt } ||
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 331 |   (T_KWD("if") ~ BExp ~ T_KWD("then") ~ Block ~ T_KWD("else") ~ Block) ==>
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 332 |     { case (((((x,y),z),u),v),w) => If(y, u, w): Stmt } ||
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 333 |   (T_KWD("while") ~ BExp ~ T_KWD("do") ~ Block) ==> { case (((x, y), z), w) => While(y, w) } ||
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 334 |   (T_KWD("read") ~ IdParser) ==> { case (x, y) => Read(y) } ||
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 335 |   (T_KWD("write") ~ IdParser) ==> { case (x, y) => Write(y) } ||
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 336 |   (T_KWD("write") ~ StringParser) ==> { case (x, y) => WriteS(y) }
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 337 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 338 | lazy val Stmts: Parser[List[Token], Block] = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 339 |   (Stmt ~ T_SEMI ~ Stmts) ==> { case ((x, y), z) => x :: z : Block } ||
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 340 | (Stmt ==> ((s) => List(s) : Block)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 341 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 342 | lazy val Block: Parser[List[Token], Block] = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 343 |   (T_BEGIN ~ Stmts ~ T_END) ==> { case ((x, y), z) => y : Block } || 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 344 | (Stmt ==> ((s) => List(s))) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 345 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 346 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 347 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 348 | // parser examples | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 349 | val p1 = "x := 5" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 350 | val p1_toks = tokenizer(p1) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 351 | val p1_ast = Block.parse_all(p1_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 352 | //println(p1_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 353 | //println(p1_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 354 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 355 | val p2 = "{ x := 5; y := 8}"
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 356 | val p2_toks = tokenizer(p2) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 357 | val p2_ast = Block.parse_all(p2_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 358 | //println(p2_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 359 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 360 | val p3 = "5 == 6" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 361 | val p3_toks = tokenizer(p3) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 362 | val p3_ast = BExp.parse_all(p3_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 363 | //println(p3_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 364 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 365 | val p4 = "true" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 366 | val p4_toks = tokenizer(p4) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 367 | val p4_ast = BExp.parse_all(p4_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 368 | //println(p4_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 369 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 370 | val p5 = "if true then skip else skip" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 371 | val p5_toks = tokenizer(p5) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 372 | val p5_ast = Stmt.parse_all(p5_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 373 | //println(p5_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 374 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 375 | val p6 = "if true then x := 5 else x := 10" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 376 | val p6_toks = tokenizer(p6) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 377 | val p6_ast = Stmt.parse_all(p6_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 378 | //println(p6_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 379 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 380 | val p7 = "if false then x := 5 else x := 10" | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 381 | val p7_toks = tokenizer(p7) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 382 | val p7_ast = Stmt.parse_all(p7_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 383 | //println(p7_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 384 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 385 | val p8 = "write x; write \"foo\"; read x " | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 386 | val p8_toks = tokenizer(p8) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 387 | val p8_ast = Stmts.parse_all(p8_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 388 | //println(p8_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 389 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 390 | // multiplication | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 391 | val p9 = """ x := 5; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 392 | y := 4; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 393 | r := 0; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 394 |               while y > 0 do {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 395 | r := r + x; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 396 | y := y - 1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 397 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 398 | """ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 399 | val p9_toks = tokenizer(p9) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 400 | val p9_ast = Stmts.parse_all(p9_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 401 | //println(p9_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 402 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 403 | // fibonacci numbers | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 404 | val p10 = """ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 405 | write "Fib: "; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 406 | read n; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 407 | minus1 := 0; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 408 | minus2 := 1; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 409 | temp := 0; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 410 |  while n > 0 do  {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 411 | temp := minus2; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 412 | minus2 := minus1 + minus2; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 413 | minus1 := temp; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 414 | n := n - 1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 415 | }; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 416 | write "Result:"; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 417 | write minus2 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 418 | """ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 419 | val p10_toks = tokenizer(p10) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 420 | val p10_ast = Stmts.parse_all(p10_toks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 421 | //println(p10_ast) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 422 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 423 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 424 | // an interpreter for the WHILE language | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 425 | type Env = Map[String, Int] | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 426 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 427 | def eval_aexp(a: AExp, env : Env) : Int = a match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 428 | case Num(i) => i | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 429 | case Var(s) => env(s) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 430 |   case Aop("+", a1, a2) => eval_aexp(a1, env) + eval_aexp(a2, env)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 431 |   case Aop("-", a1, a2) => eval_aexp(a1, env) - eval_aexp(a2, env)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 432 |   case Aop("*", a1, a2) => eval_aexp(a1, env) * eval_aexp(a2, env)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 433 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 434 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 435 | def eval_bexp(b: BExp, env: Env) : Boolean = b match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 436 | case True => true | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 437 | case False => false | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 438 |   case Bop("==", a1, a2) => eval_aexp(a1, env) == eval_aexp(a2, env)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 439 |   case Bop("!=", a1, a2) => !(eval_aexp(a1, env) == eval_aexp(a2, env))
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 440 |   case Bop("<", a1, a2) => eval_aexp(a1, env) < eval_aexp(a2, env)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 441 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 442 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 443 | def eval_stmt(s: Stmt, env: Env) : Env = s match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 444 | case Skip => env | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 445 | case Assign(x, a) => env + (x -> eval_aexp(a, env)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 446 | case If(b, bl1, bl2) => if (eval_bexp(b, env)) eval_bl(bl1, env) else eval_bl(bl2, env) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 447 | case While(b, bl) => | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 448 | if (eval_bexp(b, env)) eval_stmt(While(b, bl), eval_bl(bl, env)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 449 | else env | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 450 |   case WriteS(s: String) => { println(s); env }
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 451 |   case Write(s: String) => { println(env(s)); env }
 | 
| 704 | 452 |   //case Read(s: String) => tokenizer(Console.readLine) match {
 | 
| 453 | // case List(T_NUM(n)) => env + (s -> n.toInt) | |
| 454 |   //  case _ => { println("not a number"); eval_stmt(Read(s: String), env) }
 | |
| 455 | //} | |
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 456 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 457 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 458 | def eval_bl(bl: Block, env: Env) : Env = bl match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 459 | case Nil => env | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 460 | case s::bl => eval_bl(bl, eval_stmt(s, env)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 461 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 462 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 463 | def eval(bl: Block) : Env = eval_bl(bl, Map()) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 464 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 465 | def interpret(s: String): Unit = | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 466 | eval(Stmts.parse_all(tokenizer(s)).head) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 467 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 468 | // interpreter example | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 469 | //interpret(p10) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 470 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 471 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 472 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 473 | // compiler - built-in functions | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 474 | // copied from http://www.ceng.metu.edu.tr/courses/ceng444/link/jvm-cpm.html | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 475 | // | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 476 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 477 | val beginning = """ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 478 | .class public XXX.XXX | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 479 | .super java/lang/Object | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 480 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 481 | .method public <init>()V | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 482 | aload_0 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 483 | invokenonvirtual java/lang/Object/<init>()V | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 484 | return | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 485 | .end method | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 486 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 487 | .method public static write(I)V | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 488 | .limit locals 5 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 489 | .limit stack 5 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 490 | iload 0 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 491 | getstatic java/lang/System/out Ljava/io/PrintStream; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 492 | swap | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 493 | invokevirtual java/io/PrintStream/println(I)V | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 494 | return | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 495 | .end method | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 496 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 497 | .method public static writes(Ljava/lang/String;)V | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 498 | .limit stack 2 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 499 | .limit locals 2 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 500 | getstatic java/lang/System/out Ljava/io/PrintStream; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 501 | aload 0 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 502 | invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 503 | return | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 504 | .end method | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 505 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 506 | .method public static read()I | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 507 | .limit locals 10 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 508 | .limit stack 10 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 509 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 510 | ldc 0 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 511 | istore 1 ; this will hold our final integer | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 512 | Label1: | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 513 | getstatic java/lang/System/in Ljava/io/InputStream; | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 514 | invokevirtual java/io/InputStream/read()I | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 515 | istore 2 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 516 | iload 2 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 517 | ldc 10 ; the newline delimiter | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 518 | isub | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 519 | ifeq Label2 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 520 | iload 2 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 521 | ldc 32 ; the space delimiter | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 522 | isub | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 523 | ifeq Label2 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 524 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 525 | iload 2 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 526 | ldc 48 ; we have our digit in ASCII, have to subtract it from 48 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 527 | isub | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 528 | ldc 10 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 529 | iload 1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 530 | imul | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 531 | iadd | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 532 | istore 1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 533 | goto Label1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 534 | Label2: | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 535 | ;when we come here we have our integer computed in Local Variable 1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 536 | iload 1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 537 | ireturn | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 538 | .end method | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 539 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 540 | .method public static main([Ljava/lang/String;)V | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 541 | .limit locals 200 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 542 | .limit stack 200 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 543 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 544 | """ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 545 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 546 | val ending = """ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 547 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 548 | return | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 549 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 550 | .end method | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 551 | """ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 552 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 553 | // for generating new labels | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 554 | var counter = -1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 555 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 556 | def Fresh(x: String) = {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 557 | counter += 1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 558 | x ++ "_" ++ counter.toString() | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 559 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 560 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 561 | type Mem = Map[String, String] | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 562 | type Instrs = List[String] | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 563 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 564 | def compile_aexp(a: AExp, env : Mem) : Instrs = a match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 565 |   case Num(i) => List("ldc " + i.toString + "\n")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 566 |   case Var(s) => List("iload " + env(s) + "\n")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 567 |   case Aop("+", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("iadd\n")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 568 |   case Aop("-", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("isub\n")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 569 |   case Aop("*", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("imul\n")
 | 
| 227 
93bd75031ced
added handout
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
219diff
changeset | 570 |   case Aop("/", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("idiv\n")
 | 
| 
93bd75031ced
added handout
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
219diff
changeset | 571 |   case Aop("%", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("irem\n") 
 | 
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 572 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 573 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 574 | def compile_bexp(b: BExp, env : Mem, jmp: String) : Instrs = b match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 575 | case True => Nil | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 576 |   case False => List("goto " + jmp + "\n")
 | 
| 227 
93bd75031ced
added handout
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
219diff
changeset | 577 |   case Bop("==", a1, a2) => 
 | 
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 578 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("if_icmpne " + jmp + "\n")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 579 |   case Bop("!=", a1, a2) => 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 580 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("if_icmpeq " + jmp + "\n")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 581 |   case Bop("<", a1, a2) => 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 582 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("if_icmpge " + jmp + "\n")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 583 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 584 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 585 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 586 | def compile_stmt(s: Stmt, env: Mem) : (Instrs, Mem) = s match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 587 | case Skip => (Nil, env) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 588 |   case Assign(x, a) => {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 589 | val index = if (env.isDefinedAt(x)) env(x) else env.keys.size.toString | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 590 | (compile_aexp(a, env) ++ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 591 |      List("istore " + index + "\n"), env + (x -> index))
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 592 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 593 |   case If(b, bl1, bl2) => {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 594 |     val if_else = Fresh("If_else")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 595 |     val if_end = Fresh("If_end")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 596 | val (instrs1, env1) = compile_bl(bl1, env) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 597 | val (instrs2, env2) = compile_bl(bl2, env1) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 598 | (compile_bexp(b, env, if_else) ++ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 599 | instrs1 ++ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 600 |      List("goto " + if_end + "\n") ++
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 601 |      List("\n" + if_else + ":\n\n") ++
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 602 | instrs2 ++ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 603 |      List("\n" + if_end + ":\n\n"), env2)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 604 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 605 |   case While(b, bl) => {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 606 |     val loop_begin = Fresh("Loop_begin")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 607 |     val loop_end = Fresh("Loop_end")
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 608 | val (instrs1, env1) = compile_bl(bl, env) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 609 |     (List("\n" + loop_begin + ":\n\n") ++
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 610 | compile_bexp(b, env, loop_end) ++ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 611 | instrs1 ++ | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 612 |      List("goto " + loop_begin + "\n") ++
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 613 |      List("\n" + loop_end + ":\n\n"), env1)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 614 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 615 | case Write(x) => | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 616 |     (List("iload " + env(x) + "\n" + 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 617 | "invokestatic XXX/XXX/write(I)V\n"), env) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 618 | case WriteS(x) => | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 619 |     (List("ldc \"" + x + "\"\n" + 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 620 | "invokestatic XXX/XXX/writes(Ljava/lang/String;)V\n"), env) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 621 |   case Read(x) => {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 622 | val index = if (env.isDefinedAt(x)) env(x) else env.keys.size.toString | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 623 |     (List("invokestatic XXX/XXX/read()I\n" + 
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 624 | "istore " + index + "\n"), env + (x -> index)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 625 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 626 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 627 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 628 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 629 | def compile_bl(bl: Block, env: Mem) : (Instrs, Mem) = bl match {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 630 | case Nil => (Nil, env) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 631 |   case s::bl => {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 632 | val (instrs1, env1) = compile_stmt(s, env) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 633 | val (instrs2, env2) = compile_bl(bl, env1) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 634 | (instrs1 ++ instrs2, env2) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 635 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 636 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 637 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 638 | def compile(class_name: String, input: String) : String = {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 639 | val tks = tokenizer(input) | 
| 227 
93bd75031ced
added handout
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
219diff
changeset | 640 |   println("Output\n" + Stmts.parse(tks))
 | 
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 641 | val ast = Stmts.parse_single(tks) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 642 | val instructions = compile_bl(ast, Map.empty)._1 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 643 |   (beginning ++ instructions.mkString ++ ending).replaceAllLiterally("XXX", class_name)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 644 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 645 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 646 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 647 | def compile_file(file_name: String) = {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 648 |   val class_name = file_name.split('.')(0)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 649 | val output = compile(class_name, fromFile(file_name)) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 650 | val fw = new java.io.FileWriter(class_name + ".j") | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 651 | fw.write(output) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 652 | fw.close() | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 653 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 654 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 655 | def time_needed[T](i: Int, code: => T) = {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 656 | val start = System.nanoTime() | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 657 | for (j <- 1 to i) code | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 658 | val end = System.nanoTime() | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 659 | (end - start)/(i * 1.0e9) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 660 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 661 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 662 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 663 | def compile_run(file_name: String) : Unit = {
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 664 |   val class_name = file_name.split('.')(0)
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 665 | compile_file(file_name) | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 666 |   val test = ("java -jar jvm/jasmin-2.4/jasmin.jar " + class_name + ".j").!!
 | 
| 227 
93bd75031ced
added handout
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
219diff
changeset | 667 |   ("java " + class_name + "/" + class_name).!
 | 
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 668 | } | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 669 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 670 | |
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 671 | //examples | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 672 | //println(compile("test", p9))
 | 
| 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 673 | //compile_run("loops.while")
 | 
| 704 | 674 | //compile_run("p.while")
 | 
| 675 | compile_run("fib.while")
 | |
| 212 
1459e6e29621
added comp
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 676 | //compile_run("test.while")
 |