// compiles Abacus programs directly to Javabyte code
import scala.sys.process._
import lib._
import abacus._
import recs._
import comp2._
def compile_aprog(p: AProg) : String = {
def compile_inst(i: AInst, l: Int) : List[String] = {
("L" + l.toString + ":") :: (i match {
case Inc(n) => List("iinc " + n.toString + " 1")
case Dec(n, l) => List("iload " + n.toString, "ifeq L" + l.toString, "iinc " + n.toString + " -1")
case Goto(l) => List("goto L" + l.toString)
})
}
val code = for ((i, l) <- p.zipWithIndex)
yield compile_inst(i, l).mkString("", "\n", "\n")
code.mkString
}
def init_regs(ns: List[Int]) : String = {
val code = for ((n, i) <- ns.zipWithIndex)
yield List("bipush " + n.toString, "istore " + i.toString).mkString("", "\n", "\n")
code.mkString
}
def print_result(l: Int, r: Int, class_name: String) : String = {
List("L" + l.toString + ":",
"iload " + r.toString,
"invokestatic " + class_name + "/" + class_name + "/write(I)V").mkString("", "\n", "\n")
}
// compiler preludes
def beginning(class_name: String) : String = {
"\n.class public " + class_name + "." + class_name + """
.super java/lang/Object
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static write(I)V
.limit locals 5
.limit stack 5
iload 0
getstatic java/lang/System/out Ljava/io/PrintStream;
swap
invokevirtual java/io/PrintStream/println(I)V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit locals 200
.limit stack 200
""" }
val ending = """
return
.end method
"""
def compile(f: Rec, ns: List[Int]) : Unit = {
val class_name = "Prog" + ns.mkString // name of the class and program
val (aprog, res, max) = compile_rec(f)
val init_code = init_regs(ns.padTo(max, 0)) // initialising registers with input data
val main_code = compile_aprog(aprog.p)
val end_code = print_result(aprog.p.length, res, class_name)
val code = beginning(class_name) + init_code + main_code + end_code + ending
val fw = new java.io.FileWriter(class_name + ".j") // temporary file
fw.write(code)
fw.close()
val _ = ("java -jar jvm/jasmin-2.4/jasmin.jar " + class_name + ".j").!!
val start = System.nanoTime()
val result = ("java " + class_name + "/" + class_name).!!
val end = System.nanoTime()
println("Result: " + result + " Time: " + (end - start) / 1.0e9)
}
print("Add(69, 30) "); compile(Add, List(69, 30))
print("Mult(13, 9) "); compile(recs.Mult, List(13, 9))
print("Power(3, 4) "); compile(Power, List(3, 4))
print("Strt: "); compile(Strt(2), List(2,3))
println("FACTORIAL")
for (i <- 7 to 9) {
println("Input: " + i)
compile(Fact, List(i))
}
println("PRIME TEST")
for (i <- 10 to 20) {
println("Input: " + i)
compile(Prime, List(i))
}