From 30280816c4b2e7c28fe1f0a4ee71b9c0987187e2 Mon Sep 17 00:00:00 2001 From: Chiyoda Sumika Date: Sun, 3 Sep 2023 23:07:49 -0400 Subject: [PATCH] done --- src/main/scala/project2/Interpreter.scala | 5 +- src/main/scala/project2/Parser.scala | 7 +-- .../scala/project2/SemanticAnalyzer.scala | 14 ++--- src/test/scala/project2/CompilerTest.scala | 33 ++++++++++ src/test/scala/project2/InterpreterTest.scala | 34 ++++++++++ src/test/scala/project2/ParserTest.scala | 62 +++++++++++++++++-- .../scala/project2/SemanticAnalyzerTest.scala | 16 ++++- src/test/scala/project2/TimedSuite.scala | 2 +- 8 files changed, 152 insertions(+), 21 deletions(-) diff --git a/src/main/scala/project2/Interpreter.scala b/src/main/scala/project2/Interpreter.scala index 5a60ea7..34e4008 100644 --- a/src/main/scala/project2/Interpreter.scala +++ b/src/main/scala/project2/Interpreter.scala @@ -190,8 +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 "+" => () + case "-" => memory(sp) = -memory(sp) case _ => BUG(s"Unary operator $op undefined") } @@ -279,6 +279,7 @@ class StackInterpreter extends Interpreter with BugReporter { case VarDec(x, rhs, body) => eval(rhs, sp)(env) eval(body, sp + 1)(env.withVal(x, sp)) + memory(sp) = memory(sp + 1) case VarAssign(x, rhs) => eval(rhs, sp)(env) memory(env.apply(x)) = memory(sp) diff --git a/src/main/scala/project2/Parser.scala b/src/main/scala/project2/Parser.scala index 2ea2ffb..bd44421 100644 --- a/src/main/scala/project2/Parser.scala +++ b/src/main/scala/project2/Parser.scala @@ -434,7 +434,7 @@ class ArithParser(in: Scanner) extends Parser(in) { isInfixOp(min)(in.peek) ) { val (op, pos) = getOperator - res = Prim(op, res, parseExpression(prec(op))).withPos(pos) + res = Prim(op, res, parseExpression(prec(op) + assoc(op))).withPos(pos) } res } @@ -541,9 +541,7 @@ class BranchParser(in: Scanner) extends LetParser(in) { } // TODO: remove ??? and complete the implementation. - override def parseSimpleExpression: Exp = { - print(in.peek) - in.peek match { + override def parseSimpleExpression: Exp = in.peek match { case Keyword("if") => val pos = in.next().pos accept('(') @@ -557,7 +555,6 @@ class BranchParser(in: Scanner) extends LetParser(in) { } else expected("missing else statement") case _ => super.parseSimpleExpression - } } } diff --git a/src/main/scala/project2/SemanticAnalyzer.scala b/src/main/scala/project2/SemanticAnalyzer.scala index b6f213e..2421971 100644 --- a/src/main/scala/project2/SemanticAnalyzer.scala +++ b/src/main/scala/project2/SemanticAnalyzer.scala @@ -120,19 +120,19 @@ class SemanticAnalyzer(parser: Parser) extends Reporter { error("undefined unary operator", exp.pos) analyze(v)(env) case Prim(op, lop, rop) => // Done - if(!(isOperator(op) || isBOperator(op))) + if(!isOperator(op)) error("undefined primitive operator", exp.pos) analyze(lop)(env) analyze(rop)(env) case Let(x, a, b) => // val x = a; b // Done: check variable reuse if(env.vars.contains(x)) - error(s"cannot assign variable $x", exp.pos) + warn(s"redifinition of ${if(env.vars(x))"variable"else"value"} $x", exp.pos) analyze(a)(env) analyze(b)(env.withVal(x)) case Ref(x) => if (!env.vars.contains(x)) - error(s"symbol $x not defined", exp.pos) + error(s"symbol $x is undefined", exp.pos) // Done case Cond(op, l, r) => if (!isBOperator(op)) @@ -146,20 +146,20 @@ class SemanticAnalyzer(parser: Parser) extends Reporter { analyze(eBranch)(env) case VarDec(x, rhs, body) => // var x = rhs; body if (env.vars.contains(x)) - error(s"symbol $x already defined", exp.pos) + warn(s"redifinition of ${if(env.vars(x))"variable"else"value"} $x", exp.pos) analyze(rhs)(env) analyze(body)(env.withVar(x)) - // TODO + // Done 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"}", exp.pos) analyze(rhs)(env) - // TODO + // Done case While(cond, lBody, body) => analyze(cond)(env) analyze(lBody)(env) analyze(body)(env) - // TODO + // Done case _ => abort(s"unknown AST node $exp") } diff --git a/src/test/scala/project2/CompilerTest.scala b/src/test/scala/project2/CompilerTest.scala index 9ddca71..c148281 100644 --- a/src/test/scala/project2/CompilerTest.scala +++ b/src/test/scala/project2/CompilerTest.scala @@ -35,7 +35,40 @@ class CompilerTest extends TimedSuite { test("arithm") { testCompiler(Lit(-21), -21) + testCompiler(Unary("-", Lit(23)), -23) + testCompiler(Unary("+", Lit(22)), 22) testCompiler(Prim("-", Lit(10), Lit(2)), 8) + testCompiler(Prim("+", Prim("+", Prim("-", Lit(1), Lit(2)), Lit(3)), Lit(4)), 6) + testCompiler(Prim("*", Lit(2), Lit(-3)), -6) + testCompiler(Prim("+", Prim("+", Prim("-", Unary("-", Lit(5)), Prim("/", Lit(8), Lit(3))),Lit(2)), Lit(3)), -2) } + test("let&ref") { + testCompiler(Let("x", Lit(2), Ref("x")), 2) + testCompiler(Let("x", Prim("*", Lit(2), Unary("-", Lit(5))), Ref("x")), -10) + } + + test("if&cond") { + testCompiler(Let("x",Lit(5), Let("y", Lit(5), If(Cond("==", Ref("x"), Ref("y")),Lit(5), Lit(10)))), 5) + testCompiler(If(Cond(">", Lit(3), Lit(1)), Lit(10), Lit(5)), 10) + testCompiler(If(Cond("==", Lit(1), Lit(2)), Lit(1), Lit(2)), 2) + testCompiler(VarDec("x",Lit(5),If(Cond("==",Ref("x"),Lit(5)),Lit(7),Lit(6))), 7) + testCompiler(VarDec("x",Lit(5),If(Cond("!=",Ref("x"),Lit(5)),Lit(7),Lit(6))), 6) + } + + test("varassign") { + testCompiler(VarDec("x", Lit(5), VarAssign("x", Prim("-", Ref("x"), Lit(15)))), -10) + testCompiler(VarDec("x",Lit(5),VarAssign("x",Lit(3))), 3) + } + + test("vardec") { + testCompiler(VarDec("x",Lit(5),Ref("x")), 5) + testCompiler(VarDec("x",Unary("-",Lit(5)),Ref("x")), -5) + } + + test("while") { + testCompiler(While(Cond("!=",Lit(5),Lit(5)),Lit(3),Lit(5)), 5) + testCompiler(VarDec("x",Lit(2),VarDec("y",Lit(0),While(Cond("<",Ref("y"),Lit(3)),Let("dummy",VarAssign("x",Prim("*",Ref("x"),Ref("x"))),VarAssign("y",Prim("+",Ref("y"),Lit(1)))),Ref("x")))), 256) + testCompiler(VarDec("x",Lit(0),While(Cond("!=",Ref("x"),Lit(5)),VarAssign("x",Prim("+",Ref("x"),Lit(1))),Ref("x"))), 5) + } } diff --git a/src/test/scala/project2/InterpreterTest.scala b/src/test/scala/project2/InterpreterTest.scala index c39624b..115bb08 100644 --- a/src/test/scala/project2/InterpreterTest.scala +++ b/src/test/scala/project2/InterpreterTest.scala @@ -13,7 +13,41 @@ class InterpretTest extends TimedSuite { test("arithm") { testInterpreter(Lit(-21), -21) + testInterpreter(Unary("-", Lit(23)), -23) + testInterpreter(Unary("+", Lit(22)), 22) testInterpreter(Prim("-", Lit(10), Lit(2)), 8) + testInterpreter(Prim("+", Prim("+", Prim("-", Lit(1), Lit(2)), Lit(3)), Lit(4)), 6) + testInterpreter(Prim("*", Lit(2), Lit(-3)), -6) + testInterpreter(Prim("+", Prim("+", Prim("-", Unary("-", Lit(5)), Prim("/", Lit(8), Lit(3))),Lit(2)), Lit(3)), -2) } + test("let&ref") { + testInterpreter(Let("x", Lit(2), Ref("x")), 2) + testInterpreter(Let("x", Prim("*", Lit(2), Unary("-", Lit(5))), Ref("x")), -10) + } + + test("if&cond") { + testInterpreter(Let("x",Lit(5), Let("y", Lit(5), If(Cond("==", Ref("x"), Ref("y")),Lit(5), Lit(10)))), 5) + testInterpreter(If(Cond(">", Lit(3), Lit(1)), Lit(10), Lit(5)), 10) + testInterpreter(If(Cond("==", Lit(1), Lit(2)), Lit(1), Lit(2)), 2) + testInterpreter(VarDec("x",Lit(5),If(Cond("==",Ref("x"),Lit(5)),Lit(7),Lit(6))), 7) + testInterpreter(VarDec("x",Lit(5),If(Cond("!=",Ref("x"),Lit(5)),Lit(7),Lit(6))), 6) + } + + test("varassign") { + testInterpreter(VarDec("x", Lit(5), VarAssign("x", Prim("-", Ref("x"), Lit(15)))), -10) + testInterpreter(VarDec("x",Lit(5),VarAssign("x",Lit(3))), 3) + } + + test("vardec") { + testInterpreter(VarDec("x",Lit(5),Ref("x")), 5) + testInterpreter(VarDec("x",Unary("-",Lit(5)),Ref("x")), -5) + } + + test("while") { + testInterpreter(While(Cond("!=",Lit(5),Lit(5)),Lit(3),Lit(5)), 5) + testInterpreter(VarDec("x",Lit(2),VarDec("y",Lit(0),While(Cond("<",Ref("y"),Lit(3)),Let("dummy",VarAssign("x",Prim("*",Ref("x"),Ref("x"))),VarAssign("y",Prim("+",Ref("y"),Lit(1)))),Ref("x")))), 256) + testInterpreter(VarDec("x",Lit(0),While(Cond("!=",Ref("x"),Lit(5)),VarAssign("x",Prim("+",Ref("x"),Lit(1))),Ref("x"))), 5) + } + } diff --git a/src/test/scala/project2/ParserTest.scala b/src/test/scala/project2/ParserTest.scala index 42a0e56..7b24ccb 100644 --- a/src/test/scala/project2/ParserTest.scala +++ b/src/test/scala/project2/ParserTest.scala @@ -42,13 +42,67 @@ class ParserTest extends TimedSuite { assert(ast == res, "Invalid result") } - /*test("SingleDigit") { + test("SingleDigit") { testGenericPrecedence("1", Lit(1)) } test("GenericPrecedence") { testGenericPrecedence("2-4*3", Prim("-", Lit(2), Prim("*", Lit(4), Lit(3)))) - }*/ + testGenericPrecedence("1+ -2", Prim("+",Lit(1),Unary("-",Lit(2)))) + testGenericPrecedence("1+2*3/4", Prim("+",Lit(1),Prim("/",Prim("*",Lit(2),Lit(3)),Lit(4)))) + testGenericPrecedence("1+(-1)", Prim("+",Lit(1), Unary("-",Lit(1)))) + testGenericPrecedence("(1-2*3/4-5)*6", + Prim("*",Prim("-",Prim("-",Lit(1),Prim("/",Prim("*",Lit(2),Lit(3)),Lit(4))),Lit(5)),Lit(6))) + } + + test("testLetParser") { + testLetParser("val x=1;x", Let("x", Lit(1), Ref("x"))) + testLetParser("val x = 1; val y = 2; x - y", + Let("x", Lit(1), Let("y", Lit(2), Prim("-", Ref("x"), Ref("y"))))) + testLetParser("val x = 1; val y = 2; x*3 - y", + Let("x", Lit(1), Let("y", Lit(2), Prim("-", Prim("*", Ref("x"), Lit(3)), Ref("y"))))) + } + + test("testBranchParser") { + testBranchParser("if(1==2)3 else 4", If(Cond("==",Lit(1), Lit(2)), Lit(3), Lit(4))) + testBranchParser("val x = 5; if (x == 5) x else 5", + Let("x",Lit(5),If(Cond("==",Ref("x"),Lit(5)),Ref("x"),Lit(5)))) + testBranchParser("if(3>5){1}else{2}", If(Cond(">", Lit(3), Lit(5)), Lit(1), Lit(2))) + testBranchParser("if(3>5){if(9<0){1}else{2}}else{4}", + If(Cond(">", Lit(3), Lit(5)), If(Cond("<", Lit(9), Lit(0)), Lit(1), Lit(2)), Lit(4))) + assertThrows[Exception] { + testBranchParser("if(1>2)1", Lit(0)) + } + } + + test("testVariableParser"){ + testVariableParser("var x = 1; var y = 2; x = y = 3", + VarDec("x", Lit(1), VarDec("y", Lit(2), VarAssign("x", VarAssign("y", Lit(3)))))) + assertThrows[Exception] { + testVariableParser("var x = 1 1", Lit(0)) + } + } + + //Loop Parser + test("testLoopParser"){ + testLoopParser("var x = 1; var y = 1; while(x <= 0) {val t = x + y; if(t > y) x = t else y = (-x - 1)};x", + VarDec("x", Lit(1), + VarDec("y", Lit(1), + While(Cond("<=", Ref("x"), Lit(0)), + Let("t", Prim("+", Ref("x"), Ref("y")), + If(Cond(">", Ref("t"), Ref("y")), + VarAssign("x", Ref("t")), + VarAssign("y",Prim("-", Unary("-", Ref("x")), Lit(1))))), + Ref("x"))))) + assertThrows[Exception] { + testLoopParser("while(1){};", Lit(0)) + } + assertThrows[Exception] { + testLoopParser("while(1 == 1) { val x = 2; }", Lit(0)) + } + testLoopParser("while(1 == 1) { val x = 2; 2 }; 1", While(Cond("==", Lit(1), Lit(1)), Let("x", Lit(2), Lit(2)), Lit(1))) + } + test("1") { testGenericPrecedence(s"${(1 << 31) - 1}", Lit({ (1 << 31) - 1 @@ -86,12 +140,12 @@ class ParserTest extends TimedSuite { Prim("*", Prim("*", Prim("*", Lit(2), Lit(9)), Lit(5)), Lit(3)), Prim("/", Prim("/", Lit(18), Lit(6)), Lit(3)))) } - /*test("rt") { + test("rt") { testGenericPrecedence("18/6/3",Prim("/",Prim("/",Lit(18),Lit(6)),Lit(3))) } test("go"){ testGenericPrecedence("2*9*5*3",Prim("*",Prim("*",Prim("*",Lit(2),Lit(9)),Lit(5)), Lit(3))) - }*/ + } test("8") { 0 } diff --git a/src/test/scala/project2/SemanticAnalyzerTest.scala b/src/test/scala/project2/SemanticAnalyzerTest.scala index 9bea2cf..683c60d 100644 --- a/src/test/scala/project2/SemanticAnalyzerTest.scala +++ b/src/test/scala/project2/SemanticAnalyzerTest.scala @@ -31,11 +31,23 @@ class SemanticAnalyzerTest extends TimedSuite { test("32"){ testSemanticAnalyzer(VarDec("x",Lit(1),Let("x",Lit(5),Lit(4))), 1 ,0) } - /*test("3"){ + test("3"){ testSemanticAnalyzer(Prim("%",Lit(1),Lit(5)),0,1) } test("3134"){ testSemanticAnalyzer(Prim("%",Lit(1),Lit(5)),0,1) - }*/ + } + + test("more tests"){ + testSemanticAnalyzer(Let("x", Lit(1), VarAssign("x", Lit(2))), 0, 1) // assign to imm + testSemanticAnalyzer(Let("x", Lit(1), Let("x", Lit(2), Ref("x"))), 1, 0) // redef imm -> imm + testSemanticAnalyzer(VarDec("x", Lit(1), VarDec("x", Lit(2), Ref("x"))), 1, 0) // redef mut -> mut + testSemanticAnalyzer(Let("x", Lit(1), VarDec("x", Lit(2), VarAssign("x", Lit(3)))), 1, 0) // redef imm -> mut + testSemanticAnalyzer(Let("x", Lit(1), Let("x", Lit(2), VarAssign("x", Lit(3)))), 1, 1) // warn + err + testSemanticAnalyzer(Prim("+", Unary("/", Lit(1)), Lit(2)), 0, 1) // invalid unary op + testSemanticAnalyzer(Prim("++", Lit(1), Lit(2)), 0, 1) // invalid op + testSemanticAnalyzer(If(Cond("<>", Lit(1), Lit(2)), Lit(3), Lit(4)), 0, 1) // invalid boolean op + testSemanticAnalyzer(If(Cond("==", Ref("x"), Lit(1)), Lit(2), Lit(3)), 0, 1) // undefined sym + } } diff --git a/src/test/scala/project2/TimedSuite.scala b/src/test/scala/project2/TimedSuite.scala index 78a936c..e1c25fa 100644 --- a/src/test/scala/project2/TimedSuite.scala +++ b/src/test/scala/project2/TimedSuite.scala @@ -5,6 +5,6 @@ import org.scalatest.time.{Span, Millis} class TimedSuite extends FunSuite with TimeLimitedTests { - val timeLimit = Span(1000, Millis) + val timeLimit = Span(10000, Millis) override val defaultTestSignaler: Signaler = ThreadSignaler }