| author | cu | 
| Tue, 03 Oct 2017 23:01:06 +0100 | |
| changeset 512 | 56550ad904d8 | 
| parent 471 | e5df48ff7033 | 
| child 535 | 3871fc18506b | 
| permissions | -rw-r--r-- | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 1 | // A Small Compiler for the WHILE Language | 
| 471 | 2 | // (it does not use a parser and lexer) | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 3 | |
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 4 | // the abstract syntax trees | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 5 | abstract class Stmt | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 6 | abstract class AExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 7 | abstract class BExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 8 | type Block = List[Stmt] | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 9 | |
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 10 | // statements | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 11 | case object Skip extends Stmt | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 12 | case class If(a: BExp, bl1: Block, bl2: Block) extends Stmt | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 13 | case class While(b: BExp, bl: Block) extends Stmt | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 14 | case class Assign(s: String, a: AExp) extends Stmt | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 15 | case class Write(s: String) extends Stmt | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 16 | case class Read(s: String) extends Stmt | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 17 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 18 | // arithmetic expressions | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 19 | case class Var(s: String) extends AExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 20 | case class Num(i: Int) extends AExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 21 | case class Aop(o: String, a1: AExp, a2: AExp) extends AExp | 
| 70 
e6868bd2942b
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
69diff
changeset | 22 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 23 | // boolean expressions | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 24 | case object True extends BExp | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 25 | case object False extends BExp | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 26 | case class Bop(o: String, a1: AExp, a2: AExp) extends BExp | 
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 27 | |
| 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 28 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 29 | // compiler headers needed for the JVM | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 30 | // (contains an init method, as well as methods for read and write) | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 31 | val beginning = """ | 
| 80 
191daa3ee29e
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
76diff
changeset | 32 | .class public XXX.XXX | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 33 | .super java/lang/Object | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 34 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 35 | .method public <init>()V | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 36 | aload_0 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 37 | invokenonvirtual java/lang/Object/<init>()V | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 38 | return | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 39 | .end method | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 40 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 41 | .method public static write(I)V | 
| 373 
b018234c9126
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
369diff
changeset | 42 | .limit locals 1 | 
| 
b018234c9126
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
369diff
changeset | 43 | .limit stack 2 | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 44 | getstatic java/lang/System/out Ljava/io/PrintStream; | 
| 373 
b018234c9126
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
369diff
changeset | 45 | iload 0 | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 46 | invokevirtual java/io/PrintStream/println(I)V | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 47 | return | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 48 | .end method | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 49 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 50 | .method public static read()I | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 51 | .limit locals 10 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 52 | .limit stack 10 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 53 | |
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 54 | ldc 0 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 55 | istore 1 ; this will hold our final integer | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 56 | Label1: | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 57 | getstatic java/lang/System/in Ljava/io/InputStream; | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 58 | invokevirtual java/io/InputStream/read()I | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 59 | istore 2 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 60 | iload 2 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 61 | ldc 10 ; the newline delimiter | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 62 | isub | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 63 | ifeq Label2 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 64 | iload 2 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 65 | ldc 32 ; the space delimiter | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 66 | isub | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 67 | ifeq Label2 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 68 | |
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 69 | iload 2 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 70 | ldc 48 ; we have our digit in ASCII, have to subtract it from 48 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 71 | isub | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 72 | ldc 10 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 73 | iload 1 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 74 | imul | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 75 | iadd | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 76 | istore 1 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 77 | goto Label1 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 78 | Label2: | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 79 | ;when we come here we have our integer computed in local variable 1 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 80 | iload 1 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 81 | ireturn | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 82 | .end method | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 83 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 84 | .method public static main([Ljava/lang/String;)V | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 85 | .limit locals 200 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 86 | .limit stack 200 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 87 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 88 | """ | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 89 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 90 | val ending = """ | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 91 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 92 | return | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 93 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 94 | .end method | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 95 | """ | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 96 | |
| 471 | 97 | println("starting")
 | 
| 98 | ||
| 99 | ||
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 100 | // for generating new labels | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 101 | var counter = -1 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 102 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 103 | def Fresh(x: String) = {
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 104 | counter += 1 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 105 | x ++ "_" ++ counter.toString() | 
| 66 
9215b9fb8852
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: diff
changeset | 106 | } | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 107 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 108 | // environments and instructions | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 109 | type Env = Map[String, String] | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 110 | type Instrs = List[String] | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 111 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 112 | // arithmetic expression compilation | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 113 | def compile_aexp(a: AExp, env : Env) : Instrs = a match {
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 114 |   case Num(i) => List("ldc " + i.toString + "\n")
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 115 |   case Var(s) => List("iload " + env(s) + "\n")
 | 
| 369 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 116 |   case Aop("+", a1, a2) => 
 | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 117 | compile_aexp(a1, env) ++ | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 118 |     compile_aexp(a2, env) ++ List("iadd\n")
 | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 119 |   case Aop("-", a1, a2) => 
 | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 120 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("isub\n")
 | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 121 |   case Aop("*", a1, a2) => 
 | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 122 |     compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("imul\n")
 | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 123 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 124 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 125 | // boolean expression compilation | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 126 | def compile_bexp(b: BExp, env : Env, jmp: String) : Instrs = b match {
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 127 | case True => Nil | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 128 |   case False => List("goto " + jmp + "\n")
 | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 129 |   case Bop("=", a1, a2) => 
 | 
| 369 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 130 | compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 131 |     List("if_icmpne " + jmp + "\n")
 | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 132 |   case Bop("!=", a1, a2) => 
 | 
| 369 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 133 | compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 134 |     List("if_icmpeq " + jmp + "\n")
 | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 135 |   case Bop("<", a1, a2) => 
 | 
| 369 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 136 | compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 137 |     List("if_icmpge " + jmp + "\n")
 | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 138 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 139 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 140 | // statement compilation | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 141 | def compile_stmt(s: Stmt, env: Env) : (Instrs, Env) = s match {
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 142 | case Skip => (Nil, env) | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 143 |   case Assign(x, a) => {
 | 
| 369 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 144 | val index = if (env.isDefinedAt(x)) env(x) else | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 145 | env.keys.size.toString | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 146 | (compile_aexp(a, env) ++ | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 147 |      List("istore " + index + "\n"), env + (x -> index))
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 148 | } | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 149 |   case If(b, bl1, bl2) => {
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 150 |     val if_else = Fresh("If_else")
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 151 |     val if_end = Fresh("If_end")
 | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 152 | val (instrs1, env1) = compile_block(bl1, env) | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 153 | val (instrs2, env2) = compile_block(bl2, env1) | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 154 | (compile_bexp(b, env, if_else) ++ | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 155 | instrs1 ++ | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 156 |      List("goto " + if_end + "\n") ++
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 157 |      List("\n" + if_else + ":\n\n") ++
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 158 | instrs2 ++ | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 159 |      List("\n" + if_end + ":\n\n"), env2)
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 160 | } | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 161 |   case While(b, bl) => {
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 162 |     val loop_begin = Fresh("Loop_begin")
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 163 |     val loop_end = Fresh("Loop_end")
 | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 164 | val (instrs1, env1) = compile_block(bl, env) | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 165 |     (List("\n" + loop_begin + ":\n\n") ++
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 166 | compile_bexp(b, env, loop_end) ++ | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 167 | instrs1 ++ | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 168 |      List("goto " + loop_begin + "\n") ++
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 169 |      List("\n" + loop_end + ":\n\n"), env1)
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 170 | } | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 171 | case Write(x) => | 
| 369 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 172 |     (List("iload " + env(x) + "\n" + 
 | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 173 | "invokestatic XXX/XXX/write(I)V\n"), env) | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 174 |   case Read(x) => {
 | 
| 369 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 175 | val index = if (env.isDefinedAt(x)) env(x) else | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 176 | env.keys.size.toString | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 177 |     (List("invokestatic XXX/XXX/read()I\n" + 
 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 178 | "istore " + index + "\n"), env + (x -> index)) | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 179 | } | 
| 69 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 180 | } | 
| 
cc3f7908b942
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
68diff
changeset | 181 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 182 | // compilation of a block (i.e. list of instructions) | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 183 | def compile_block(bl: Block, env: Env) : (Instrs, Env) = bl match {
 | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 184 | case Nil => (Nil, env) | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 185 |   case s::bl => {
 | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 186 | val (instrs1, env1) = compile_stmt(s, env) | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 187 | val (instrs2, env2) = compile_block(bl, env1) | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 188 | (instrs1 ++ instrs2, env2) | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 189 | } | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 190 | } | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 191 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 192 | // main compilation function for blocks | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 193 | def compile(bl: Block, class_name: String) : String = {
 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 194 | val instructions = compile_block(bl, Map.empty)._1 | 
| 80 
191daa3ee29e
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
76diff
changeset | 195 |   (beginning ++ instructions.mkString ++ ending).replaceAllLiterally("XXX", class_name)
 | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 196 | } | 
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 197 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 198 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 199 | // Fibonacci numbers as a test-case | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 200 | val fib_test = | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 201 |   List(Read("n"),                       //  read n;                     
 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 202 |        Assign("minus1",Num(0)),         //  minus1 := 0;
 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 203 |        Assign("minus2",Num(1)),         //  minus2 := 1;
 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 204 |        Assign("temp",Num(0)),           //  temp := 0;
 | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 205 |        While(Bop("<",Num(0),Var("n")),  //  while n > 0 do  {
 | 
| 369 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 206 |           List(Assign("temp",Var("minus2")),    //  temp := minus2;
 | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 207 |                Assign("minus2",Aop("+",Var("minus1"),Var("minus2"))), 
 | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 208 | // minus2 := minus1 + minus2; | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 209 |                Assign("minus1",Var("temp")), //  minus1 := temp;
 | 
| 
43c0ed473720
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
323diff
changeset | 210 |                Assign("n",Aop("-",Var("n"),Num(1))))), //  n := n - 1 };
 | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 211 |        Write("minus1"))                 //  write minus1
 | 
| 80 
191daa3ee29e
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
76diff
changeset | 212 | |
| 
191daa3ee29e
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
76diff
changeset | 213 | |
| 75 
898c25a4e399
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
74diff
changeset | 214 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 215 | // prints out the JVM-assembly program | 
| 80 
191daa3ee29e
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
76diff
changeset | 216 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 217 | println(compile(fib_test, "fib")) | 
| 80 
191daa3ee29e
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
76diff
changeset | 218 | |
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 219 | // can be assembled with | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 220 | // | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 221 | // java -jar jvm/jasmin-2.4/jasmin.jar fib.j | 
| 80 
191daa3ee29e
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
76diff
changeset | 222 | // | 
| 323 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 223 | // and started with | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 224 | // | 
| 
4ce07c4abdb4
updated
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
201diff
changeset | 225 | // java fib/fib | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 226 | |
| 471 | 227 | import scala.util._ | 
| 228 | import scala.sys.process._ | |
| 229 | import scala.io | |
| 230 | ||
| 231 | def compile_tofile(bl: Block, class_name: String) = {
 | |
| 232 | val output = compile(bl, class_name) | |
| 233 | val fw = new java.io.FileWriter(class_name + ".j") | |
| 234 | fw.write(output) | |
| 235 | fw.close() | |
| 236 | } | |
| 237 | ||
| 238 | def compile_and_run(bl: Block, class_name: String) : Unit = {
 | |
| 239 | compile_tofile(bl, class_name) | |
| 240 |   println("compiled ")
 | |
| 241 |   val test = ("java -jar jvm/jasmin-2.4/jasmin.jar " + class_name + ".j").!!
 | |
| 242 |   println("assembled ")
 | |
| 243 |   ("java " + class_name + "/" + class_name).!!
 | |
| 244 | } | |
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 245 | |
| 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 246 | |
| 471 | 247 | compile_and_run(fib_test, "fib") | 
| 76 
373cf55a3ca5
tuned
 Christian Urban <christian dot urban at kcl dot ac dot uk> parents: 
75diff
changeset | 248 |