| 864 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      1 | // Compiler for JVM
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      2 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      3 | import $file.lexer
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      4 | import lexer._
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      5 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      6 | import $file.parser
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      7 | import parser._
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      8 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      9 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     10 | val beginning = """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     11 | .class public XXX.XXX
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     12 | .super java/lang/Object
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     13 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     14 | .method public static write(I)V 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     15 |     .limit locals 1 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     16 |     .limit stack 2 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     17 |     getstatic java/lang/System/out Ljava/io/PrintStream; 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     18 |     iload 0
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     19 |     invokevirtual java/io/PrintStream/print(I)V 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     20 |     return 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     21 | .end method
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     22 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     23 | .method public static writes(Ljava/lang/String;)V
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     24 |     .limit stack 2
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     25 |     .limit locals 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     26 |     getstatic java/lang/System/out Ljava/io/PrintStream;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     27 |     aload 0
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     28 |     invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     29 |     return
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     30 | .end method
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     31 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     32 | .method public static read()I 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     33 |     .limit locals 10 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     34 |     .limit stack 10
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     35 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     36 |     ldc 0 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     37 |     istore 1  ; this will hold our final integer 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     38 | Label1: 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     39 |     getstatic java/lang/System/in Ljava/io/InputStream; 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     40 |     invokevirtual java/io/InputStream/read()I 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     41 |     istore 2 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     42 |     iload 2 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     43 |     ldc 10   ; the newline delimiter 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     44 |     isub 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     45 |     ifeq Label2 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     46 |     iload 2 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     47 |     ldc 32   ; the space delimiter 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     48 |     isub 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     49 |     ifeq Label2
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     50 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     51 |     iload 2 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     52 |     ldc 48   ; we have our digit in ASCII, have to subtract it from 48 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     53 |     isub 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     54 |     ldc 10 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     55 |     iload 1 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     56 |     imul 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     57 |     iadd 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     58 |     istore 1 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     59 |     goto Label1 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     60 | Label2: 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     61 |     ;when we come here we have our integer computed in local variable 1 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     62 |     iload 1 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     63 |     ireturn 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     64 | .end method
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     65 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     66 | .method public static main([Ljava/lang/String;)V
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     67 |    .limit locals 200
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     68 |    .limit stack 200
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     69 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     70 | ; COMPILED CODE STARTS
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     71 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     72 | """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     73 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     74 | val ending = """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     75 | ; COMPILED CODE ENDS
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     76 |    return
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     77 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     78 | .end method
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     79 | """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     80 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     81 | // Compiler
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     82 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     83 | var counter = -1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     84 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     85 | def Fresh(x: String) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     86 |   counter += 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     87 |   x ++ "_" ++ counter.toString()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     88 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     89 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     90 | implicit def string_interpolations(sc: StringContext) = new {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     91 |     def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     92 |     def l(args: Any*): String = sc.s(args:_*) ++ ":\n"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     93 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     94 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     95 | type Env = Map[String, Int]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     96 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     97 | def compile_op(op: String) = op match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     98 |   case "+" => i"iadd"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     99 |   case "-" => i"isub"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    100 |   case "*" => i"imul"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    101 |   case "/" => i"idiv"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    102 |   case "%" => i"irem"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    103 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    104 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    105 | def compile_aexp(a: AExp, env : Env) : String = a match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    106 |   case Num(i) => i"ldc $i"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    107 |   case Var(s) => i"iload ${env(s)} \t\t; $s"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    108 |   case Aop(op, a1, a2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    109 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ compile_op(op)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    110 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    111 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    112 | def compile_bexp(b: BExp, env : Env, jmp: String) : String = b match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    113 |   case True => ""
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    114 |   case False => i"goto $jmp"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    115 |   case And(b1, b2) => compile_bexp(b1, env, jmp) ++ compile_bexp(b2, env, jmp)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    116 |   case Or(b1, b2) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    117 |     val b1_false = Fresh("Or_second");
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    118 |     val or_end = Fresh("Or_end");
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    119 |     compile_bexp(b1, env, b1_false) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    120 |     i"goto $or_end" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    121 |     l"$b1_false" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    122 |     compile_bexp(b2, env, jmp) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    123 |     l"$or_end"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    124 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    125 |   case Bop("==", a1, a2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    126 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmpne $jmp"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    127 |   case Bop("!=", a1, a2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    128 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmpeq $jmp"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    129 |   case Bop("<", a1, a2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    130 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmpge $jmp"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    131 |   case Bop(">", a1, a2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    132 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmple $jmp"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    133 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    134 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    135 | def compile_stmt(s: Stmt, env: Env) : (String, Env) = s match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    136 |   case Skip => ("", env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    137 |   case Assign(x, a) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    138 |     val index = env.getOrElse(x, env.keys.size)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    139 |     (compile_aexp(a, env) ++ i"istore $index \t\t; $x", env + (x -> index))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    140 |   } 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    141 |   case If(b, bl1, bl2) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    142 |     val if_else = Fresh("If_else")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    143 |     val if_end = Fresh("If_end")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    144 |     val (instrs1, env1) = compile_block(bl1, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    145 |     val (instrs2, env2) = compile_block(bl2, env1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    146 |     (compile_bexp(b, env, if_else) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    147 |      instrs1 ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    148 |      i"goto $if_end" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    149 |      l"$if_else" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    150 |      instrs2 ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    151 |      l"$if_end", env2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    152 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    153 |   case While(b, bl) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    154 |     val loop_begin = Fresh("Loop_begin")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    155 |     val loop_end = Fresh("Loop_end")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    156 |     val (instrs1, env1) = compile_block(bl, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    157 |     (l"$loop_begin" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    158 |      compile_bexp(b, env, loop_end) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    159 |      instrs1 ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    160 |      i"goto $loop_begin" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    161 |      l"$loop_end", env1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    162 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    163 |   case For(id, lower, upper, code) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    164 |       val (assignment_code, env1) = compile_stmt(Assign(id, lower), env)  // id := lower;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    165 |       val while_equivalent = While(
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    166 |           Or(Bop("<", Var(id), upper), Bop("==", Var(id), upper)),    // while id <= upper do {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    167 |           code ++                                                     //    code  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    168 |           List(
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    169 |             Assign(id, Aop("+", Var(id), Num(1)))                     //    id := id + 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    170 |           ))                                                          // };
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    171 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    172 |       val (while_code, env2) = compile_stmt(while_equivalent, env1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    173 |       (assignment_code ++ while_code, env2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    174 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    175 |   case WriteId(x) => (i"iload ${env(x)} \t\t; $x" ++ 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    176 |      i"invokestatic XXX/XXX/write(I)V", env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    177 |   case WriteString(x) => (s"   ldc ${x}\n" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    178 |      i"invokestatic XXX/XXX/writes(Ljava/lang/String;)V", env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    179 |   case Read(x) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    180 |     val index = env.getOrElse(x, env.keys.size) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    181 |     (i"invokestatic XXX/XXX/read()I" ++ 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    182 |      i"istore $index \t\t; $x", env + (x -> index))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    183 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    184 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    185 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    186 | def compile_block(bl: Block, env: Env) : (String, Env) = bl match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    187 |   case Nil => ("", env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    188 |   case s::bl => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    189 |     val (instrs1, env1) = compile_stmt(s, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    190 |     val (instrs2, env2) = compile_block(bl, env1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    191 |     (instrs1 ++ instrs2, env2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    192 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    193 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    194 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    195 | def compile(bl: Block, class_name: String) : String = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    196 |   val instructions = compile_block(bl, Map.empty)._1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    197 |   (beginning ++ instructions ++ ending).replaceAllLiterally("XXX", class_name)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    198 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    199 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    200 | // Compiling and running
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    201 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    202 | import scala.util._
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    203 | import scala.sys.process._
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    204 | import scala.io
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    205 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    206 | def compile_tofile(bl: Block, class_name: String) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    207 |   val output = compile(bl, class_name)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    208 |   val fw = new java.io.FileWriter(class_name + ".j") 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    209 |   fw.write(output) 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    210 |   fw.close()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    211 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    212 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    213 | def compile_all(bl: Block, class_name: String) : Unit = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    214 |   compile_tofile(bl, class_name)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    215 |   println("compiled ")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    216 |   val test = ("java -jar jasmin.jar " + class_name + ".j").!!
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    217 |   println("assembled ")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    218 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    219 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    220 | def time_needed[T](i: Int, code: => T) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    221 |   val start = System.nanoTime()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    222 |   for (j <- 1 to i) code
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    223 |   val end = System.nanoTime()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    224 |   (end - start)/(i * 1.0e9)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    225 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    226 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    227 | def compile_run(bl: Block, class_name: String) : Unit = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    228 |   println("Start compilation")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    229 |   compile_all(bl, class_name)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    230 |   println("running")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    231 |   println("Time: " + time_needed(1, ("java " + class_name + "/" + class_name).!))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    232 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    233 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    234 | // ---- Q1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    235 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    236 | // Fibonacci
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    237 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    238 | val fibonacciProgram = """write "Fib";
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    239 | read n;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    240 | minus1 := 0;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    241 | minus2 := 1;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    242 | while n > 0 do {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    243 |   temp := minus2;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    244 |   minus2 := minus1 + minus2;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    245 |   minus1 := temp;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    246 |   n := n - 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    247 | };
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    248 | write "Result";
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    249 | write minus2"""
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    250 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    251 | //compile_all(Stmts.parse_all(tokenise(fibonacciProgram)).head, "fib")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    252 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    253 | val factorialProgram = """write "Factorial";
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    254 | read n;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    255 | fact := 1;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    256 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    257 | while n > 0 do {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    258 |   fact := n * fact;
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    259 |   n := n - 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    260 | };
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    261 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    262 | write "Result";
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    263 | write fact
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    264 | """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    265 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    266 | compile_all(Stmts.parse_all(tokenise(factorialProgram)).head, "factorial")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    267 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    268 | // ---- Q3
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    269 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    270 | /* compile_run(Stmts.parse_all(tokenise("""for i := 1 upto 10 do {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    271 |   for i := 1 upto 10 do {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    272 |     write i
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    273 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    274 | }""")).head, "nestedloop") */
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    275 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    276 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    277 | compile_run(Stmts.parse_all(tokenise(os.read(os.pwd / "collatz2.while"))).head, "collatz2")
 |