diff -r fd894e017e12 -r 191daa3ee29e compile.scala --- a/compile.scala Sat Nov 24 15:10:43 2012 +0000 +++ b/compile.scala Mon Nov 26 01:11:55 2012 +0000 @@ -10,7 +10,7 @@ val NUM = PLUS(DIGIT) val KEYWORD = ALTS("skip", "while", "do", "if", "then", "else", "true", "false", "write") val SEMI: Rexp = ";" -val OP: Rexp = ALTS(":=", "=", "-", "+", "*", "!", "<", ">") +val OP: Rexp = ALTS(":=", "=", "-", "+", "*", "!=", "<", ">") val WHITESPACE = PLUS(RANGE(" \n")) val RPAREN: Rexp = ")" val LPAREN: Rexp = "(" @@ -65,7 +65,7 @@ case object True extends BExp case object False extends BExp -case class Bop(o: String, a1: AExp, a2: AExp) extends BExp +case class Relop(o: String, a1: AExp, a2: AExp) extends BExp // atomic parsers case class TokParser(tok: Token) extends Parser[List[Token], Token] { @@ -107,10 +107,10 @@ (T_KWD("true") ==> ((_) => True: BExp)) || (T_KWD("false") ==> ((_) => False: BExp)) || (T_LPAREN ~> BExp <~ T_RPAREN) || - (AExp ~ T_OP("=") ~ AExp) ==> { case ((x, y), z) => Bop("=", x, z): BExp } || - (AExp ~ T_OP("!=") ~ AExp) ==> { case ((x, y), z) => Bop("!=", x, z): BExp } || - (AExp ~ T_OP("<") ~ AExp) ==> { case ((x, y), z) => Bop("<", x, z): BExp } || - (AExp ~ T_OP(">") ~ AExp) ==> { case ((x, y), z) => Bop("<", z, x): BExp } + (AExp ~ T_OP("=") ~ AExp) ==> { case ((x, y), z) => Relop("=", x, z): BExp } || + (AExp ~ T_OP("!=") ~ AExp) ==> { case ((x, y), z) => Relop("!=", x, z): BExp } || + (AExp ~ T_OP("<") ~ AExp) ==> { case ((x, y), z) => Relop("<", x, z): BExp } || + (AExp ~ T_OP(">") ~ AExp) ==> { case ((x, y), z) => Relop("<", z, x): BExp } lazy val Stmt: Parser[List[Token], Stmt] = (T_KWD("skip") ==> ((_) => Skip: Stmt)) || @@ -128,9 +128,9 @@ (T_BEGIN ~> Stmts <~ T_END) || (Stmt ==> ((s) => List(s))) -// interpreter +// compiler val beginning = """ -.class public examples/HelloWorld +.class public XXX.XXX .super java/lang/Object .method public ()V @@ -172,8 +172,9 @@ } type Env = Map[String, String] +type Instrs = List[String] -def compile_aexp(a: AExp, env : Env) : List[String] = a match { +def compile_aexp(a: AExp, env : Env) : Instrs = a match { case Num(i) => List("ldc " + i.toString + "\n") case Var(s) => List("iload " + env(s) + "\n") case Aop("+", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("iadd\n") @@ -181,19 +182,24 @@ case Aop("*", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("imul\n") } -def compile_bexp(b: BExp, env : Env, jmp: String) : List[String] = b match { - case Bop("=", a1, a2) => +def compile_bexp(b: BExp, env : Env, jmp: String) : Instrs = b match { + case True => Nil + case False => List("goto " + jmp + "\n") + case Relop("=", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("if_icmpne " + jmp + "\n") - case Bop("<", a1, a2) => + case Relop("!=", a1, a2) => + compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("if_icmpeq " + jmp + "\n") + case Relop("<", a1, a2) => compile_aexp(a1, env) ++ compile_aexp(a2, env) ++ List("if_icmpge " + jmp + "\n") } -def compile_stmt(s: Stmt, env: Env) : (List[String], Env) = s match { +def compile_stmt(s: Stmt, env: Env) : (Instrs, Env) = s match { case Skip => (Nil, env) case Assign(x, a) => { val index = if (env.isDefinedAt(x)) env(x) else env.keys.size.toString - (compile_aexp(a, env) ++ List("istore " + index + "\n"), env + (x -> index)) + (compile_aexp(a, env) ++ + List("istore " + index + "\n"), env + (x -> index)) } case If(b, bl1, bl2) => { val if_else = Fresh("If_else") @@ -218,10 +224,10 @@ List("\n" + loop_end + ":\n\n"), env1) } case Write(x) => - (List("iload " + env(x) + "\n" + "invokestatic examples/HelloWorld/write(I)V\n"), env) + (List("iload " + env(x) + "\n" + "invokestatic XXX/XXX/write(I)V\n"), env) } -def compile_bl(bl: Block, env: Env) : (List[String], Env) = bl match { +def compile_bl(bl: Block, env: Env) : (Instrs, Env) = bl match { case Nil => (Nil, env) case s::bl => { val (instrs1, env1) = compile_stmt(s, env) @@ -230,18 +236,88 @@ } } -def compile(name: String) : String = { - val tks = Tok.fromFile(name) +def compile(input: String) : String = { + val class_name = input.split('.')(0) + val tks = Tok.fromFile(input) val ast = Stmts.parse_single(tks) val instructions = compile_bl(ast, Map.empty)._1 - beginning ++ instructions.mkString ++ ending + (beginning ++ instructions.mkString ++ ending).replaceAllLiterally("XXX", class_name) } +def compile_to(input: String, output: String) = { + val fw = new java.io.FileWriter(output) + fw.write(compile(input)) + fw.close() +} + +// +val tks = Tok.fromString("x := x + 1") +val ast = Stmt.parse_single(tks) +println(compile_stmt(ast, Map("x" -> "n"))._1.mkString) + + + //examples -println(compile("loops.while")) -//println(compile("fib.while")) +//compile_to("loops.while", "loops.j") +//compile_to("fib.while", "fib.j") + + +// testing cases for time measurements + +def time_needed[T](i: Int, code: => T) = { + val start = System.nanoTime() + for (j <- 1 to i) code + val end = System.nanoTime() + (end - start)/(i * 1.0e9) +} + +// for testing +import scala.sys.process._ + +val test_prog = """ +start := XXX; +x := start; +y := start; +z := start; +while 0 < x do { + while 0 < y do { + while 0 < z do { + z := z - 1 + }; + z := start; + y := y - 1 + }; + y := start; + x := x - 1 +}; +write x; +write y; +write z +""" + + +def compile_test(n: Int) : Unit = { + val class_name = "LOOP" + val tks = Tok.fromString(test_prog.replaceAllLiterally("XXX", n.toString)) + val ast = Stmts.parse_single(tks) + val instructions = compile_bl(ast, Map.empty)._1 + val assembly = (beginning ++ instructions.mkString ++ ending).replaceAllLiterally("XXX", class_name) + val fw = new java.io.FileWriter(class_name + ".j") + fw.write(assembly) + fw.close() + val test = ("java -jar jvm/jasmin-2.4/jasmin.jar " + class_name + ".j").!! + println(n + " " + time_needed(2, ("java " + class_name + "/" + class_name).!!)) +} + +List(1, 5000, 10000, 50000, 100000, 250000, 500000, 750000, 1000000).map(compile_test(_)) + + + +// javabyte code assmbler +// +// java -jar jvm/jasmin-2.4/jasmin.jar loops.j @@ -249,5 +325,3 @@ - -