master
bill 1 year ago
parent acf15f81fe
commit ebae52c4df

10
proj3/.gitignore vendored

@ -0,0 +1,10 @@
.vscode
.DS_Store
.bloop
.metals
**/target
**/.bloop
**/.metals
gen/*
!gen/bootstrap.c
metals.*

@ -52,7 +52,9 @@ abstract class X86Compiler extends BugReporter with Codegen {
*/ */
val primitives = Map( val primitives = Map(
"putchar" -> Func("putchar"), "putchar" -> Func("putchar"),
"getchar" -> Func("getchar")) "getchar" -> Func("getchar"),
"toInt" -> Func("toInt"),
"toChar" -> Func("toChar"))
private class Env { private class Env {
def undef(name: String) = BUG(s"Undefined identifier $name (should have been found during the semantic analysis)") def undef(name: String) = BUG(s"Undefined identifier $name (should have been found during the semantic analysis)")
@ -124,6 +126,28 @@ abstract class X86Compiler extends BugReporter with Codegen {
emitln(s"cmp ${loc(sp1)}, ${loc(sp)}") emitln(s"cmp ${loc(sp1)}, ${loc(sp)}")
emitln(s"sete %al") emitln(s"sete %al")
emitln(s"movzbq %al, ${loc(sp)}") emitln(s"movzbq %al, ${loc(sp)}")
case "!=" =>
emitln(s"cmp ${loc(sp1)}, ${loc(sp)}")
emitln(s"setne %al")
emitln(s"movzbq %al, ${loc(sp)}")
case ">=" =>
emitln(s"cmp ${loc(sp1)}, ${loc(sp)}")
emitln(s"setge %al")
emitln(s"movzbq %al, ${loc(sp)}")
case ">" =>
emitln(s"cmp ${loc(sp1)}, ${loc(sp)}")
emitln(s"setg %al")
emitln(s"movzbq %al, ${loc(sp)}")
case "<=" =>
emitln(s"cmp ${loc(sp1)}, ${loc(sp)}")
emitln(s"setle %al")
emitln(s"movzbq %al, ${loc(sp)}")
case "<" =>
emitln(s"cmp ${loc(sp1)}, ${loc(sp)}")
emitln(s"setl %al")
emitln(s"movzbq %al, ${loc(sp)}")
case "block-get" =>
emitln(s"movq (${loc(sp)}, ${loc(sp1)}, 8), ${loc(sp)}")
case _ => BUG(s"Binary operator $op undefined") case _ => BUG(s"Binary operator $op undefined")
} }
@ -136,6 +160,9 @@ abstract class X86Compiler extends BugReporter with Codegen {
* Valid operators: block-set * Valid operators: block-set
*/ */
def transTer(op: String)(sp: Loc, sp1: Loc, sp2: Loc) = op match { def transTer(op: String)(sp: Loc, sp1: Loc, sp2: Loc) = op match {
case "block-set" =>
emitln(s"movq ${loc(sp2)}, (${loc(sp)}, ${loc(sp1)}, 8)")
emitln(s"movq ${loc(sp2)}, ${loc(sp)}") // returns rhs
case _ => BUG(s"ternary operator $op undefined") case _ => BUG(s"ternary operator $op undefined")
} }
@ -173,7 +200,9 @@ abstract class X86Compiler extends BugReporter with Codegen {
* if the location 'sp' contains the value 'true' * if the location 'sp' contains the value 'true'
*/ */
def transJumpIfTrue(sp: Loc)(label: Label) = { def transJumpIfTrue(sp: Loc)(label: Label) = {
??? emitln(s"movq $$1, ${loc(sp + 1)}")
emitln(s"cmp ${loc(sp)}, ${loc(sp + 1)}")
emitln(s"je $label")
} }
/* /*
@ -188,7 +217,13 @@ abstract class X86Compiler extends BugReporter with Codegen {
def trans(exp: Exp, sp: Loc)(env: LocationEnv): Unit = exp match { def trans(exp: Exp, sp: Loc)(env: LocationEnv): Unit = exp match {
case Lit(x: Int) => case Lit(x: Int) =>
emitln(s"movq $$$x, ${loc(sp)}") emitln(s"movq $$$x, ${loc(sp)}")
case Lit(b: Boolean) => () // TODO case Lit(x: Char) =>
emitln(s"movq $$${x.toInt}, ${loc(sp)}")
case Lit(b: Boolean) => // TODO
if(b)
emitln(s"movq $$1, ${loc(sp)}")
else
emitln(s"movq $$0, ${loc(sp)}")
case Lit(x: Unit) => () // TODO case Lit(x: Unit) => () // TODO
case Prim(op, args) => case Prim(op, args) =>
val idxs = List.tabulate(args.length)(i => sp + i) val idxs = List.tabulate(args.length)(i => sp + i)
@ -205,7 +240,7 @@ abstract class X86Compiler extends BugReporter with Codegen {
case Ref(x) => case Ref(x) =>
env(x) match { env(x) match {
case Reg(sp1) => emitln(s"movq ${loc(sp1)}, ${loc(sp)}") case Reg(sp1) => emitln(s"movq ${loc(sp1)}, ${loc(sp)}")
case Func(name) => ??? // Extra credit case Func(name) => emitln(s"leaq ${funcName(name)}(%rip), ${loc(sp)}") // Extra credit
} }
case If(cond, tBranch, eBranch) => case If(cond, tBranch, eBranch) =>
val lab = freshLabel("if") val lab = freshLabel("if")
@ -233,12 +268,24 @@ abstract class X86Compiler extends BugReporter with Codegen {
transJumpIfTrue(sp)(s"${lab}_body") transJumpIfTrue(sp)(s"${lab}_body")
trans(body, sp)(env) trans(body, sp)(env)
case LetRec(funs, body) => case LetRec(funs, body) =>
emitln(s"${funcName("toInt")}:", 0)
emitln(s"movzbq %dil, %rax")
emitln(s"ret\n")
emitln(s"${funcName("toChar")}:", 0)
emitln(s"movzbq %dil, %rax")
emitln("ret\n")
emitln("################# FUNCTIONS #####################", 0) emitln("################# FUNCTIONS #####################", 0)
// We do not save the location of the function into register because we can use their // We do not save the location of the function into register because we can use their
// name as a label. // name as a label.
val funsLoc = funs map { case FunDef(name, _, _, _) => (name, Func(name)) } val funsLoc = funs map { case FunDef(name, _, _, _) => (name, Func(name)) }
// TODO complete the code // TODO complete the code
funs map {
case func@FunDef(_, _, _, _) =>
trans(func, Reg(0))(env.withVals(funsLoc))
}
emitln("#################################################\n\n", 0) emitln("#################################################\n\n", 0)
emitln("###################### MAIN #####################", 0) emitln("###################### MAIN #####################", 0)
@ -257,7 +304,8 @@ abstract class X86Compiler extends BugReporter with Codegen {
// emit the main function (body of LetRec) here // emit the main function (body of LetRec) here
// TODO you may need to change that code. // TODO you may need to change that code.
trans(body, Reg(0))(LocationEnv()) trans(body, Reg(0))(LocationEnv().withVals(funsLoc))
emitln(s"movq ${loc(0)}, %rax") emitln(s"movq ${loc(0)}, %rax")
//////////// DO NOT CHANGE//////////////// //////////// DO NOT CHANGE////////////////
@ -280,6 +328,10 @@ abstract class X86Compiler extends BugReporter with Codegen {
////////////////////////////////////////// //////////////////////////////////////////
// TODO // TODO
val ids = (0 until args.length).toList
val arg_regs = (args zip ids) map {case (Arg(fname, _, _), idx) => (fname, sp + idx)}
trans(fbody, sp + args.length)(env.withVals(arg_regs))
emitln(s"movq ${loc(sp + args.length)}, %rax")
//////////// DO NOT CHANGE//////////////// //////////// DO NOT CHANGE////////////////
emitln("movq %rbp, %rsp\t# reset frame") emitln("movq %rbp, %rsp\t# reset frame")
@ -292,27 +344,51 @@ abstract class X86Compiler extends BugReporter with Codegen {
// code and work on multiple arguments. // code and work on multiple arguments.
// Evaluate the arguments // Evaluate the arguments
// TODO // TODO
val ids = (0 until args.length).toList
(args zip ids) map {case (arg, idx) => trans(arg, sp + idx)(env)}
// Compute the physical location of the function to be called // Compute the physical location of the function to be called
val fLoc: String = fun match { val fLoc: String = fun match {
case Ref(fname) => case Ref(fname) =>
env(fname) match { env(fname) match {
case Reg(sp) => ??? // Extra credit case Reg(sp) => s"*${loc(sp)}" // Extra credit
case Func(name) => "" // TODO case Func(name) => funcName(name) // TODO
} }
case _ => ??? // Extra credit case _ => // return from another invocation
trans(fun, sp)(env);
s"*${loc(sp)}"
} }
// Implement the calling conventions after that point // Implement the calling conventions after that point
// and generate the function call // and generate the function call
// TODO // TODO
() val spID : Int = sp match {
case Reg(i) => i
}
for(i <- 0 to spID){
emitln(s"pushq ${loc(i)}");
}
for(i <- 0 to spID) {
emitln(s"movq ${loc(sp + i)}, ${loc(i)}")
}
emitln(s"call ${fLoc}")
for(i <- spID to 0 by -1) {
emitln(s"popq ${loc(i)}");
}
emitln(s"movq %rax, ${loc(sp)}")
case ArrayDec(size, _) => case ArrayDec(size, _) =>
// This node needs to allocate an area of eval(size) * 8 bytes in the heap // This node needs to allocate an area of eval(size) * 8 bytes in the heap
// the assembly variable "heap" contains a pointer to the first valid byte // the assembly variable "heap" contains a pointer to the first valid byte
// in the heap. Make sure to update its value accordingly. // in the heap. Make sure to update its value accordingly.
// TODO // TODO
() emitln(s"movq (%rip), ${loc(sp)}")
trans(size, sp + 1)(env)
emitln(s"movq (%rip), ${loc(sp + 2)}")
emitln(s"movq (${loc(sp + 2)}, ${loc(sp + 1)}, 8), ${loc(sp + 2)}")
emitln(s"movq ${loc(sp + 2)}, %rip")
case _ => BUG(s"don't know how to implement $exp") case _ => BUG(s"don't know how to implement $exp")
} }
} }

@ -19,7 +19,9 @@ class ValueInterpreter extends Interpreter with BugReporter {
*/ */
val primitives = Map[String, BoxedVal]( val primitives = Map[String, BoxedVal](
"putchar" -> BoxedVal(Primitive("putchar")), "putchar" -> BoxedVal(Primitive("putchar")),
"getchar" -> BoxedVal(Primitive("getchar")) "getchar" -> BoxedVal(Primitive("getchar")),
"toInt" -> BoxedVal(Primitive("toInt")),
"toChar" -> BoxedVal(Primitive("toChar"))
) )
/* /*
@ -204,6 +206,12 @@ class ValueInterpreter extends Interpreter with BugReporter {
Console.out.write(c) Console.out.write(c)
Console.out.flush Console.out.flush
Cst(()) Cst(())
case Primitive("toInt") =>
val List(Cst(c: Char)) = eargs
Cst(c.toInt)
case Primitive("toChar") =>
val List(Cst(c: Int)) = eargs
Cst(c.toChar)
} }
case ArrayDec(size, _) => case ArrayDec(size, _) =>
val Cst(s: Int) = eval(size)(env) val Cst(s: Int) = eval(size)(env)
@ -225,7 +233,9 @@ object StackVal extends BugReporter {
*/ */
val primitives = Map[String, Loc]( val primitives = Map[String, Loc](
"putchar" -> 0, "putchar" -> 0,
"getchar" -> 1 "getchar" -> 1,
"toInt" -> 2,
"toChar" -> 3
) )
/** /**
@ -303,6 +313,8 @@ class StackInterpreter extends Interpreter with BugReporter {
val memory = new Array[Val](1000) val memory = new Array[Val](1000)
memory(0) = Primitive("putchar") memory(0) = Primitive("putchar")
memory(1) = Primitive("getchar") memory(1) = Primitive("getchar")
memory(2) = Primitive("toInt")
memory(3) = Primitive("toChar")
var flag: Boolean = true var flag: Boolean = true
/* /*
@ -332,12 +344,15 @@ class StackInterpreter extends Interpreter with BugReporter {
case (">=", Cst(x: Int), Cst(y: Int)) => memory(sp) = Cst(x >= y) case (">=", Cst(x: Int), Cst(y: Int)) => memory(sp) = Cst(x >= y)
case ("<" , Cst(x: Int), Cst(y: Int)) => memory(sp) = Cst(x < y) case ("<" , Cst(x: Int), Cst(y: Int)) => memory(sp) = Cst(x < y)
case (">" , Cst(x: Int), Cst(y: Int)) => memory(sp) = Cst(x > y) case (">" , Cst(x: Int), Cst(y: Int)) => memory(sp) = Cst(x > y)
case ("block-get", Cst(arr: Array[Any]), Cst(i: Int)) => ??? case ("block-get", Cst(arr: Array[Any]), Cst(i: Int)) =>
if (arr(i) == null)
BUG(s"uninitialized memory")
memory(sp) = Cst(arr(i))
case _ => BUG(s"Binary operator $op undefined") case _ => BUG(s"Binary operator $op undefined")
} }
def evalTer(op: String)(sp: Loc, sp1: Loc, sp2: Loc) = (op, memory(sp), memory(sp1), memory(sp2)) match { def evalTer(op: String)(sp: Loc, sp1: Loc, sp2: Loc) = (op, memory(sp), memory(sp1), memory(sp2)) match {
case ("block-set", Cst(arr: Array[Any]), Cst(i: Int), Cst(x)) => ??? case ("block-set", Cst(arr: Array[Any]), Cst(i: Int), Cst(x)) => memory(sp) = Cst(arr(i) = x)
case _ => BUG(s"ternary operator $op undefined") case _ => BUG(s"ternary operator $op undefined")
} }
@ -353,9 +368,9 @@ class StackInterpreter extends Interpreter with BugReporter {
* an empty environment and return the value. * an empty environment and return the value.
*/ */
def run(exp: Exp): Val = { def run(exp: Exp): Val = {
// Start at 2, putchar and getchar are store at 0 and 1!! // Start at 4, putchar, getchar, toChar, toInt are store at 0 and 1, 2, 3!!
eval(exp, 2)(LocationEnv()) eval(exp, 4)(LocationEnv())
memory(2) memory(4)
} }
/* /*
@ -405,11 +420,47 @@ class StackInterpreter extends Interpreter with BugReporter {
eval(cond, sp)(env) eval(cond, sp)(env)
} }
eval(body, sp)(env) eval(body, sp)(env)
case FunDef(_, args, _, fbody) => ??? case FunDef(_, args, _, fbody) =>
memory(sp) = Func(args map { arg => (arg.name) }, fbody, env)
case LetRec(funs, body) => case LetRec(funs, body) =>
// TODO modify that code // TODO modify that code
eval(body, sp)(env) val ids = (sp until sp + funs.length).toList
case App(fun, args) => ??? // Evaluate all functions
case ArrayDec(size, _) => ??? val funcs = (funs zip ids) map { case (fun@FunDef(name, _, _, _), idx) => (name, idx) }
// Add all functions to the functions environment (recursion)
(funs zip ids) foreach { case (fun@FunDef(_, _, _, _), idx:Int) => eval(fun, idx)(env.withVals(funcs)) }
eval(body, sp + funs.length)(env.withVals(funcs))
memory(sp) = memory(sp + funs.length)
case App(fun, args) =>
val ids = (sp until sp + args.length).toList
(args zip ids) map { case (arg, idx) => eval(arg, idx)(env) }
eval(fun, sp + args.length)(env)
memory(sp + args.length) match {
case Func(fargs, fbody, fenv) =>
eval(fbody, sp + args.length + 1)(fenv.withVals(fargs zip ids))
memory(sp) = memory(sp + args.length + 1)
case Primitive("getchar") =>
memory(sp) = Cst(Console.in.read)
case Primitive("putchar") =>
val List(Cst(c: Int)) = memory(sp)
Console.out.write(c)
Console.out.flush
Cst(())
case Primitive("toInt") =>
val List(Cst(c: Char)) = memory(sp)
memory(sp) = Cst(c.toInt)
case Primitive("toChar") =>
val List(Cst(c: Int)) = memory(sp)
memory(sp) = Cst(c.toChar)
}
case ArrayDec(size, _) =>
eval(size, sp)(env)
val Cst(idx: Int) = memory(sp)
memory(sp) = Cst(new Array[Any](idx))
} }
} }

@ -41,7 +41,6 @@ OPTION: intStack""")
} else { } else {
args(0) args(0)
} }
println("============ SRC CODE ============") println("============ SRC CODE ============")
println(src) println(src)
println("==================================\n") println("==================================\n")
@ -51,7 +50,7 @@ OPTION: intStack""")
// Parser to test! // Parser to test!
// TODO: Change this as you finish parsers // TODO: Change this as you finish parsers
val parser = new BaseParser(scanner) val parser = new ArrayParser(scanner)
val ast = try { val ast = try {
parser.parseCode parser.parseCode
} catch { } catch {

@ -99,11 +99,11 @@ class Scanner(in: Reader[Char]) extends Reader[Tokens.Token] with Reporter {
// List of delimiters // List of delimiters
// TODO: Update this as delimiters are added to our language // TODO: Update this as delimiters are added to our language
val isDelim = Set('(',')','=',';','{','}',':') val isDelim = Set('(',')','=',';','{','}',':', ',', '[', ']')
// List of keywords // List of keywords
// TODO: Update this as keywords are added to our language // TODO: Update this as keywords are added to our language
val isKeyword = Set("if", "else", "val", "var", "while") val isKeyword = Set("if", "else", "val", "var", "while", "def", "=>", "new")
val isBoolean = Set("true", "false") val isBoolean = Set("true", "false")
@ -119,7 +119,7 @@ class Scanner(in: Reader[Char]) extends Reader[Tokens.Token] with Reporter {
} }
val s = buf.toString val s = buf.toString
if (isKeyword(s)) Keyword(s) if (isKeyword(s)) Keyword(s)
else if (isBoolean(s)) Boolean(s) else if (isBoolean(s)) Literal(s.toBoolean)
else Ident(s) else Ident(s)
} }
@ -169,6 +169,12 @@ class Scanner(in: Reader[Char]) extends Reader[Tokens.Token] with Reporter {
getOperator() getOperator()
} else if (in.hasNext(isDigit)) { } else if (in.hasNext(isDigit)) {
getNum() getNum()
} else if (in.hasNext(Set('\''))) {
in.next()
val s = in.next()
if (in.hasNext(_ == '\'')) in.next()
else expected(s"\'")
Literal(s)
} else if (in.hasNext(isDelim)) { } else if (in.hasNext(isDelim)) {
Delim(in.next()) Delim(in.next())
} else if (!in.hasNext) { } else if (!in.hasNext) {
@ -372,6 +378,7 @@ object Language {
case class ArrayType(tp: Type) extends Type case class ArrayType(tp: Type) extends Type
val IntType = BaseType("Int") val IntType = BaseType("Int")
val CharType = BaseType("Char")
val UnitType = BaseType("Unit") val UnitType = BaseType("Unit")
val BooleanType = BaseType("Boolean") val BooleanType = BaseType("Boolean")
@ -448,6 +455,18 @@ class BaseParser(in: Scanner) extends Parser(in) {
* TODO: Implement this function * TODO: Implement this function
*/ */
def parseType: Type = in.peek match { def parseType: Type = in.peek match {
case Ident("Int") =>
in.next()
IntType
case Ident("Char") =>
in.next()
CharType
case Ident("Boolean") =>
in.next()
BooleanType
case Ident("Unit") =>
in.next()
UnitType
case _ => expected("type") case _ => expected("type")
} }
@ -460,6 +479,9 @@ class BaseParser(in: Scanner) extends Parser(in) {
* TODO: Implement this function * TODO: Implement this function
*/ */
def parseOptionalType: Type = in.peek match { def parseOptionalType: Type = in.peek match {
case Delim(':') =>
in.next()
parseType
case _ => UnknownType case _ => UnknownType
} }
@ -626,14 +648,37 @@ class SyntacticSugarParser(in: Scanner) extends BaseParser(in) {
suf + "$" + next suf + "$" + next
} }
override def parseSimpleExpression = in.peek match { override def parseSimpleExpression = in.peek match { // !!!
case Keyword("if") =>
val pos = in.next().pos
accept('(')
val cond = parseSimpleExpression
accept(')')
val tBranch = parseSimpleExpression
val res = if (in.peek == Keyword("else")) {
in.next()
If(cond, tBranch, parseSimpleExpression).withPos(pos)
} else {
If(cond, tBranch, Lit(Unit)).withPos(pos)
}
res
case _ => super.parseSimpleExpression case _ => super.parseSimpleExpression
} }
override def parseExpression = { override def parseExpression = {
// NOTE: parse expression terminates when it parse a simples expression. // NOTE: parse expression terminates when it parse a simples expression.
// syntax sugar allows to have an other expression after it. // syntax sugar allows to have an other expression after it. !!!
val res = super.parseExpression var res = in.peek match {
case Keyword("val") | Keyword("var") | Keyword("while") =>
super.parseExpression
case _ =>
var simp = parseSimpleExpression
if(isNewLine(in.peek)) {
accept(';')
simp = Let(freshName(), UnknownType, simp, parseExpression).withPos(simp.pos)
}
simp
}
res res
} }
@ -719,10 +764,30 @@ class FunctionParser(in: Scanner) extends SyntacticSugarParser(in) {
/* /*
* This function parse types. * This function parse types.
* *
* TODO * TODO !!!
*/ */
override def parseType = in.peek match { override def parseType = in.peek match {
case _ => super.parseType case Delim('(') =>
accept('(')
val list = parseList[Type](parseType, ',', tok => tok match {
case Delim(')') => false;
case _ => true
})
val argList = list map { tp => ("", tp)}
accept("=>")
val rtp = parseType
FunType(argList, rtp)
case _ =>
val typ = super.parseType
if(in.peek == Delim('=') && in.peek1 == Ident(">")) {
accept("=>")
val rtp = super.parseType
val typList: List[(String, Type)] = List(("", typ))
FunType(typList, rtp)
}
else {
typ
}
} }
/* /*
@ -742,7 +807,9 @@ class FunctionParser(in: Scanner) extends SyntacticSugarParser(in) {
* TODO: complete the function * TODO: complete the function
*/ */
def parseArg: Arg = { def parseArg: Arg = {
??? val (arg, pos) = getName()
val ty = parseOptionalType
Arg(arg, ty, pos)
} }
/* /*
@ -752,7 +819,16 @@ class FunctionParser(in: Scanner) extends SyntacticSugarParser(in) {
* TODO: complete the function * TODO: complete the function
*/ */
def parseFunction: Exp = { def parseFunction: Exp = {
??? accept("def")
val (fname, pos) = getName()
accept('(')
val args = parseList[Arg](parseArg, ',', _ match {
case Ident(_) => true; case _ => false
})
accept(')')
val retTy = parseOptionalType
accept('=')
FunDef(fname, args, retTy, parseSimpleExpression).withPos(pos)
} }
/* /*
@ -765,6 +841,12 @@ class FunctionParser(in: Scanner) extends SyntacticSugarParser(in) {
* TODO: complete the function * TODO: complete the function
*/ */
def parseProgram = in.peek match { def parseProgram = in.peek match {
case Keyword("def") =>
val fns = parseList[Exp](parseFunction, ';', _ match {
case Keyword("def") => true; case _ => false
})
accept(';')
LetRec(fns, parseExpression)
case _ => LetRec(Nil, parseExpression) case _ => LetRec(Nil, parseExpression)
} }
@ -798,7 +880,15 @@ class FunctionParser(in: Scanner) extends SyntacticSugarParser(in) {
res res
case _ => case _ =>
var res = parseAtom var res = parseAtom
// TODO: complete while(in.peek == Delim('(')) {
val pos = in.next().pos
val params = parseList[Exp](parseSimpleExpression, ',', _ match {
case Delim(')') => false; case _ => true
})
accept(')')
res = App(res, params).withPos(pos)
}
// Done: completed
res res
} }
@ -865,7 +955,12 @@ class ArrayParser(in: Scanner) extends FunctionParser(in) {
import Tokens._ import Tokens._
override def parseType = in.peek match { override def parseType = in.peek match {
case Ident("Array") => ??? case Ident("Array") =>
in.next()
accept('[')
val ty = parseType
accept(']')
ArrayType(ty)
case _ => super.parseType case _ => super.parseType
} }
@ -874,12 +969,37 @@ class ArrayParser(in: Scanner) extends FunctionParser(in) {
* *
* TODO * TODO
*/ */
override def parseTight = ??? override def parseTight : Exp = {
val lhs = super.parseTight
if (in.peek == Delim('=')) {
accept('=')
lhs match {
case App(arr, List(idx)) =>
Prim("block-set", List(arr, idx, parseSimpleExpression)).withPos(lhs.pos)
case _ =>
error("Unsupported assignment")
lhs
}
}
else
lhs
}
/* /*
* Parse array declaration * Parse array declaration
* *
* TODO * TODO
*/ */
override def parseSimpleExpression = ??? override def parseSimpleExpression = in.peek match {
case Keyword("new") =>
val pos = in.next().pos
val ty = parseType
accept('(')
val expr = parseSimpleExpression
accept(')')
ArrayDec(expr, ty).withPos(pos)
case _ =>
super.parseSimpleExpression
}
} }

@ -7,6 +7,8 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
* Primitive functions that do not need to be defined or declared. * Primitive functions that do not need to be defined or declared.
*/ */
val primitives = Map[String,(Boolean,Type)]( val primitives = Map[String,(Boolean,Type)](
"toInt" -> (false, FunType(List(("", CharType)), IntType)),
"toChar" -> (false, FunType(List(("", IntType)), CharType)),
"getchar" -> (false, FunType(List(), IntType)), "getchar" -> (false, FunType(List(), IntType)),
"putchar" -> (false, FunType(List(("", IntType)), UnitType)) "putchar" -> (false, FunType(List(("", IntType)), UnitType))
) )
@ -163,7 +165,10 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
* TODO: implement the remaining binary operators for typeBinOperator * TODO: implement the remaining binary operators for typeBinOperator
*/ */
def typeBinOperator(op: String)(pos: Position) = op match { def typeBinOperator(op: String)(pos: Position) = op match {
case "+" => FunType(List(("", IntType), ("", IntType)), IntType) case "+" | "-" | "*" | "/" =>
FunType(List(("", IntType), ("", IntType)), IntType)
case ">=" | "<=" | ">" | "<" | "==" | "!=" =>
FunType(List(("", IntType), ("", IntType)), BooleanType)
case _ => case _ =>
error("undefined binary operator", pos) error("undefined binary operator", pos)
UnknownType UnknownType
@ -177,6 +182,8 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
* TODO: implement typeUnOperator * TODO: implement typeUnOperator
*/ */
def typeUnOperator(op: String)(pos: Position) = op match { def typeUnOperator(op: String)(pos: Position) = op match {
case "+" | "-" => FunType(List(("", IntType)), IntType)
// case "!" => FunType(List(("", BooleanType)), BooleanType)
case _ => case _ =>
error(s"undefined unary operator", pos) error(s"undefined unary operator", pos)
UnknownType UnknownType
@ -188,6 +195,8 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
* operators: block-set * operators: block-set
*/ */
def typeTerOperator(op: String)(pos: Position) = op match { def typeTerOperator(op: String)(pos: Position) = op match {
case "block-set" =>
FunType(List(("", ArrayType(IntType)), ("", IntType)), IntType)
case _ => case _ =>
error(s"undefined ternary operator", pos) error(s"undefined ternary operator", pos)
UnknownType UnknownType
@ -215,7 +224,8 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
case (_, UnknownType) => typeWellFormed(tp)(env, pos) // tp <: Any case (_, UnknownType) => typeWellFormed(tp)(env, pos) // tp <: Any
case (UnknownType, _) => typeWellFormed(pt)(env, pos) // for function arguments case (UnknownType, _) => typeWellFormed(pt)(env, pos) // for function arguments
case (FunType(args1, rtp1), FunType(args2, rtp2)) if args1.length == args2.length => case (FunType(args1, rtp1), FunType(args2, rtp2)) if args1.length == args2.length =>
??? // TODO: Function type conformity FunType(typeConform(args1, args2)(env, pos), typeConforms(rtp1, rtp2)(env, pos))
// Done: Function type conformity
case (ArrayType(tp), ArrayType(pt)) => ArrayType(typeConforms(tp, pt)(env, pos)) case (ArrayType(tp), ArrayType(pt)) => ArrayType(typeConforms(tp, pt)(env, pos))
case _ => error(s"type mismatch;\nfound : $tp\nexpected: $pt", pos); pt case _ => error(s"type mismatch;\nfound : $tp\nexpected: $pt", pos); pt
} }
@ -281,12 +291,22 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
def typeInfer(exp: Exp, pt: Type)(env: TypeEnv): Exp = exp match { def typeInfer(exp: Exp, pt: Type)(env: TypeEnv): Exp = exp match {
case Lit(_: Int) => exp.withType(IntType) case Lit(_: Int) => exp.withType(IntType)
case Lit(_: Boolean) => ??? case Lit(_: Boolean) => exp.withType(BooleanType)
case Lit(_: Unit) => ??? case Lit(_: Char) => exp.withType(CharType)
case Prim("block-set", args) => ??? case Lit(_: Unit) => exp.withType(UnitType)
case Prim("block-set", args) =>
Prim("block-set", List(
typeCheck(args(0), ArrayType(pt))(env),
typeCheck(args(1), IntType)(env),
typeCheck(args(2), pt)(env)
)).withType(UnitType)
case Prim(op, args) => case Prim(op, args) =>
typeOperator(op, args.length)(exp.pos) match { typeOperator(op, args.length)(exp.pos) match {
case FunType(atps, rtp) => ??? case FunType(atps, rtp) =>
val args_checked = (args zip atps) map {
case (arg, (_, param)) => typeCheck(arg, param)(env)
}
Prim(op, args_checked).withType(rtp)
case UnknownType => exp.withType(UnknownType) case UnknownType => exp.withType(UnknownType)
case _ => BUG("operator's type needs to be FunType") case _ => BUG("operator's type needs to be FunType")
} }
@ -298,18 +318,28 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
Let(x, nrhs.tp, nrhs, nbody).withType(nbody.tp) Let(x, nrhs.tp, nrhs, nbody).withType(nbody.tp)
case Ref(x) => case Ref(x) =>
env(x) match { env(x) match {
case Some(tp) => ??? // Remember to check that the type taken from the environment is welformed case Some(tp) =>
exp.withType(typeWellFormed(tp)(env, exp.pos))
// Remember to check that the type taken from the environment is wellformed
case _ => case _ =>
error("undefined identifier", exp.pos) error("undefined identifier", exp.pos)
??? exp.withType(UnknownType)
} }
case If(cond, tBranch, eBranch) => case If(cond, tBranch, eBranch) =>
// Hint: type check the else branch before the then branch. // Hint: type check the else branch before the then branch.
??? val condChecked = typeCheck(cond, BooleanType)(env)
val elseChecked = typeCheck(eBranch, pt)(env)
val thenChecked = typeCheck(tBranch, elseChecked.tp)(env)
If(condChecked, thenChecked, elseChecked).withType(elseChecked.tp)
case VarDec(x, tp, rhs, body) => case VarDec(x, tp, rhs, body) =>
if (env.isDefined(x)) if (env.isDefined(x))
warn("reuse of variable name", exp.pos) warn("reuse of variable name", exp.pos)
??? val rhsChecked = typeCheck(rhs, tp)(env)
val _env = env.withVar(x, rhsChecked.tp)
val bodyChecked = typeCheck(body, pt)(_env)
VarDec(x, rhsChecked.tp, rhsChecked, bodyChecked).withType(bodyChecked.tp)
case VarAssign(x, rhs) => case VarAssign(x, rhs) =>
val xtp = if (!env.isDefined(x)) { val xtp = if (!env.isDefined(x)) {
error("undefined identifier", exp.pos) error("undefined identifier", exp.pos)
@ -320,7 +350,7 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
env(x).get env(x).get
} }
??? val rhsChecked = typeCheck(rhs, xtp)(env)
/* Because of syntactic sugar, a variable assignment /* Because of syntactic sugar, a variable assignment
* statement can be accepted as an expression * statement can be accepted as an expression
@ -338,18 +368,35 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
* Without changing the semantics! * Without changing the semantics!
*/ */
pt match { pt match {
case UnitType => ??? case UnitType | IntType | BooleanType | CharType => VarAssign(x, rhsChecked).withType(rhsChecked.tp)
case _ => ??? case _ => exp.withType(UnknownType)
}
case While(cond, lbody, body) =>
val condChecked = typeCheck(cond, BooleanType)(env)
val lbodyChecked = typeCheck(lbody, UnitType)(env)
val bodyChecked = typeCheck(body, pt)(env)
While(condChecked, lbodyChecked, bodyChecked).withType(bodyChecked.tp)
case FunDef(fname, args, rtp, fbody) =>
checkDuplicateNames(args)
val argsWType = args map {
a => (a.name, typeWellFormed(a.tp)(env, a.pos))
} }
case While(cond, lbody, body) => ??? val bodyChecked = typeCheck(fbody, rtp)(env.withVals(argsWType)) // check rtp w/ pt?
case FunDef(fname, args, rtp, fbody) => ??? FunDef(fname, args, bodyChecked.tp, bodyChecked).withType(
FunType(argsWType, bodyChecked.tp)
)
case LetRec(funs, body) => case LetRec(funs, body) =>
// TODO modify to handle general case // TODO modify to handle general case
val nbody = typeCheck(body, pt)(env) val _env = env.withVals(funs.map {case FunDef(name, _, rtp, _) => (name, rtp)})
LetRec(Nil, nbody).withType(nbody.tp) val funsChecked = funs map {case f@FunDef(_, _, rtp, _) => typeCheck(f, rtp)(_env) }
val bodyChecked = typeCheck(body, pt)( env.withVals(funsChecked map {case FunDef(name, _, rtp, _) => (name, rtp)}))
LetRec(funsChecked, bodyChecked).withType(bodyChecked.tp)
case App(fun, args) => case App(fun, args) =>
// TODO Check fun type // TODO Check fun type
val nFun: Exp = ??? val nFun: Exp = typeCheck(fun, fun.tp)(env)
// Handling some errors // Handling some errors
val ftp = nFun.tp match { val ftp = nFun.tp match {
@ -369,7 +416,9 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
} }
// TODO: Check arguments type // TODO: Check arguments type
val nargs: List[Exp] = ??? val nargs: List[Exp] = (args zip ftp.args) map {
case (arg, (_, param)) => typeCheck(arg, param)(env)
}
// Transform some function applications into primitives on arrays. // Transform some function applications into primitives on arrays.
nFun.tp match { nFun.tp match {
@ -380,7 +429,7 @@ class SemanticAnalyzer(parser: Parser) extends Reporter with BugReporter {
case ArrayDec(size: Exp, etp: Type) => case ArrayDec(size: Exp, etp: Type) =>
// TODO: Check array declaration // TODO: Check array declaration
// Note that etp is the type of elements // Note that etp is the type of elements
??? ArrayDec(typeCheck(size, IntType)(env), etp).withType(etp)
case _ => BUG(s"malformed expresstion $exp") case _ => BUG(s"malformed expresstion $exp")
} }
} }

Loading…
Cancel
Save