| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      1 | // A Small Compiler for the WHILE Language
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      2 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      3 | // - this compiler contains support for "static" integer 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      4 | //   arrays (they are mutable but cannot be re-sized)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      5 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      6 | // Call with 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      7 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      8 | // amm compile_arrays.sc
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |      9 |   
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     10 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     11 | // the abstract syntax trees for WHILE
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     12 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     13 | abstract class Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     14 | abstract class AExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     15 | abstract class BExp 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     16 | type Block = List[Stmt]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     17 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     18 | // statements
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     19 | case object Skip extends Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     20 | case class ArrayDef(s: String, n: Int) extends Stmt            // array definition
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     21 | case class If(a: BExp, bl1: Block, bl2: Block) extends Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     22 | case class While(b: BExp, bl: Block) extends Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     23 | case class Assign(s: String, a: AExp) extends Stmt             // var := exp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     24 | case class AssignA(s: String, a1: AExp, a2: AExp) extends Stmt // arr[exp1] := exp2
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     25 | case class Write(s: String) extends Stmt
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     26 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     27 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     28 | // arithmetic expressions
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     29 | case class Var(s: String) extends AExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     30 | case class Num(i: Int) extends AExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     31 | case class Aop(o: String, a1: AExp, a2: AExp) extends AExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     32 | case class Ref(s: String, a: AExp) extends AExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     33 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     34 | // boolean expressions
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     35 | case object True extends BExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     36 | case object False extends BExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     37 | case class Bop(o: String, a1: AExp, a2: AExp) extends BExp
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     38 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     39 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     40 | // compiler headers needed for the JVM
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     41 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     42 | // - contains a main method and a method for writing out an integer
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     43 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     44 | // - the stack and locals are hard-coded
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     45 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     46 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     47 | val beginning = """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     48 | .class public XXX.XXX
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     49 | .super java/lang/Object
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     50 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     51 | .method public static write(I)V 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     52 |     .limit locals 1 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     53 |     .limit stack 2 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     54 |     getstatic java/lang/System/out Ljava/io/PrintStream; 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     55 |     iload 0
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     56 |     invokevirtual java/io/PrintStream/print(I)V
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     57 |     return 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     58 | .end method
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     59 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     60 | .method public static main([Ljava/lang/String;)V
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     61 |    .limit locals 200
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     62 |    .limit stack 200
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     63 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     64 | ; COMPILED CODE STARTS   
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     65 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     66 | """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     67 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     68 | val ending = """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     69 | ; COMPILED CODE ENDS
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     70 |    return
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     71 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     72 | .end method
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     73 | """
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     74 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     75 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     76 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     77 | // for generating new labels
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     78 | var counter = -1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     79 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     80 | def Fresh(x: String) = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     81 |   counter += 1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     82 |   x ++ "_" ++ counter.toString()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     83 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     84 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     85 | // environments for variables and indices
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     86 | type Env = Map[String, Int]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     87 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     88 | // convenient string interpolations 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     89 | // for generating instructions and labels
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     90 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     91 | implicit def sring_inters(sc: StringContext) = new {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     92 |     def i(args: Any*): String = "   " ++ sc.s(args:_*) ++ "\n"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     93 |     def l(args: Any*): String = sc.s(args:_*) ++ ":\n"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     94 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |     95 | 
 | 
| 817 |     96 | def compile_num(i: Int) = 
 | 
|  |     97 |   if (0 <= i && i <= 5) i"iconst_$i" else 
 | 
|  |     98 |   if (-128 <= i && i <= 127) i"bipush $i" else i"ldc $i"
 | 
|  |     99 | 
 | 
|  |    100 | def compile_aload(i: Int) = 
 | 
|  |    101 |   if (0 <= i && i <= 3) i"aload_$i" else i"aload $i"
 | 
|  |    102 | 
 | 
|  |    103 | def compile_astore(i: Int) = 
 | 
|  |    104 |   if (0 <= i && i <= 3) i"astore_$i" else i"astore $i"
 | 
|  |    105 | 
 | 
|  |    106 | def compile_iload(i: Int) = 
 | 
|  |    107 |   if (0 <= i && i <= 3) i"iload_$i" else i"iload $i"
 | 
|  |    108 | 
 | 
|  |    109 | def compile_istore(i: Int) = 
 | 
|  |    110 |   if (0 <= i && i <= 3) i"istore_$i" else i"istore $i"
 | 
|  |    111 | 
 | 
|  |    112 | 
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    113 | def compile_op(op: String) = op match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    114 |   case "+" => i"iadd"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    115 |   case "-" => i"isub"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    116 |   case "*" => i"imul"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    117 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    118 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    119 | // arithmetic expression compilation
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    120 | def compile_aexp(a: AExp, env : Env) : String = a match {
 | 
| 817 |    121 |   case Num(i) => compile_num(i)
 | 
|  |    122 |   case Var(s) => compile_iload(env(s))
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    123 |   case Aop(op, a1, a2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    124 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ compile_op(op)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    125 |   case Ref(s, a) =>
 | 
| 817 |    126 |     compile_aload(env(s)) ++ compile_aexp(a, env) ++  i"iaload"
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    127 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    128 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    129 | // boolean expression compilation
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    130 | def compile_bexp(b: BExp, env : Env, jmp: String) : String = b match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    131 |   case True => ""
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    132 |   case False => i"goto $jmp"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    133 |   case Bop("==", a1, a2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    134 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmpne $jmp"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    135 |   case Bop("!=", a1, a2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    136 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmpeq $jmp"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    137 |   case Bop("<", a1, a2) => 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    138 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ i"if_icmpge $jmp"
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    139 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    140 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    141 | // statement compilation
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    142 | def compile_stmt(s: Stmt, env: Env) : (String, Env) = s match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    143 |   case Skip => ("", env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    144 |   case Assign(x, a) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    145 |      val index = env.getOrElse(x, env.keys.size)
 | 
| 817 |    146 |     (compile_aexp(a, env) ++ compile_istore(index), env + (x -> index)) 
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    147 |   } 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    148 |   case If(b, bl1, bl2) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    149 |     val if_else = Fresh("If_else")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    150 |     val if_end = Fresh("If_end")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    151 |     val (instrs1, env1) = compile_block(bl1, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    152 |     val (instrs2, env2) = compile_block(bl2, env1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    153 |     (compile_bexp(b, env, if_else) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    154 |      instrs1 ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    155 |      i"goto $if_end" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    156 |      l"$if_else" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    157 |      instrs2 ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    158 |      l"$if_end", env2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    159 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    160 |   case While(b, bl) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    161 |     val loop_begin = Fresh("Loop_begin")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    162 |     val loop_end = Fresh("Loop_end")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    163 |     val (instrs1, env1) = compile_block(bl, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    164 |     (l"$loop_begin" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    165 |      compile_bexp(b, env, loop_end) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    166 |      instrs1 ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    167 |      i"goto $loop_begin" ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    168 |      l"$loop_end", env1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    169 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    170 |   case Write(x) => 
 | 
| 817 |    171 |     (compile_iload(env(x)) ++ 
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    172 |      i"invokestatic XXX/XXX/write(I)V", env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    173 |   case ArrayDef(s: String, n: Int) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    174 |     val index = if (env.isDefinedAt(s)) throw new Exception("array def error") else 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    175 |                     env.keys.size
 | 
| 817 |    176 |     (compile_num(n) ++
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    177 |      i"newarray int" ++
 | 
| 817 |    178 |      compile_astore(index), env + (s -> index))
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    179 |   }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    180 |   case AssignA(s, a1, a2) => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    181 |     val index = if (env.isDefinedAt(s)) env(s) else 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    182 |                     throw new Exception("array not defined")
 | 
| 817 |    183 |     (compile_aload(env(s)) ++
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    184 |      compile_aexp(a1, env) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    185 |      compile_aexp(a2, env) ++
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    186 |      i"iastore", env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    187 |   } 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    188 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    189 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    190 | // compile a block (i.e. list of statements)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    191 | def compile_block(bl: Block, env: Env) : (String, Env) = bl match {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    192 |   case Nil => ("", env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    193 |   case s::bl => {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    194 |     val (instrs1, env1) = compile_stmt(s, env)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    195 |     val (instrs2, env2) = compile_block(bl, env1)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    196 |     (instrs1 ++ instrs2, env2)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    197 |   }
 | 
| 
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 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    201 | // main compile function for blocks (adds headers and proper JVM names)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    202 | def compile(bl: Block, class_name: String) : String = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    203 |   val instructions = compile_block(bl, Map())._1
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    204 |   (beginning ++ instructions ++ ending).replace("XXX", class_name)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    205 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    206 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    207 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    208 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    209 | // contrived example involving arrays
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    210 | val array_test = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    211 |   List(ArrayDef("a", 10),               // array a[10]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    212 |        ArrayDef("b", 2),                // array b[2]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    213 |        AssignA("a", Num(0), Num(10)),   // a[0] := 10
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    214 |        Assign("x", Ref("a", Num(0))),   // x := a[0]
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    215 |        Write("x"),            
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    216 |        AssignA("b", Num(1), Num(5)),    // b[1] := 5
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    217 |        Assign("x", Ref("b", Num(1))),   // x := b[1] 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    218 |        Write("x"))                     
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    219 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    220 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    221 | // prints out the JVM-assembly instructions for fib above
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    222 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    223 | //    println(compile(array_test, "arr"))
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    224 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    225 | // can be assembled by hand with 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    226 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    227 | //    java -jar jasmin.jar arr.j
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    228 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    229 | // and run with
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    230 | //
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    231 | //    java arr/arr
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    232 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    233 | // automating the above
 | 
| 869 |    234 | 
 | 
|  |    235 | // pre-2.5.0 ammonite 
 | 
|  |    236 | // import ammonite.ops._
 | 
|  |    237 | 
 | 
|  |    238 | // post 2.5.0 ammonite
 | 
|  |    239 | import os._
 | 
|  |    240 | 
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    241 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    242 | def compile_to_file(bl: Block, class_name: String) : Unit = 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    243 |   write.over(pwd / s"$class_name.j", compile(bl, class_name))  
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    244 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    245 | def compile_and_run(bl: Block, class_name: String) : Unit = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    246 |   println(s"Start of compilation")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    247 |   compile_to_file(bl, class_name)
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    248 |   println(s"generated $class_name.j file")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    249 |   os.proc("java", "-jar", "jasmin.jar", s"$class_name.j").call()
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    250 |   println(s"generated $class_name.class file ")
 | 
| 747 |    251 |   //println(os.proc("java", s"${class_name}/${class_name}").call().out.text())
 | 
|  |    252 |   os.proc("java", s"${class_name}/${class_name}").call(stdout = os.Inherit)
 | 
| 725 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    253 |   println(s"done.")
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    254 | }
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    255 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    256 | 
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    257 |    
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    258 | @main def main() = {
 | 
| 
Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset |    259 |   compile_and_run(array_test, "arr")
 | 
| 
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 | 
 | 
| 829 |    263 | 
 | 
|  |    264 | 
 | 
|  |    265 | 
 | 
|  |    266 | // runs with amm2 and amm3
 |