From 4a2fbdaa22b9c1aaf6588d9ff6e5a1e96d9f1755 Mon Sep 17 00:00:00 2001 From: billsun Date: Sat, 2 Sep 2023 00:54:59 +0000 Subject: [PATCH] completed --- src/main/scala/project2/Compiler.scala | 51 ++++++++++++++---- src/main/scala/project2/Interpreter.scala | 41 +++++++++++--- src/main/scala/project2/Parser.scala | 54 ++++++++++++++++--- .../scala/project2/SemanticAnalyzer.scala | 34 +++++++----- 4 files changed, 145 insertions(+), 35 deletions(-) diff --git a/src/main/scala/project2/Compiler.scala b/src/main/scala/project2/Compiler.scala index 9400d57..1df2012 100644 --- a/src/main/scala/project2/Compiler.scala +++ b/src/main/scala/project2/Compiler.scala @@ -199,6 +199,8 @@ abstract class X86Compiler extends BugReporter with Codegen { * 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") } @@ -223,6 +225,7 @@ abstract class X86Compiler extends BugReporter with Codegen { var nLabel = 0 def freshLabel(pref: String) = { nLabel += 1; s"$pref$nLabel" } + /* * Generate code that jumps to the label 'label' @@ -260,18 +263,48 @@ abstract class X86Compiler extends BugReporter with Codegen { def trans(exp: Exp, sp: Loc)(env: LocationEnv): Unit = exp match { case Lit(x) => emitln(s"movq $$$x, ${regs(sp)}") - case Unary(op, v) => () - case Prim(op, lop, rop) => () - case Let(x, a, b) => () - case Ref(x) => () - case Cond(op, l, r) => () - case If(cond, tBranch, eBranch) => () - case VarDec(x, rhs, body) => () - case VarAssign(x, rhs) => () + 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) - () // TODO: continue ... + 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 } } diff --git a/src/main/scala/project2/Interpreter.scala b/src/main/scala/project2/Interpreter.scala index db70850..9d5761a 100644 --- a/src/main/scala/project2/Interpreter.scala +++ b/src/main/scala/project2/Interpreter.scala @@ -190,6 +190,8 @@ class StackInterpreter extends Interpreter with BugReporter { * TODO: Implement the appropriate code as defined in the handout. */ def evalUn(op: String)(sp: Loc) = op match { + case "+" => memory(sp) + case "-" => -memory(sp) case _ => BUG(s"Unary operator $op undefined") } @@ -218,6 +220,11 @@ class StackInterpreter extends Interpreter with BugReporter { def evalCond(op: String)(sp: Loc, sp1: Loc) = { flag = op match { case "==" => memory(sp) == memory(sp1) + case "!=" => memory(sp) != memory(sp1) + case ">=" => memory(sp) >= memory(sp1) + case "<=" => memory(sp) <= memory(sp1) + case ">" => memory(sp) > memory(sp1) + case "<" => memory(sp) < memory(sp1) case _ => BUG(s"Binary operator $op undefined") } } @@ -249,14 +256,32 @@ class StackInterpreter extends Interpreter with BugReporter { def eval(exp: Exp, sp: Loc)(env: LocationEnv): Unit = exp match { case Lit(x) => memory(sp) = x - case Unary(op, v) => ??? - case Prim(op, lop, rop) => ??? - case Let(x, a, b) => ??? - case Ref(x) => ??? - case Cond(op, l, r) => ??? - case If(cond, tBranch, eBranch) => ??? - case VarDec(x, rhs, body) => ??? - case VarAssign(x, rhs) => ??? + case Unary(op, v) => + eval(v, sp)(env) + evalUn(op)(sp) + case Prim(op, lop, rop) => + eval(a, sp)(env) + eval(b, sp + 1)(env) + evalBin(sp, sp + 1) + case Let(x, a, b) => + eval(a, sp)(env) + eval(b, sp + 1)(env.withVal(x, sp)) + memory(sp) = memory(sp + 1) + case Ref(x) => + memory(sp) = memory(env.apply(x)) + case Cond(op, l, r) => + eval(l, sp)(env) + eval(r, sp + 1)(env) + evalCond(op)(sp, sp + 1) + case If(cond, tBranch, eBranch) => + eval(cond, sp)(env) + eval(if(flag)tBranch else eBranch, sp) + case VarDec(x, rhs, body) => + eval(rhs, sp)(env) + eval(body, sp + 1)(env.withVal(x, sp)) + case VarAssign(x, rhs) => + eval(rhs, sp)(env) + memory(env.apply(x)) = memory(sp) case While(cond, lbody, body) => eval(cond, sp)(env) while (flag) { diff --git a/src/main/scala/project2/Parser.scala b/src/main/scala/project2/Parser.scala index b852fbf..7cf64b1 100644 --- a/src/main/scala/project2/Parser.scala +++ b/src/main/scala/project2/Parser.scala @@ -1,5 +1,7 @@ package project2 +import java.awt.RenderingHints.Key + // Class used to carry position information within the source code case class Position(gapLine: Int, gapCol: Int, startLine: Int, startCol: Int, endLine: Int, endCol: Int) @@ -426,7 +428,11 @@ class ArithParser(in: Scanner) extends Parser(in) { def parseExpression: Exp = parseExpression(0) def parseExpression(min: Int): Exp = { var res = parseUAtom - // TODO: complete + // TODO: complete DONE? + if (in.hasNext(isOperator)) { + val (op, pos) = getOperator + Prim(op, res, parseUAtom).withPos(pos) + } res } } @@ -469,7 +475,7 @@ class LetParser(in: Scanner) extends ArithParser(in) { case Ident(x) => val (_, pos) = getName Ref(x).withPos(pos) - // TODO: remove ??? and add the implementation for this case + // TODO: remove ??? and add the implementation for this case DONE case _ => abort(s"Illegal start of simple expression") } @@ -532,7 +538,20 @@ class BranchParser(in: Scanner) extends LetParser(in) { } // TODO: remove ??? and complete the implementation. - override def parseSimpleExpression = ??? + override def parseSimpleExpression: Exp = in.peek match { + case Keyword("if") => + val pos = in.next().pos + accept('(') + val cond = parseCondition + accept(')') + val if_stmt = parseSimpleExpression + if (in.hasNext(_ == Keyword("else"))) { + val else_stmt = parseSimpleExpression + If(cond, if_stmt, else_stmt).withPos(pos) + } + else expected("missing else statement") + case _ => super.parseSimpleExpression + } } /* @@ -562,12 +581,24 @@ class VariableParser(in: Scanner) extends BranchParser(in) { // TODO: remove ??? and complete the implementation. override def parseExpression = in.peek match { - case _ => ??? + case Keyword("val") => super.parseExpression + case Keyword("var") => + in.next() + val (name, pos) = getName + accept('=') + val rhs = parseSimpleExpression + accept(';') + val body = parseExpression + Var(name, rhs, body).withPos(pos) + case _ => parseSimpleExpression } // TODO: remove ??? and complete the implementation. override def parseSimpleExpression = (in.peek, in.peek1) match { - case _ => ??? + case (Ident(x), Delim('=')) => + val pos = in.pos + VarAssign(x, parseSimpleExpression).withPos(pos) + case _ => super.parseExpression } } @@ -597,5 +628,16 @@ class LoopParser(in: Scanner) extends VariableParser(in) { import Tokens._ // TODO: remove ??? and complete the implementation. - override def parseExpression = ??? + override def parseExpression = in.peek match { + case Keyword("while") => + val pos = in.next().pos + accept('(') + val cond = parseCondition + accept(')') + val simp = parseSimpleExpression + val body = parseExpression + While(cond, simp, body).withPos(pos) + case _ => + super.parseExpression + } } diff --git a/src/main/scala/project2/SemanticAnalyzer.scala b/src/main/scala/project2/SemanticAnalyzer.scala index e6541fe..112cad0 100644 --- a/src/main/scala/project2/SemanticAnalyzer.scala +++ b/src/main/scala/project2/SemanticAnalyzer.scala @@ -124,33 +124,43 @@ class SemanticAnalyzer(parser: Parser) extends Reporter { error("undefined primitive operator") analyze(lop) analyze(rop) - case Let(x, a, b) => + case Let(x, a, b) => // val x = a; b // Done: check variable reuse - if(!(env.vars.contains(x) && env.vars[x])) + if(!env.vars.contains(x)) error(s"cannot assign variable $x") analyze(a)(env) analyze(b)(env.withVal(x)) case Ref(x) => if (!env.vars.contains(x)) - error(s"symbol $x not found") - ()// Done + error(s"symbol $x not defined") + // Done case Cond(op, l, r) => - // if (!isBOperator(op)) - // error(s"$op is not a boolean operator") + if (!isBOperator(op)) + error(s"$op is not a boolean operator") analyze(op) analyze(l) analyze(r) - () // Done + // Done case If(cond, tBranch, eBranch) => analyze(cond)(env) analyze(tBranch)(env) analyze(eBranch)(env) - case VarDec(x, rhs, body) => - () // TODO - case VarAssign(x, rhs) => //diff w/ LET?? - () // TODO + case VarDec(x, rhs, body) => // var x = rhs; body + if (env.vars.contains(x)) + error(s"symbol $x already defined") + analyze(rhs)(env) + analyze(body)(env) + // TODO + case VarAssign(x, rhs) => // x = rhs + if (!(env.vars.contains(x) && env.vars[x])) + error(s"cannot assign $x: ${if(env.vars.contains(x))"immutable"else"undefined"}") + analyze(rhs) + // TODO case While(cond, lBody, body) => - () // TODO + analyze(cond) + analyze(lBody) + analyze(body) + // TODO case _ => abort(s"unknown AST node $exp") }