From b8b612545cbec07e921333dd9e39a7c4a4604bba Mon Sep 17 00:00:00 2001 From: ValeriHristov Date: Sun, 25 Nov 2018 17:02:00 +0200 Subject: [PATCH 1/6] Implement comparison operators. --- JSImpl/src/ASTInterpreter.cpp | 9 ++++ JSImpl/src/ByteCodeGenerator.cpp | 46 ++++++++++++++++++--- JSImpl/src/main.cpp | 2 +- JSImpl/test/sprtTests.cpp | 71 +++++++++++++++++++++++++++++++- spasm/src/spasm.cpp | 52 +++++++++++++++++++++++ spasm/src/spasm_impl.hpp | 12 +++++- 6 files changed, 183 insertions(+), 9 deletions(-) diff --git a/JSImpl/src/ASTInterpreter.cpp b/JSImpl/src/ASTInterpreter.cpp index f7d1dc22..25f5c021 100644 --- a/JSImpl/src/ASTInterpreter.cpp +++ b/JSImpl/src/ASTInterpreter.cpp @@ -185,6 +185,15 @@ void ASTInterpreter::Visit(BinaryExpression* e) { case TokenType::Less: m_Evaluation.push_back(left < right); break; + case TokenType::LessEqual: + m_Evaluation.push_back(left <= right); + break; + case TokenType::Greater: + m_Evaluation.push_back(left > right); + break; + case TokenType::GreaterEqual: + m_Evaluation.push_back(left >= right); + break; case TokenType::Comma: m_Evaluation.push_back(right); break; diff --git a/JSImpl/src/ByteCodeGenerator.cpp b/JSImpl/src/ByteCodeGenerator.cpp index dc846f2d..e54472e8 100644 --- a/JSImpl/src/ByteCodeGenerator.cpp +++ b/JSImpl/src/ByteCodeGenerator.cpp @@ -53,7 +53,11 @@ class ByteCodeGenerator : public ExpressionVisitor SAVE, RESTORE, LESS, + LESSEQ, + GREATER, + GREATEREQ, EQ, + NEQ, LEQ, GETG, SETG, @@ -266,7 +270,8 @@ void ByteCodeGenerator::Visit(BinaryExpression* e) IPLString o = CreateRegister(); m_RegisterStack.push(o); - switch (e->GetOperator()) { + TokenType t = e->GetOperator(); + switch (t) { case TokenType::Plus: PushInstruction(Instruction::Type::ADD, o, l, r); return; @@ -282,11 +287,20 @@ void ByteCodeGenerator::Visit(BinaryExpression* e) case TokenType::Less: PushInstruction(Instruction::Type::LESS, o, l, r); return; + case TokenType::LessEqual: + PushInstruction(Instruction::Type::LESSEQ, o, l, r); + return; + case TokenType::Greater: + PushInstruction(Instruction::Type::GREATER, o, l, r); + return; + case TokenType::GreaterEqual: + PushInstruction(Instruction::Type::GREATEREQ, o, l, r); + break; case TokenType::EqualEqual: PushInstruction(Instruction::Type::EQ, o, l, r); return; case TokenType::BangEqual: - NOT_IMPLEMENTED; + PushInstruction(Instruction::Type::NEQ,o,l,r); break; case TokenType::Equal: @@ -378,8 +392,8 @@ void ByteCodeGenerator::Visit(UnaryExpression* e) PushInstruction(Instruction::Type::SUB, reg, reg, one); } return; - default: - NOT_IMPLEMENTED; + default: + NOT_IMPLEMENTED; break; } } @@ -427,8 +441,8 @@ void ByteCodeGenerator::Visit(UnaryExpression* e) case TokenType::Bang: NOT_IMPLEMENTED; return; - default: - NOT_IMPLEMENTED; + default: + NOT_IMPLEMENTED; break; } } @@ -532,11 +546,31 @@ IPLString ByteCodeGenerator::GetCode() + " r" + std::to_string(ResolveRegisterName(i.Args[1])) + " r" + std::to_string(ResolveRegisterName(i.Args[2])) + '\n'; break; + case ByteCodeGenerator::Instruction::LESSEQ: + result += "lesseq r" + std::to_string(ResolveRegisterName(i.Args[0])) + + " r" + std::to_string(ResolveRegisterName(i.Args[1])) + + " r" + std::to_string(ResolveRegisterName(i.Args[2])) + '\n'; + break; + case ByteCodeGenerator::Instruction::GREATER: + result += "greater r" + std::to_string(ResolveRegisterName(i.Args[0])) + + " r" + std::to_string(ResolveRegisterName(i.Args[1])) + + " r" + std::to_string(ResolveRegisterName(i.Args[2])) + '\n'; + break; + case ByteCodeGenerator::Instruction::GREATEREQ: + result += "greatereq r" + std::to_string(ResolveRegisterName(i.Args[0])) + + " r" + std::to_string(ResolveRegisterName(i.Args[1])) + + " r" + std::to_string(ResolveRegisterName(i.Args[2])) + '\n'; + break; case ByteCodeGenerator::Instruction::EQ: result += "eq r" + std::to_string(ResolveRegisterName(i.Args[0])) + " r" + std::to_string(ResolveRegisterName(i.Args[1])) + " r" + std::to_string(ResolveRegisterName(i.Args[2])) + '\n'; break; + case ByteCodeGenerator::Instruction::NEQ: + result += "neq r" + std::to_string(ResolveRegisterName(i.Args[0])) + + " r" + std::to_string(ResolveRegisterName(i.Args[1])) + + " r" + std::to_string(ResolveRegisterName(i.Args[2])) + '\n'; + break; case ByteCodeGenerator::Instruction::LEQ: result += "leq r" + std::to_string(ResolveRegisterName(i.Args[0])) + " r" + std::to_string(ResolveRegisterName(i.Args[1])) diff --git a/JSImpl/src/main.cpp b/JSImpl/src/main.cpp index 90f6023f..bee143e6 100644 --- a/JSImpl/src/main.cpp +++ b/JSImpl/src/main.cpp @@ -76,7 +76,7 @@ void Generate() //Tokenize("var a = 0; var b = a + 123;a+b;", tokens); /*Tokenize("var a; if(a < 4) { a = 8; if(a < 7) {var b = 4;}} else { a = 2} ", tokens);*/ IPLString source = "var i = 0; \n" - "for (var j = 0; j < 10; j++)\n" + "for (var j = 0; 10 >= j; j++)\n" "{\n" " i = i + j;\n" "}"; diff --git a/JSImpl/test/sprtTests.cpp b/JSImpl/test/sprtTests.cpp index 84805543..a7b9e3b8 100644 --- a/JSImpl/test/sprtTests.cpp +++ b/JSImpl/test/sprtTests.cpp @@ -127,7 +127,6 @@ TEST_F(SPRTTest, Less) ASSERT_EQ(Output.str(), "100"); } - TEST_F(SPRTTest, LessEq) { Spasm::byte bytecode[] = { @@ -145,6 +144,76 @@ TEST_F(SPRTTest, LessEq) ASSERT_EQ(Output.str(), "101"); } +TEST_F(SPRTTest, Greater) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::Greater, 3, 1, 2, + OpCodes::Greater, 4, 2, 1, + OpCodes::Greater, 5, 2, 2, + OpCodes::Print, 3, + OpCodes::Print, 4, + OpCodes::Print, 5, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "010"); +} + +TEST_F(SPRTTest, GreaterEq) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::GreaterEq, 3, 1, 2, + OpCodes::GreaterEq, 4, 2, 1, + OpCodes::GreaterEq, 5, 2, 2, + OpCodes::Print, 3, + OpCodes::Print, 4, + OpCodes::Print, 5, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "011"); +} + +TEST_F(SPRTTest, Equal) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::Const, 3, 6, + OpCodes::Equal, 4, 2, 1, + OpCodes::Equal, 5, 2, 2, + OpCodes::Equal, 6, 1, 3, + OpCodes::Print, 4, + OpCodes::Print, 5, + OpCodes::Print, 6, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "011"); +} + +TEST_F(SPRTTest, NotEqual) +{ + Spasm::byte bytecode[] = { + OpCodes::Const, 1, 6, + OpCodes::Const, 2, 7, + OpCodes::Const, 3, 6, + OpCodes::NotEqual, 4, 2, 1, + OpCodes::NotEqual, 5, 2, 2, + OpCodes::NotEqual, 6, 1, 3, + OpCodes::Print, 4, + OpCodes::Print, 5, + OpCodes::Print, 6, + }; + + Run(bytecode, sizeof(bytecode)); + ASSERT_EQ(Output.str(), "100"); +} + TEST_F(SPRTTest, Jump) { Spasm::byte bytecode[] = { diff --git a/spasm/src/spasm.cpp b/spasm/src/spasm.cpp index 58fb6d40..4d309466 100644 --- a/spasm/src/spasm.cpp +++ b/spasm/src/spasm.cpp @@ -187,6 +187,38 @@ Spasm::RunResult Spasm::run() lesseq(arg0, arg1, arg2); break; } + case OpCodes::Greater: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + greater(arg0, arg1, arg2); + break; + } + case OpCodes::GreaterEq: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + greatereq(arg0, arg1, arg2); + break; + } + case OpCodes::Equal: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + equal(arg0, arg1, arg2); + break; + } + case OpCodes::NotEqual: + { + const auto arg0 = read_reg(size); + const auto arg1 = read_reg(size); + const auto arg2 = read_reg(size); + not_equal(arg0, arg1, arg2); + break; + } default: { std::cerr << opcode << ": not implemented" << std::endl; @@ -380,6 +412,26 @@ void Spasm::lesseq(reg_t a0, reg_t a1, reg_t a2) set_local(a0, get_local(a1) <= get_local(a2)); } +void Spasm::greater(reg_t a0, reg_t a1, reg_t a2) +{ + set_local(a0, get_local(a1) > get_local(a2)); +} + +void Spasm::greatereq(reg_t a0, reg_t a1, reg_t a2) +{ + set_local(a0, get_local(a1) >= get_local(a2)); +} + +void Spasm::equal(reg_t a0, reg_t a1, reg_t a2) +{ + set_local(a0, fabs(get_local(a1) - get_local(a2)) < 0.0001); +} + +void Spasm::not_equal(reg_t a0, reg_t a1, reg_t a2) +{ + set_local(a0, fabs(get_local(a1) - get_local(a2)) > 0.0001); +} + data_t Spasm::get_local(reg_t reg) { assert(&data_stack[0] <= (m_FP + reg)); diff --git a/spasm/src/spasm_impl.hpp b/spasm/src/spasm_impl.hpp index 7c2bd38d..2548828f 100644 --- a/spasm/src/spasm_impl.hpp +++ b/spasm/src/spasm_impl.hpp @@ -30,7 +30,11 @@ enum OpCodes : char Mod, Less, LessEq, - LastIndex = LessEq, + Greater, + GreaterEq, + Equal, + NotEqual, + LastIndex = NotEqual, }; static_assert(LastIndex < 0x3f, "Too many opcodes"); @@ -121,6 +125,12 @@ class Spasm void less(reg_t a0, reg_t a1, reg_t a2); void lesseq(reg_t a0, reg_t a1, reg_t a2); + void greater(reg_t a0, reg_t a1, reg_t a2); + void greatereq(reg_t a0, reg_t a1, reg_t a2); + + void equal(reg_t a0, reg_t a1, reg_t a2); + void not_equal(reg_t a0, reg_t a1, reg_t a2); + data_t get_local(reg_t reg); void set_local(reg_t reg, data_t data); data_t pop_data(); From c72389738dd790e54b4b6c43b16322d809111167 Mon Sep 17 00:00:00 2001 From: ValeriHristov Date: Sun, 25 Nov 2018 17:09:41 +0200 Subject: [PATCH 2/6] Remove debug code. --- JSImpl/src/ByteCodeGenerator.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/JSImpl/src/ByteCodeGenerator.cpp b/JSImpl/src/ByteCodeGenerator.cpp index e54472e8..fd853264 100644 --- a/JSImpl/src/ByteCodeGenerator.cpp +++ b/JSImpl/src/ByteCodeGenerator.cpp @@ -270,8 +270,7 @@ void ByteCodeGenerator::Visit(BinaryExpression* e) IPLString o = CreateRegister(); m_RegisterStack.push(o); - TokenType t = e->GetOperator(); - switch (t) { + switch (e->GetOperator()) { case TokenType::Plus: PushInstruction(Instruction::Type::ADD, o, l, r); return; From 98776131ab11333638f5cc86acb151a9b75013da Mon Sep 17 00:00:00 2001 From: ValeriHristov Date: Sun, 25 Nov 2018 17:11:24 +0200 Subject: [PATCH 3/6] Undo test code. --- JSImpl/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JSImpl/src/main.cpp b/JSImpl/src/main.cpp index bee143e6..90f6023f 100644 --- a/JSImpl/src/main.cpp +++ b/JSImpl/src/main.cpp @@ -76,7 +76,7 @@ void Generate() //Tokenize("var a = 0; var b = a + 123;a+b;", tokens); /*Tokenize("var a; if(a < 4) { a = 8; if(a < 7) {var b = 4;}} else { a = 2} ", tokens);*/ IPLString source = "var i = 0; \n" - "for (var j = 0; 10 >= j; j++)\n" + "for (var j = 0; j < 10; j++)\n" "{\n" " i = i + j;\n" "}"; From 5925c14157bda10dcb0a5c4067c43e48f176d80f Mon Sep 17 00:00:00 2001 From: ValeriHristov Date: Thu, 27 Dec 2018 14:31:43 +0200 Subject: [PATCH 4/6] Implemented resize of the data stack when needed. --- spasm/src/spasm.cpp | 39 ++++++++++++++++++++++++++++++++++++--- spasm/src/spasm_impl.hpp | 4 +++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/spasm/src/spasm.cpp b/spasm/src/spasm.cpp index 6a62c905..605c9f75 100644 --- a/spasm/src/spasm.cpp +++ b/spasm/src/spasm.cpp @@ -75,7 +75,15 @@ Spasm::RunResult Spasm::run() case OpCodes::Push: { const auto count = PC_t(read_reg(size)); - assert(m_SP + count <= &data_stack[data_stack.size() - 1]); + if(!(m_SP + count <= &data_stack[data_stack.size() - 1])) + { + float resizeCoeff = 2.f; + if (count > data_stack.size()) + { + resizeCoeff = float(ceil(count / data_stack.size()) + 1); + } + resizeDataStack(); + } std::fill(m_SP, m_SP + count, data_t{}); m_SP += count; break; @@ -236,6 +244,25 @@ Spasm::RunResult Spasm::run() return RunResult::Success; } +/*! +** Resizes the data stack. m_FP and m_SP are updated. +*/ +void Spasm::resizeDataStack(float resizeCoefficient) +{ + data_t* stackStart = &(data_stack[0]); + size_t fpOffset = m_FP - stackStart; + size_t spOffset = m_SP - stackStart; + + size_t currentSize = data_stack.size(); + size_t newSize = size_t(currentSize * resizeCoefficient); + data_stack.resize(newSize); + + stackStart = &(data_stack[0]); + m_FP = stackStart + fpOffset; + m_SP = stackStart + spOffset; +} + + /*! ** Pushes the next data_t object on the data stack */ @@ -449,7 +476,10 @@ data_t Spasm::get_local(reg_t reg) void Spasm::set_local(reg_t reg, data_t data) { assert(&data_stack[0] <= (m_FP + reg)); - assert((m_FP + reg) < &data_stack[data_stack.size() - 1]); + if(!((m_FP + reg) < &data_stack[data_stack.size() - 1])) + { + resizeDataStack(); + } m_FP[reg] = data; } @@ -462,7 +492,10 @@ data_t Spasm::pop_data() void Spasm::push_data(data_t data) { - assert(m_SP < &data_stack[data_stack.size() - 1]); + if(!(m_SP < &data_stack[data_stack.size() - 1])) + { + resizeDataStack(); + } *(m_SP++) = data; } diff --git a/spasm/src/spasm_impl.hpp b/spasm/src/spasm_impl.hpp index 04e809a0..ce20774b 100644 --- a/spasm/src/spasm_impl.hpp +++ b/spasm/src/spasm_impl.hpp @@ -115,9 +115,11 @@ class Spasm //! Input stream for read () operation std::istream* istr; - //! Output stream for print () opertion + //! Output stream for print () operation std::ostream* ostr; + void resizeDataStack(float resizeCoefficient = 2.f); + void push(reg_t reg); void popto(reg_t reg); void dup(); From 89a713b65ef3a095158f844e8ddaa6a92d547096 Mon Sep 17 00:00:00 2001 From: ValeriHristov Date: Thu, 27 Dec 2018 15:25:34 +0200 Subject: [PATCH 5/6] Fix unused variable --- spasm/src/spasm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spasm/src/spasm.cpp b/spasm/src/spasm.cpp index 605c9f75..3540a589 100644 --- a/spasm/src/spasm.cpp +++ b/spasm/src/spasm.cpp @@ -82,7 +82,7 @@ Spasm::RunResult Spasm::run() { resizeCoeff = float(ceil(count / data_stack.size()) + 1); } - resizeDataStack(); + resizeDataStack(resizeCoeff); } std::fill(m_SP, m_SP + count, data_t{}); m_SP += count; From 2b772294e3dec4cb5a564c3ad218201163716d98 Mon Sep 17 00:00:00 2001 From: ValeriHristov Date: Sun, 20 Jan 2019 23:08:07 +0200 Subject: [PATCH 6/6] Add unit test for stack resize on push instruction --- JSImpl/test/sprtTests.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/JSImpl/test/sprtTests.cpp b/JSImpl/test/sprtTests.cpp index 25b7665b..b64f8c44 100644 --- a/JSImpl/test/sprtTests.cpp +++ b/JSImpl/test/sprtTests.cpp @@ -423,3 +423,17 @@ TEST_F(SPASMTest, StringEscapeD) CompileAndRun(program); ASSERT_EQ(Output.str(), "the answer\\\" is 42"); } + + +TEST_F(SPASMTest, DataStackResize) +{ + const char* program = + "00: push 1025" "\n" + "01: push 15000" "\n" + "02: const 16025 123""\n" + "03: print 16025" "\n" + "" + ; + CompileAndRun(program); + ASSERT_EQ(Output.str(), "123"); +} \ No newline at end of file