You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
311 lines
9.0 KiB
311 lines
9.0 KiB
package project2
|
|
|
|
import scala.collection.mutable.HashMap
|
|
|
|
/*
|
|
* This compiler generates Scala-like code that computes the
|
|
* result of a given AST.
|
|
*/
|
|
abstract class StackCompiler extends BugReporter with Codegen {
|
|
import Language._
|
|
|
|
type Loc = Int
|
|
|
|
// Pretty printing
|
|
var nTab = 0
|
|
def emitln(msg: String): Unit = emitln(msg, nTab)
|
|
|
|
/**
|
|
* Env of the compiler. Keeps track of the location
|
|
* in memory of each variable defined.
|
|
*/
|
|
class Env {
|
|
def undef(name: String) = BUG(s"Undefined identifier $name (should have been found during the semantic analysis)")
|
|
|
|
def apply(name: String): Loc = undef(name)
|
|
}
|
|
|
|
case class LocationEnv(
|
|
vars: Map[String, Loc] = Map.empty,
|
|
outer: Env = new Env) extends Env {
|
|
|
|
/*
|
|
* Return a copy of the current state plus a
|
|
* variable 'name' at the location 'loc'
|
|
*/
|
|
def withVal(name: String, loc: Loc): LocationEnv = {
|
|
copy(vars = vars + (name -> loc))
|
|
}
|
|
|
|
/*
|
|
* Return the location of the variable 'name'
|
|
*/
|
|
override def apply(name: String): Loc = vars.get(name) match {
|
|
case Some(loc) => loc
|
|
case _ =>outer(name)
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Generate code that computes the unary operator
|
|
* 'op' on the value at memory location 'sp' and that
|
|
* stores the result at 'sp'.
|
|
*/
|
|
def transUn(op: String)(sp: Loc) = op match {
|
|
case "-" => emitln(s"memory($sp) = -memory($sp)")
|
|
case "+" => ()
|
|
}
|
|
|
|
/*
|
|
* Generate code that computes the binary operator
|
|
* 'op' on the values at memory location 'sp' and
|
|
* 'sp1' and that stores the result at 'sp'.
|
|
*/
|
|
def transBin(op: String)(sp: Loc, sp1: Loc) = op match {
|
|
case "-" => emitln(s"memory($sp) -= memory($sp1)")
|
|
case "+" => emitln(s"memory($sp) += memory($sp1)")
|
|
case "*" => emitln(s"memory($sp) *= memory($sp1)")
|
|
case "/" => emitln(s"memory($sp) /= memory($sp1)")
|
|
case "%" => emitln(s"memory($sp) %= memory($sp1)")
|
|
}
|
|
|
|
/*
|
|
* Generate code that computes the binary operator
|
|
* 'op' on the values at memory location 'sp' and
|
|
* 'sp1' and that stores the result in 'flag'.
|
|
*/
|
|
def transCond(op: String)(sp: Loc, sp1: Loc) = op match {
|
|
case "==" => emitln(s"flag = (memory($sp) == memory($sp1))")
|
|
case "!=" => emitln(s"flag = (memory($sp) != memory($sp1))")
|
|
case "<=" => emitln(s"flag = (memory($sp) <= memory($sp1))")
|
|
case ">=" => emitln(s"flag = (memory($sp) >= memory($sp1))")
|
|
case "<" => emitln(s"flag = (memory($sp) < memory($sp1))")
|
|
case ">" => emitln(s"flag = (memory($sp) > memory($sp1))")
|
|
}
|
|
|
|
/*
|
|
* Generate code that computesS the result of the
|
|
* computation represented by the AST 'exp'.
|
|
*/
|
|
def emitCode(exp: Exp): Unit = {
|
|
emitln("type Val = Int")
|
|
emitln("val memory = new Array[Val](1000)")
|
|
emitln("var flag = true")
|
|
trans(exp, 0)(LocationEnv())
|
|
emitln(s"memory(0)")
|
|
}
|
|
|
|
/*
|
|
* Generate code that computes the result of the
|
|
* computation represented by the AST 'exp'. The
|
|
* value will be placed at memory location 'sp'
|
|
*/
|
|
def trans(exp: Exp, sp: Loc)(env: LocationEnv): Unit = exp match {
|
|
case Lit(x) =>
|
|
emitln(s"memory($sp) = $x")
|
|
case Unary(op, v) =>
|
|
trans(v, sp)(env)
|
|
transUn(op)(sp)
|
|
case Prim(op, lop, rop) =>
|
|
trans(lop, sp)(env)
|
|
trans(rop, sp + 1)(env)
|
|
transBin(op)(sp, sp + 1)
|
|
case Let(x, a, b) =>
|
|
trans(a, sp)(env)
|
|
trans(b, sp + 1)(env.withVal(x, sp))
|
|
emitln(s"memory($sp) = memory(${sp + 1})")
|
|
case Ref(x) =>
|
|
emitln(s"memory($sp) = memory(${env(x)})")
|
|
case Cond(op, l, r) =>
|
|
trans(l, sp)(env)
|
|
trans(r, sp+1)(env)
|
|
transCond(op)(sp, sp + 1)
|
|
case If(cond, tBranch, eBranch) =>
|
|
trans(cond, sp)(env) // Set flag value
|
|
emitln(s"if (flag) {")
|
|
nTab += 1
|
|
trans(tBranch, sp)(env)
|
|
nTab -= 1
|
|
emitln("} else {")
|
|
nTab += 1
|
|
trans(eBranch, sp)(env)
|
|
nTab -= 1
|
|
emitln("}")
|
|
case VarDec(x, rhs, body) =>
|
|
trans(rhs, sp)(env)
|
|
trans(body, sp + 1)(env.withVal(x, sp))
|
|
emitln(s"memory($sp) = memory(${sp + 1})")
|
|
case VarAssign(x, rhs) =>
|
|
trans(rhs, sp)(env)
|
|
emitln(s"memory(${env(x)}) = memory($sp)")
|
|
case While(cond, lBody, body) =>
|
|
trans(cond, sp)(env)
|
|
emitln(s"while (flag) {")
|
|
nTab += 1
|
|
trans(lBody, sp)(env)
|
|
trans(cond, sp)(env)
|
|
nTab -= 1
|
|
emitln(s"}")
|
|
trans(body, sp)(env)
|
|
}
|
|
|
|
}
|
|
|
|
abstract class X86Compiler extends BugReporter with Codegen {
|
|
import Language._
|
|
|
|
type Loc = Int
|
|
type PhyLoc = String
|
|
|
|
/**
|
|
* Env of the compiler. Keep track of the location
|
|
* in memory of each variable defined.
|
|
*/
|
|
private class Env {
|
|
def undef(name: String) = BUG(s"Undefined identifier $name (should have been found during the semantic analysis)")
|
|
|
|
def apply(name: String): Loc = undef(name)
|
|
}
|
|
|
|
private case class LocationEnv(
|
|
vars: Map[String, Loc] = Map.empty,
|
|
outer: Env = new Env) extends Env {
|
|
|
|
/*
|
|
* Return a copy of the current state plus a
|
|
* variable 'name' at the location 'loc'
|
|
*/
|
|
def withVal(name: String, loc: Loc): LocationEnv = {
|
|
copy(vars = vars + (name -> loc))
|
|
}
|
|
|
|
/*
|
|
* Return the location of the variable 'name'
|
|
*/
|
|
override def apply(name: String): Loc = vars.get(name) match {
|
|
case Some(loc) => loc
|
|
case _ => outer(name)
|
|
}
|
|
}
|
|
|
|
// List of available register.
|
|
val regs = Seq("%rbx", "%rcx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15")
|
|
|
|
/*
|
|
* Generate code that computes the unary operator
|
|
* 'op' on the value at memory location 'sp' and that
|
|
* stores the result at 'sp'.
|
|
*
|
|
* TODO: Fill in transUn with the appropriate code.
|
|
*/
|
|
def transUn(op: String)(sp: Loc) = op match {
|
|
case "-" => emitln(s"neg ${regs(sp)}")
|
|
case "+" => ()
|
|
case _ => BUG(s"Unary operator $op undefined")
|
|
}
|
|
|
|
/*
|
|
* Generate code that computes the binary operator
|
|
* 'op' on the values at memory location 'sp' and
|
|
* 'sp1' and that stores the result at 'sp'.
|
|
*/
|
|
def transBin(op: String)(sp: Loc, sp1: Loc) = op match {
|
|
case "+" => emitln(s"addq ${regs(sp1)}, ${regs(sp)}")
|
|
case "-" => emitln(s"subq ${regs(sp1)}, ${regs(sp)}")
|
|
case "*" => emitln(s"imulq ${regs(sp1)}, ${regs(sp)}")
|
|
case "/" =>
|
|
emitln(s"movq ${regs(sp)}, %rax")
|
|
emitln(s"cqto")
|
|
emitln(s"idiv ${regs(sp1)}")
|
|
emitln(s"movq %rax, ${regs(sp)}")
|
|
case _ => BUG(s"Binary operator $op undefined")
|
|
}
|
|
|
|
type Label = String
|
|
|
|
var nLabel = 0
|
|
def freshLabel(pref: String) = { nLabel += 1; s"$pref$nLabel" }
|
|
|
|
|
|
/*
|
|
* Generate code that jumps to the label 'label'
|
|
* if the CPU flags are verifying the operator
|
|
* 'op'
|
|
* NOTE: The flags will need to be set before.
|
|
*/
|
|
def transJumpIf(op: String)(label: Label) = {
|
|
op match {
|
|
case "==" => emitln(s"je $label")
|
|
case "!=" => emitln(s"jne $label")
|
|
case "<=" => emitln(s"jle $label")
|
|
case ">=" => emitln(s"jge $label")
|
|
case "<" => emitln(s"jl $label")
|
|
case ">" => emitln(s"jg $label")
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Generate code that compute the result of the
|
|
* computation represented by the AST 'exp'.
|
|
*/
|
|
def emitCode(exp: Exp): Unit = {
|
|
trans(exp, 0)(LocationEnv())
|
|
emitln(s"movq ${regs(0)}, %rax")
|
|
}
|
|
|
|
/*
|
|
* Generate code that compute the result og the
|
|
* computation represented by the AST 'exp'. The
|
|
* value will be placed at memory location 'sp'
|
|
*
|
|
* TODO: Fill in each () with the appropriate code.
|
|
*/
|
|
def trans(exp: Exp, sp: Loc)(env: LocationEnv): Unit = exp match {
|
|
case Lit(x) =>
|
|
emitln(s"movq $$$x, ${regs(sp)}")
|
|
case Unary(op, v) =>
|
|
trans(v, sp)(env)
|
|
transUn(op)(sp)
|
|
case Prim(op, lop, rop) =>
|
|
trans(lop, sp)(env)
|
|
trans(rop, sp + 1)(env)
|
|
transBin(op)(sp, sp + 1)
|
|
case Let(x, a, b) =>
|
|
trans(a, sp)(env)
|
|
trans(b, sp + 1)(env.withVal(x, sp))
|
|
emitln(s"movq ${regs(sp + 1)}, ${regs(sp)}")
|
|
case Ref(x) =>
|
|
emitln(s"movq ${regs(env.apply(x))}, ${regs(sp)}")
|
|
case Cond(op, l, r) =>
|
|
trans(l, sp)(env)
|
|
trans(r, sp + 1)(env)
|
|
emitln(s"cmpq ${regs(sp + 1)}, ${regs(sp)}")
|
|
case If(cond, tBranch, eBranch) =>
|
|
trans(cond, sp)(env)
|
|
val lab = freshLabel("if")
|
|
transJumpIf(cond.op)(lab)
|
|
trans(eBranch, sp)(env)
|
|
emitln(s"jmp ${lab}_skip")
|
|
emitln(s"${lab}:", 0)
|
|
trans(tBranch, sp)(env)
|
|
emitln(s"${lab}_skip:", 0)
|
|
case VarDec(x, rhs, body) =>
|
|
trans(rhs, sp)(env)
|
|
trans(body, sp + 1)(env.withVal(x, sp))
|
|
emitln(s"movq ${regs(sp + 1)}, ${regs(sp)}")
|
|
case VarAssign(x, rhs) =>
|
|
trans(rhs, sp)(env)
|
|
emitln(s"movq ${regs(sp)}, ${regs(env.apply(x))}")
|
|
case While(cond, lBody, body) =>
|
|
val lab = freshLabel("loop")
|
|
emitln(s"jmp ${lab}_cond")
|
|
emitln(s"${lab}_body:", 0)
|
|
trans(lBody, sp)(env)
|
|
emitln(s"${lab}_cond:", 0)
|
|
trans(cond, sp)(env)
|
|
transJumpIf(cond.op)(s"${lab}_body")
|
|
trans(body, sp)(env)
|
|
// TODO: continue ... Done
|
|
}
|
|
}
|