| author | Christian Urban <urbanc@in.tum.de> | 
| Sun, 21 May 2017 07:35:35 +0100 | |
| changeset 494 | ac370a049359 | 
| parent 380 | 1e88390e81aa | 
| child 625 | f8d3e2c7d8b2 | 
| permissions | -rw-r--r-- | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 1 | import scala.language.implicitConversions | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 2 | import scala.language.reflectiveCalls | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 3 | import scala.util._ | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 4 | import scala.annotation.tailrec | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 5 | import scala.sys.process._ | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 6 | |
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 7 | def fromFile(name: String) : String = | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 8 | io.Source.fromFile(name).mkString | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 9 | |
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 10 | abstract class Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 11 | case object NULL extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 12 | case object EMPTY extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 13 | case class CHAR(c: Char) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 14 | case class ALT(r1: Rexp, r2: Rexp) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 15 | case class RANGE(cs: List[Char]) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 16 | case class SEQ(r1: Rexp, r2: Rexp) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 17 | case class PLUS(r: Rexp) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 18 | case class STAR(r: Rexp) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 19 | case class NTIMES(r: Rexp, n: Int) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 20 | case class NUPTOM(r: Rexp, n: Int, m: Int) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 21 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 22 | object RANGE {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 23 | def apply(s: String) : RANGE = RANGE(s.toList) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 24 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 25 | def NMTIMES(r: Rexp, n: Int, m: Int) = {
 | 
| 223 
e4b29b57f6a3
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
221diff
changeset | 26 |   if (m < n) throw new IllegalArgumentException("the number m cannot be smaller than n.")
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 27 | else NUPTOM(r, n, m - n) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 28 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 29 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 30 | case class NOT(r: Rexp) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 31 | case class OPT(r: Rexp) extends Rexp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 32 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 33 | // some convenience for typing in regular expressions | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 34 | def charlist2rexp(s : List[Char]) : Rexp = s match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 35 | case Nil => EMPTY | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 36 | case c::Nil => CHAR(c) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 37 | case c::s => SEQ(CHAR(c), charlist2rexp(s)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 38 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 39 | implicit def string2rexp(s : String) : Rexp = charlist2rexp(s.toList) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 40 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 41 | implicit def RexpOps (r: Rexp) = new {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 42 | def | (s: Rexp) = ALT(r, s) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 43 | def % = STAR(r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 44 | def ~ (s: Rexp) = SEQ(r, s) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 45 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 46 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 47 | implicit def stringOps (s: String) = new {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 48 | def | (r: Rexp) = ALT(s, r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 49 | def | (r: String) = ALT(s, r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 50 | def % = STAR(s) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 51 | def ~ (r: Rexp) = SEQ(s, r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 52 | def ~ (r: String) = SEQ(s, r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 53 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 54 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 55 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 56 | // nullable function: tests whether the regular | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 57 | // expression can recognise the empty string | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 58 | def nullable (r: Rexp) : Boolean = r match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 59 | case NULL => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 60 | case EMPTY => true | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 61 | case CHAR(_) => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 62 | case ALT(r1, r2) => nullable(r1) || nullable(r2) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 63 | case SEQ(r1, r2) => nullable(r1) && nullable(r2) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 64 | case STAR(_) => true | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 65 | case PLUS(r) => nullable(r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 66 | case NTIMES(r, i) => if (i == 0) true else nullable(r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 67 | case NUPTOM(r, i, j) => if (i == 0) true else nullable(r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 68 | case RANGE(_) => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 69 | case NOT(r) => !(nullable(r)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 70 | case OPT(_) => true | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 71 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 72 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 73 | // derivative of a regular expression w.r.t. a character | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 74 | def der (c: Char, r: Rexp) : Rexp = r match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 75 | case NULL => NULL | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 76 | case EMPTY => NULL | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 77 | case CHAR(d) => if (c == d) EMPTY else NULL | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 78 | case ALT(r1, r2) => ALT(der(c, r1), der(c, r2)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 79 | case SEQ(r1, r2) => | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 80 | if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 81 | else SEQ(der(c, r1), r2) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 82 | case STAR(r) => SEQ(der(c, r), STAR(r)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 83 | case PLUS(r) => SEQ(der(c, r), STAR(r)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 84 | case NTIMES(r, i) => | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 85 | if (i == 0) NULL else der(c, SEQ(r, NTIMES(r, i - 1))) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 86 | case NUPTOM(r, i, j) => | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 87 | if (i == 0 && j == 0) NULL else | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 88 | if (i == 0) ALT(der(c, NTIMES(r, j)), der(c, NUPTOM(r, 0, j - 1))) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 89 | else der(c, SEQ(r, NUPTOM(r, i - 1, j))) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 90 | case RANGE(cs) => if (cs contains c) EMPTY else NULL | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 91 | case NOT(r) => NOT(der (c, r)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 92 | case OPT(r) => der(c, r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 93 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 94 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 95 | def zeroable (r: Rexp) : Boolean = r match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 96 | case NULL => true | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 97 | case EMPTY => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 98 | case CHAR(_) => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 99 | case ALT(r1, r2) => zeroable(r1) && zeroable(r2) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 100 | case SEQ(r1, r2) => zeroable(r1) || zeroable(r2) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 101 | case STAR(_) => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 102 | case PLUS(r) => zeroable(r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 103 | case NTIMES(r, i) => if (i == 0) false else zeroable(r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 104 | case NUPTOM(r, i, j) => if (i == 0) false else zeroable(r) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 105 | case RANGE(_) => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 106 | case NOT(r) => !(zeroable(r)) // bug: incorrect definition for NOT | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 107 | case OPT(_) => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 108 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 109 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 110 | // derivative w.r.t. a string (iterates der) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 111 | def ders (s: List[Char], r: Rexp) : Rexp = s match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 112 | case Nil => r | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 113 | case c::s => ders(s, der(c, r)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 114 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 115 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 116 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 117 | // regular expressions for the While language | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
311diff
changeset | 118 | val SYM = RANGE("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_".toList)
 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
311diff
changeset | 119 | val DIGIT = RANGE("0123456789".toList)
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 120 | val ID = SYM ~ (SYM | DIGIT).% | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 121 | val NUM = PLUS(DIGIT) | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 122 | val KEYWORD : Rexp = "if" | "then" | "else" | "write" | "def" | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 123 | val SEMI: Rexp = ";" | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 124 | val COMMA: Rexp = "," | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 125 | val OP: Rexp = ":=" | "==" | "-" | "+" | "*" | "!=" | "<=" | "=>" | "<" | ">" | "%" | "=" | "/" | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 126 | val WHITESPACE = PLUS(" " | "\n" | "\t")
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 127 | val RPAREN: Rexp = ")" | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 128 | val LPAREN: Rexp = "("
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 129 | val ALL = SYM | DIGIT | OP | " " | ":" | ";" | "\"" | "=" | "," | "(" | ")"
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 130 | val ALL2 = ALL | "\n" | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 131 | val COMMENT = ("/*" ~ ALL2.% ~ "*/") | ("//" ~ ALL.% ~ "\n")
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 132 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 133 | |
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 134 | // token for While language | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 135 | abstract class Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 136 | case object T_WHITESPACE extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 137 | case object T_SEMI extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 138 | case object T_COMMA extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 139 | case object T_LPAREN extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 140 | case object T_RPAREN extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 141 | case object T_COMMENT extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 142 | case class T_ID(s: String) extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 143 | case class T_OP(s: String) extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 144 | case class T_NUM(s: String) extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 145 | case class T_KWD(s: String) extends Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 146 | case class T_ERR(s: String) extends Token // special error token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 147 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 148 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 149 | type TokenFun = String => Token | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 150 | type LexRules = List[(Rexp, TokenFun)] | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 151 | val While_lexing_rules: LexRules = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 152 | List((KEYWORD, (s) => T_KWD(s)), | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 153 | (ID, (s) => T_ID(s)), | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 154 | (COMMENT, (s) => T_COMMENT), | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 155 | (OP, (s) => T_OP(s)), | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 156 | (NUM, (s) => T_NUM(s)), | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 157 | (SEMI, (s) => T_SEMI), | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 158 | (COMMA, (s) => T_COMMA), | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 159 | (LPAREN, (s) => T_LPAREN), | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 160 | (RPAREN, (s) => T_RPAREN), | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 161 | (WHITESPACE, (s) => T_WHITESPACE)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 162 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 163 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 164 | // calculates derivatives until all of them are zeroable | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 165 | @tailrec | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 166 | def munch(s: List[Char], | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 167 | pos: Int, | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 168 | rs: LexRules, | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 169 |           last: Option[(Int, TokenFun)]): Option[(Int, TokenFun)] = {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 170 |   rs match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 171 | case Nil => last | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 172 | case rs if (s.length <= pos) => last | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 173 |   case rs => {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 174 |     val ders = rs.map({case (r, tf) => (der(s(pos), r), tf)})
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 175 |     val rs_nzero = ders.filterNot({case (r, _) => zeroable(r)})
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 176 |     val rs_nulls = ders.filter({case (r, _) => nullable(r)})
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 177 | val new_last = if (rs_nulls != Nil) Some((pos, rs_nulls.head._2)) else last | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 178 | munch(s, 1 + pos, rs_nzero, new_last) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 179 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 180 | }} | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 181 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 182 | // iterates the munching function and returns a Token list | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 183 | def tokenize(s: String, rs: LexRules) : List[Token] = munch(s.toList, 0, rs, None) match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 184 | case None if (s == "") => Nil | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 185 | case None => List(T_ERR(s"Lexing error: $s")) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 186 |   case Some((n, tf)) => {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 187 | val (head, tail) = s.splitAt(n + 1) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 188 | tf(head)::tokenize(tail, rs) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 189 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 190 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 191 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 192 | def tokenizer(s:String) : List[Token] = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 193 |   tokenize(s, While_lexing_rules).filter {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 194 |     case T_ERR(s) => { println(s); sys.exit(-1) }
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 195 | case T_WHITESPACE => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 196 | case T_COMMENT => false | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 197 | case _ => true | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 198 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 199 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 200 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 201 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 202 | // Parser - Abstract syntax trees | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 203 | abstract class Exp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 204 | abstract class BExp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 205 | abstract class Decl | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 206 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 207 | case class Def(name: String, args: List[String], body: Exp) extends Decl | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 208 | case class Main(e: Exp) extends Decl | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 209 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 210 | case class Call(name: String, args: List[Exp]) extends Exp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 211 | case class If(a: BExp, e1: Exp, e2: Exp) extends Exp | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 212 | case class Write(e: Exp) extends Exp | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 213 | case class Var(s: String) extends Exp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 214 | case class Num(i: Int) extends Exp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 215 | case class Aop(o: String, a1: Exp, a2: Exp) extends Exp | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 216 | case class Sequ(e1: Exp, e2: Exp) extends Exp | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 217 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 218 | case class Bop(o: String, a1: Exp, a2: Exp) extends BExp | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 219 | |
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 220 | // calculating the maximal needed stack size | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 221 | def max_stack_exp(e: Exp): Int = e match {
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 222 | case Call(_, args) => args.map(max_stack_exp).sum | 
| 225 
ef573e8fc86e
bug found by Andres
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
223diff
changeset | 223 | case If(a, e1, e2) => max_stack_bexp(a) + (List(max_stack_exp(e1), max_stack_exp(e2)).max) | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 224 | case Write(e) => max_stack_exp(e) + 1 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 225 | case Var(_) => 1 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 226 | case Num(_) => 1 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 227 | case Aop(_, a1, a2) => max_stack_exp(a1) + max_stack_exp(a2) | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 228 | case Sequ(e1, e2) => List(max_stack_exp(e1), max_stack_exp(e2)).max | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 229 | } | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 230 | def max_stack_bexp(e: BExp): Int = e match {
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 231 | case Bop(_, a1, a2) => max_stack_exp(a1) + max_stack_exp(a2) | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 232 | } | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 233 | |
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 234 | // Parser combinators | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 235 | abstract class Parser[I <% Seq[_], T] {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 236 | def parse(ts: I): Set[(T, I)] | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 237 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 238 | def parse_all(ts: I) : Set[T] = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 239 | for ((head, tail) <- parse(ts); if (tail.isEmpty)) yield head | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 240 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 241 |   def parse_single(ts: I) : T = parse_all(ts).toList match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 242 | case List(t) => t | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 243 |     case _ => { println ("Parse Error") ; sys.exit(-1) }
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 244 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 245 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 246 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 247 | class SeqParser[I <% Seq[_], T, S](p: => Parser[I, T], q: => Parser[I, S]) extends Parser[I, (T, S)] {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 248 | def parse(sb: I) = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 249 | for ((head1, tail1) <- p.parse(sb); | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 250 | (head2, tail2) <- q.parse(tail1)) yield ((head1, head2), tail2) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 251 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 252 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 253 | class AltParser[I <% Seq[_], T](p: => Parser[I, T], q: => Parser[I, T]) extends Parser[I, T] {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 254 | def parse(sb: I) = p.parse(sb) ++ q.parse(sb) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 255 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 256 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 257 | class FunParser[I <% Seq[_], T, S](p: => Parser[I, T], f: T => S) extends Parser[I, S] {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 258 | def parse(sb: I) = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 259 | for ((head, tail) <- p.parse(sb)) yield (f(head), tail) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 260 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 261 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 262 | case class TokParser(tok: Token) extends Parser[List[Token], Token] {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 263 |   def parse(ts: List[Token]) = ts match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 264 | case t::ts if (t == tok) => Set((t, ts)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 265 | case _ => Set () | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 266 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 267 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 268 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 269 | implicit def token2tparser(t: Token) = TokParser(t) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 270 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 271 | case object NumParser extends Parser[List[Token], Int] {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 272 |   def parse(ts: List[Token]) = ts match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 273 | case T_NUM(s)::ts => Set((s.toInt, ts)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 274 | case _ => Set () | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 275 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 276 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 277 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 278 | case object IdParser extends Parser[List[Token], String] {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 279 |   def parse(ts: List[Token]) = ts match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 280 | case T_ID(s)::ts => Set((s, ts)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 281 | case _ => Set () | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 282 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 283 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 284 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 285 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 286 | implicit def ParserOps[I<% Seq[_], T](p: Parser[I, T]) = new {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 287 | def || (q : => Parser[I, T]) = new AltParser[I, T](p, q) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 288 | def ==>[S] (f: => T => S) = new FunParser[I, T, S](p, f) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 289 | def ~[S] (q : => Parser[I, S]) = new SeqParser[I, T, S](p, q) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 290 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 291 | implicit def TokOps(t: Token) = new {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 292 | def || (q : => Parser[List[Token], Token]) = new AltParser[List[Token], Token](t, q) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 293 | def ==>[S] (f: => Token => S) = new FunParser[List[Token], Token, S](t, f) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 294 | def ~[S](q : => Parser[List[Token], S]) = new SeqParser[List[Token], Token, S](t, q) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 295 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 296 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 297 | def ListParser[I <% Seq[_], T, S](p: => Parser[I, T], q: => Parser[I, S]): Parser[I, List[T]] = {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 298 |   (p ~ q ~ ListParser(p, q)) ==> { case ((x, y), z) => x :: z : List[T] } ||
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 299 | (p ==> ((s) => List(s))) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 300 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 301 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 302 | |
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 303 | // expressions | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 304 | lazy val Exp: Parser[List[Token], Exp] = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 305 |   (T_KWD("if") ~ BExp ~ T_KWD("then") ~ Exp ~ T_KWD("else") ~ Exp) ==>
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 306 |     { case (((((x, y), z), u), v), w) => If(y, u, w): Exp } ||
 | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 307 |   (M ~ T_SEMI ~ Exp) ==> { case ((x, y), z) => Sequ(x, z): Exp } || M
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 308 | lazy val M: Parser[List[Token], Exp] = | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 309 |   (T_KWD("write") ~ L) ==> { case (x, y) => Write(y): Exp } || L
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 310 | lazy val L: Parser[List[Token], Exp] = | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 311 |   (T ~ T_OP("+") ~ Exp) ==> { case ((x, y), z) => Aop("+", x, z): Exp } ||
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 312 |   (T ~ T_OP("-") ~ Exp) ==> { case ((x, y), z) => Aop("-", x, z): Exp } || T  
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 313 | lazy val T: Parser[List[Token], Exp] = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 314 |   (F ~ T_OP("*") ~ T) ==> { case ((x, y), z) => Aop("*", x, z): Exp } || 
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 315 |   (F ~ T_OP("/") ~ T) ==> { case ((x, y), z) => Aop("/", x, z): Exp } || 
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 316 |   (F ~ T_OP("%") ~ T) ==> { case ((x, y), z) => Aop("%", x, z): Exp } || F
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 317 | lazy val F: Parser[List[Token], Exp] = | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 318 | (IdParser ~ T_LPAREN ~ ListParser(Exp, T_COMMA) ~ T_RPAREN) ==> | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 319 |     { case (((x, y), z), w) => Call(x, z): Exp } ||
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 320 |   (T_LPAREN ~ Exp ~ T_RPAREN) ==> { case ((x, y), z) => y: Exp } || 
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 321 |   IdParser ==> { case x => Var(x): Exp } || 
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 322 |   NumParser ==> { case x => Num(x): Exp }
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 323 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 324 | // boolean expressions | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 325 | lazy val BExp: Parser[List[Token], BExp] = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 326 |   (Exp ~ T_OP("==") ~ Exp) ==> { case ((x, y), z) => Bop("==", x, z): BExp } || 
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 327 |   (Exp ~ T_OP("!=") ~ Exp) ==> { case ((x, y), z) => Bop("!=", x, z): BExp } || 
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 328 |   (Exp ~ T_OP("<") ~ Exp) ==> { case ((x, y), z) => Bop("<", x, z): BExp } || 
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 329 |   (Exp ~ T_OP(">") ~ Exp) ==> { case ((x, y), z) => Bop("<", z, x): BExp } || 
 | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 330 |   (Exp ~ T_OP("<=") ~ Exp) ==> { case ((x, y), z) => Bop("<=", x, z): BExp } || 
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 331 |   (Exp ~ T_OP("=>") ~ Exp) ==> { case ((x, y), z) => Bop("<=", z, x): BExp }  
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 332 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 333 | lazy val Defn: Parser[List[Token], Decl] = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 334 |    (T_KWD("def") ~ IdParser ~ T_LPAREN ~ ListParser(IdParser, T_COMMA) ~ T_RPAREN ~ T_OP("=") ~ Exp) ==>
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 335 |      { case ((((((x, y), z), w), u), v), r) => Def(y, w, r): Decl }
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 336 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 337 | lazy val Prog: Parser[List[Token], List[Decl]] = | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 338 |   (Defn ~ T_SEMI ~ Prog) ==> { case ((x, y), z) => x :: z : List[Decl] } ||
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 339 | (Exp ==> ((s) => List(Main(s)) : List[Decl])) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 340 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 341 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 342 | // compiler - built-in functions | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 343 | // copied from http://www.ceng.metu.edu.tr/courses/ceng444/link/jvm-cpm.html | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 344 | // | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 345 | |
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 346 | val library = """ | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 347 | .class public XXX.XXX | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 348 | .super java/lang/Object | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 349 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 350 | .method public <init>()V | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 351 | aload_0 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 352 | invokenonvirtual java/lang/Object/<init>()V | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 353 | return | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 354 | .end method | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 355 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 356 | .method public static write(I)V | 
| 380 
1e88390e81aa
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 357 | .limit locals 1 | 
| 
1e88390e81aa
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 358 | .limit stack 2 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 359 | getstatic java/lang/System/out Ljava/io/PrintStream; | 
| 380 
1e88390e81aa
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 360 | iload 0 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 361 | invokevirtual java/io/PrintStream/println(I)V | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 362 | return | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 363 | .end method | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 364 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 365 | """ | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 366 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 367 | // for generating new labels | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 368 | var counter = -1 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 369 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 370 | def Fresh(x: String) = {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 371 | counter += 1 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 372 | x ++ "_" ++ counter.toString() | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 373 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 374 | |
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 375 | type Mem = Map[String, Int] | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 376 | type Instrs = List[String] | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 377 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 378 | def compile_exp(a: Exp, env : Mem) : Instrs = a match {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 379 |   case Num(i) => List("ldc " + i.toString + "\n")
 | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 380 |   case Var(s) => List("iload " + env(s).toString + "\n")
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 381 |   case Aop("+", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ List("iadd\n")
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 382 |   case Aop("-", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ List("isub\n")
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 383 |   case Aop("*", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ List("imul\n")
 | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 384 |   case Aop("/", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ List("idiv\n")
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 385 |   case Aop("%", a1, a2) => compile_exp(a1, env) ++ compile_exp(a2, env) ++ List("irem\n")
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 386 |   case If(b, a1, a2) => {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 387 |     val if_else = Fresh("If_else")
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 388 |     val if_end = Fresh("If_end")
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 389 | compile_bexp(b, env, if_else) ++ | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 390 | compile_exp(a1, env) ++ | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 391 |     List("goto " + if_end + "\n") ++
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 392 |     List("\n" + if_else + ":\n\n") ++
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 393 | compile_exp(a2, env) ++ | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 394 |     List("\n" + if_end + ":\n\n")
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 395 | } | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 396 |   case Call(n, args) => {
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 397 | val is = "I" * args.length | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 398 | args.flatMap(a => compile_exp(a, env)) ++ | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 399 |     List ("invokestatic XXX/XXX/" + n + "(" + is + ")I\n")
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 400 | } | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 401 |   case Sequ(a1, a2) => {
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 402 |     compile_exp(a1, env) ++ List("pop\n") ++ compile_exp(a2, env)
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 403 | } | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 404 |   case Write(a1) => {
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 405 | compile_exp(a1, env) ++ | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 406 |     List("dup\n",
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 407 | "invokestatic XXX/XXX/write(I)V\n") | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 408 | } | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 409 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 410 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 411 | def compile_bexp(b: BExp, env : Mem, jmp: String) : Instrs = b match {
 | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 412 |   case Bop("==", a1, a2) => 
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 413 |     compile_exp(a1, env) ++ compile_exp(a2, env) ++ List("if_icmpne " + jmp + "\n")
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 414 |   case Bop("!=", a1, a2) => 
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 415 |     compile_exp(a1, env) ++ compile_exp(a2, env) ++ List("if_icmpeq " + jmp + "\n")
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 416 |   case Bop("<", a1, a2) => 
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 417 |     compile_exp(a1, env) ++ compile_exp(a2, env) ++ List("if_icmpge " + jmp + "\n")
 | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 418 |   case Bop("<=", a1, a2) => 
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 419 |     compile_exp(a1, env) ++ compile_exp(a2, env) ++ List("if_icmpgt " + jmp + "\n")
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 420 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 421 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 422 | def compile_decl(d: Decl) : Instrs = d match {
 | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 423 |   case Def(name, args, a) => { 
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 424 | val env = args.zipWithIndex.toMap | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 425 | val is = "I" * args.length | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 426 |     List(".method public static " + name + "(" + is + ")I \n",
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 427 | ".limit locals " + args.length.toString + "\n", | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 428 | ".limit stack " + (1 + max_stack_exp(a)).toString + "\n", | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 429 | name + "_Start:\n") ++ | 
| 223 
e4b29b57f6a3
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
221diff
changeset | 430 | compile_exp(a, env) ++ | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 431 |     List("ireturn\n",
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 432 | ".end method \n\n") | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 433 | } | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 434 |   case Main(a) => {
 | 
| 223 
e4b29b57f6a3
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
221diff
changeset | 435 |     List(".method public static main([Ljava/lang/String;)V\n",
 | 
| 
e4b29b57f6a3
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
221diff
changeset | 436 | ".limit locals 200\n", | 
| 
e4b29b57f6a3
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
221diff
changeset | 437 | ".limit stack 200\n") ++ | 
| 
e4b29b57f6a3
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
221diff
changeset | 438 | compile_exp(a, Map()) ++ | 
| 
e4b29b57f6a3
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
221diff
changeset | 439 |     List("invokestatic XXX/XXX/write(I)V\n",
 | 
| 
e4b29b57f6a3
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
221diff
changeset | 440 | "return\n", | 
| 
e4b29b57f6a3
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
221diff
changeset | 441 | ".end method\n") | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 442 | } | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 443 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 444 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 445 | def compile(class_name: String, input: String) : String = {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 446 | val tks = tokenizer(input) | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
311diff
changeset | 447 |   println(Prog.parse_single(tks).mkString("\n"))
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 448 | val ast = Prog.parse_single(tks) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 449 | val instructions = ast.flatMap(compile_decl).mkString | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 450 |   (library + instructions).replaceAllLiterally("XXX", class_name)
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 451 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 452 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 453 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
311diff
changeset | 454 | |
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
311diff
changeset | 455 | |
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 456 | def compile_file(file_name: String) = {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 457 |   val class_name = file_name.split('.')(0)
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 458 | val output = compile(class_name, fromFile(file_name)) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 459 | val fw = new java.io.FileWriter(class_name + ".j") | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 460 | fw.write(output) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 461 | fw.close() | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 462 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 463 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 464 | def time_needed[T](i: Int, code: => T) = {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 465 | val start = System.nanoTime() | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 466 | for (j <- 1 to i) code | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 467 | val end = System.nanoTime() | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 468 | (end - start)/(i * 1.0e9) | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 469 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 470 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 471 | def compile_run(file_name: String) : Unit = {
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 472 |   val class_name = file_name.split('.')(0)
 | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 473 | compile_file(file_name) | 
| 221 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 474 |   val test = ("java -jar jvm/jasmin-2.4/jasmin.jar " + class_name + ".j").!!
 | 
| 
824ffbf66ab4
added fun tail
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
220diff
changeset | 475 |   println("Time: " + time_needed(2, ("java " + class_name + "/" + class_name).!))
 | 
| 220 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 476 | } | 
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 477 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 478 | |
| 
141041fc76b5
added
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 479 | //examples | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
311diff
changeset | 480 | compile_file("fact.rec")
 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
311diff
changeset | 481 | //compile_run("defs.rec")
 | 
| 311 
6719e8d10a0d
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
225diff
changeset | 482 | //compile_run("fact.rec")
 |