From e4647f0ed4f48830f831f63a081a1df0725dabe2 Mon Sep 17 00:00:00 2001 From: Robin Jadoul Date: Tue, 31 Jan 2017 16:35:27 +0100 Subject: [PATCH] bf rewrite, fixes tests --- examples/brainfuck/generator.cpp | 51 +------------ examples/brainfuck/generator.h | 11 ++- examples/brainfuck/instruction.h | 120 ++++++++++++++++++++++++++++--- examples/brainfuck/main.cpp | 8 ++- examples/brainfuck/parser.cpp | 76 +++++++++----------- examples/brainfuck/parser.h | 10 +-- 6 files changed, 161 insertions(+), 115 deletions(-) diff --git a/examples/brainfuck/generator.cpp b/examples/brainfuck/generator.cpp index 82d3200..7afa64f 100644 --- a/examples/brainfuck/generator.cpp +++ b/examples/brainfuck/generator.cpp @@ -29,55 +29,10 @@ namespace bf { void Generator::run() { - - counter = 0; - std::memset(array, 0, sizeof(array)); - while (!lbrackets.empty()) - lbrackets.pop(); - - for (std::size_t instruct = 0; instruct < program.size(); instruct++) { - switch(program[instruct]) { - case Instruction::EMPTY: break; - case Instruction::PLUS: - array[counter]++; - break; - case Instruction::MINUS: - array[counter]--; - break; - case Instruction::GREATER: - if (++counter == 30000) { - std::cout << "Tried to access unavailable memory" << std::endl; - return; - } break; - case Instruction::LESS: - if (--counter == -1) { - std::cout << "Tried to access unavailable memory" << std::endl; - return; - } break; - case Instruction::POINT: - std::cout << (char)array[counter]; - break; - case Instruction::COMMA: - char c; - std::cin >> c; - array[counter] = (int)c; - break; - case Instruction::LBRACKET: - lbrackets.push(instruct); - if (array[counter] == 0) - while (program[++instruct] != Instruction::RBRACKET) {} - break; - case Instruction::RBRACKET: - if (array[counter] != 0) - instruct = lbrackets.top(); - else - lbrackets.pop(); - break; - default: // Won't happen - break; - } - } + std::size_t data_ptr = 0; + for (auto& i : m_program) + i->execute(m_data, data_ptr); } diff --git a/examples/brainfuck/generator.h b/examples/brainfuck/generator.h index 9e93ed1..460d3c6 100644 --- a/examples/brainfuck/generator.h +++ b/examples/brainfuck/generator.h @@ -33,17 +33,14 @@ namespace bf { class Generator { public: - Generator(std::deque program) : - program(program) { } + Generator(std::deque>&& program) : + m_program(std::move(program)) { } void run(); private: - std::deque program; - int array[30000]; - int counter; - std::stack lbrackets; - + std::deque> m_program; + std::array m_data; }; } // namespace bf diff --git a/examples/brainfuck/instruction.h b/examples/brainfuck/instruction.h index c658454..94ed838 100644 --- a/examples/brainfuck/instruction.h +++ b/examples/brainfuck/instruction.h @@ -25,18 +25,118 @@ #ifndef INSTRUCTION_H #define INSTRUCTION_H +#include +#include +#include +#include + namespace bf { -enum class Instruction { - EMPTY, - PLUS, - MINUS, - GREATER, - LESS, - POINT, - COMMA, - LBRACKET, - RBRACKET +using Data = std::array; + +class Instruction { + public: + virtual void execute(Data& d, std::size_t& data_ptr) const = 0; + virtual void print() const = 0; +}; + +class InstructionRight : public Instruction { + public: + void execute(Data&, std::size_t& data_ptr) const { + data_ptr++; + if (data_ptr >= 30000) { + std::cerr << "Out of bounds" << std::endl; + std::exit(1); + } + }; + + void print() const { + std::cout << ">"; + } +}; + +class InstructionLeft : public Instruction { + public: + void execute(Data&, std::size_t& data_ptr) const { + data_ptr--; + if (data_ptr >= 30000) { //wraps around when below 0 + std::cerr << "Out of bounds" << std::endl; + std::exit(1); + } + }; + + void print() const { + std::cout << "<"; + } +}; + +class InstructionInc : public Instruction { + public: + void execute(Data& d, std::size_t& ptr) const { + d[ptr]++; + } + + void print() const { + std::cout << "+"; + } +}; + +class InstructionDec : public Instruction { + public: + void execute(Data& d, std::size_t& ptr) const { + d[ptr]--; + } + + void print() const { + std::cout << "-"; + } +}; + +class InstructionOut : public Instruction { + public: + void execute(Data& d, std::size_t& ptr) const { + std::cout << static_cast(d[ptr]); + } + + void print() const { + std::cout << "."; + } +}; + +class InstructionIn : public Instruction { + public: + void execute(Data& d, std::size_t& ptr) const { + char c = -1; + if (!std::cin.eof()) + std::cin.get(c); + d[ptr] = c; + } + + void print() const { + std::cout << ","; + } +}; + +class InstructionLoop : public Instruction { + public: + InstructionLoop(std::deque>&& body) : m_body(std::move(body)) {}; + + void execute(Data& d, std::size_t& ptr) const { + while (d[ptr] != 0) { + for (auto& b : m_body) + b->execute(d, ptr); + } + } + + void print() const { + std::cout << "["; + for (auto& b : m_body) + b->print(); + std::cout << "]"; + } + + private: + std::deque> m_body; }; } diff --git a/examples/brainfuck/main.cpp b/examples/brainfuck/main.cpp index ed7a71f..392a55e 100644 --- a/examples/brainfuck/main.cpp +++ b/examples/brainfuck/main.cpp @@ -31,11 +31,15 @@ using namespace std; using namespace bf; int main(int argc, char** argv) { - + if (argc != 2) { + std::cerr << "Usage: bf " << std::endl; + std::exit(1); + } + ifstream file(argv[1]); BfLexer lex(file); Parser parser(lex); - Generator gen(*(parser.parse())); + Generator gen(std::move(*(parser.parse().release()))); gen.run(); return 0; diff --git a/examples/brainfuck/parser.cpp b/examples/brainfuck/parser.cpp index 1d4f243..2c98d1e 100644 --- a/examples/brainfuck/parser.cpp +++ b/examples/brainfuck/parser.cpp @@ -29,55 +29,45 @@ namespace bf { Parser::Parser(BfLexer lex) : - bfParser>>(), m_lex(lex) { + bfParser>>>(), m_lex(lex) { } Parser::Token Parser::lex() { try { BfLexer::Token orig = m_lex.nextToken(); - std::deque pm; + auto pm = std::make_unique>>(); switch(orig.type) { case BfLexer::PLUS: { - pm.push_back(Instruction::PLUS); - std::unique_ptr> p = std::make_unique>(pm); - //std::cout << "PARSING: found PLUS " << (int)Instruction::PLUS << std::endl; - return Token{ bfParser_Symbol::T_PLUS, std::move(p) }; + pm->push_back(std::make_unique()); + //std::cout << "PARSING: found PLUS " << (int)std::unique_ptr::PLUS << std::endl; + return Token{ bfParser_Symbol::T_PLUS, std::move(pm) }; } case BfLexer::MINUS: { - pm.push_back(Instruction::MINUS); - std::unique_ptr> p = std::make_unique>(pm); - //std::cout << "PARSING: found MINUS" << (int)Instruction::MINUS << std::endl; - return Token{ bfParser_Symbol::T_MINUS, std::move(p) }; + pm->push_back(std::make_unique()); + //std::cout << "PARSING: found MINUS" << (int)std::unique_ptr::MINUS << std::endl; + return Token{ bfParser_Symbol::T_MINUS, std::move(pm) }; } case BfLexer::GREATER: { - pm.push_back(Instruction::GREATER); - std::unique_ptr> p = std::make_unique>(pm); - //std::cout << "PARSING: found GREATER" << (int)Instruction::GREATER << std::endl; - return Token{ bfParser_Symbol::T_GREATER, std::move(p) }; + pm->push_back(std::make_unique()); + //std::cout << "PARSING: found GREATER" << (int)std::unique_ptr::GREATER << std::endl; + return Token{ bfParser_Symbol::T_GREATER, std::move(pm) }; } case BfLexer::LESS: { - pm.push_back(Instruction::LESS); - std::unique_ptr> p = std::make_unique>(pm); - //std::cout << "PARSING: found LESS" << (int)Instruction::LESS << std::endl; - return Token{ bfParser_Symbol::T_LESS, std::move(p) }; + pm->push_back(std::make_unique()); + //std::cout << "PARSING: found LESS" << (int)std::unique_ptr::LESS << std::endl; + return Token{ bfParser_Symbol::T_LESS, std::move(pm) }; } case BfLexer::POINT: { - pm.push_back(Instruction::POINT); - std::unique_ptr> p = std::make_unique>(pm); - //std::cout << "PARSING: found POINT" << (int)Instruction::POINT << std::endl; - return Token{ bfParser_Symbol::T_POINT, std::move(p) }; + pm->push_back(std::make_unique()); + //std::cout << "PARSING: found POINT" << (int)std::unique_ptr::POINT << std::endl; + return Token{ bfParser_Symbol::T_POINT, std::move(pm) }; } case BfLexer::COMMA: { - pm.push_back(Instruction::COMMA); - std::unique_ptr> p = std::make_unique>(pm); - //std::cout << "PARSING: found COMMA" << (int)Instruction::COMMA << std::endl; - return Token{ bfParser_Symbol::T_COMMA, std::move(p) }; + pm->push_back(std::make_unique()); + //std::cout << "PARSING: found COMMA" << (int)std::unique_ptr::COMMA << std::endl; + return Token{ bfParser_Symbol::T_COMMA, std::move(pm) }; } case BfLexer::LBRACKET: { - pm.push_back(Instruction::LBRACKET); - std::unique_ptr> p = std::make_unique>(pm); - //std::cout << "PARSING: found LBRACKET" << (int)Instruction::LBRACKET << std::endl; - return Token{ bfParser_Symbol::T_LBRACKET, std::move(p) }; + //std::cout << "PARSING: found LBRACKET" << (int)std::unique_ptr::LBRACKET << std::endl; + return Token{ bfParser_Symbol::T_LBRACKET, nullptr }; } case BfLexer::RBRACKET: { - pm.push_back(Instruction::RBRACKET); - std::unique_ptr> p = std::make_unique>(pm); - //std::cout << "PARSING: found RBRACKET" << (int)Instruction::RBRACKET << std::endl; - return Token{ bfParser_Symbol::T_RBRACKET, std::move(p) }; + //std::cout << "PARSING: found RBRACKET" << (int)std::unique_ptr::RBRACKET << std::endl; + return Token{ bfParser_Symbol::T_RBRACKET, nullptr }; } default: return Token { bfParser_Symbol::T_EOF, nullptr }; @@ -87,27 +77,27 @@ Parser::Token Parser::lex() { } } -std::unique_ptr> Parser::reduce_PROGRAM(std::deque subparts) { +std::unique_ptr>> Parser::reduce_PROGRAM(std::deque subparts) { // ::= for(auto& instr : *(subparts[1].value)) - subparts[0].value->push_back(instr); + subparts[0].value->push_back(std::move(instr)); return std::move(subparts[0].value); } -std::unique_ptr> Parser::reduce_EMPTY(std::deque) { +std::unique_ptr>> Parser::reduce_EMPTY(std::deque) { // ::= - return std::make_unique>(); + return std::make_unique>>(); } -std::unique_ptr> Parser::reduce_OPERATION(std::deque subparts) { +std::unique_ptr>> Parser::reduce_OPERATION(std::deque subparts) { // ::= "PLUS" | "MINUS" | ... | "COMMA" return std::move(subparts[0].value); } -std::unique_ptr> Parser::reduce_LOOP(std::deque subparts) { +std::unique_ptr>> Parser::reduce_LOOP(std::deque subparts) { // ::= "LBRACKET" "RBRACKET" - subparts[1].value->push_front(Instruction::LBRACKET); - subparts[1].value->push_back(Instruction::RBRACKET); + auto res = std::make_unique>>(); + res->push_back(std::make_unique(std::move(*subparts[1].value.release()))); + return res; //std::cout << "PARSING: found LOOP" << std::endl; //for(auto& s : *(subparts[1].value)) std::cout << "LOOP: " << (int)s << std::endl; - return std::move(subparts[1].value); } diff --git a/examples/brainfuck/parser.h b/examples/brainfuck/parser.h index 7e2b010..8c196a7 100644 --- a/examples/brainfuck/parser.h +++ b/examples/brainfuck/parser.h @@ -33,17 +33,17 @@ namespace bf { -class Parser : public bfParser>> { +class Parser : public bfParser>>> { public: Parser(BfLexer lex); protected: Token lex() override; - std::unique_ptr> reduce_PROGRAM(std::deque subparts) override; - std::unique_ptr> reduce_EMPTY(std::deque subparts) override; - std::unique_ptr> reduce_OPERATION(std::deque subparts) override; - std::unique_ptr> reduce_LOOP(std::deque subparts) override; + std::unique_ptr>> reduce_PROGRAM(std::deque subparts) override; + std::unique_ptr>> reduce_EMPTY(std::deque subparts) override; + std::unique_ptr>> reduce_OPERATION(std::deque subparts) override; + std::unique_ptr>> reduce_LOOP(std::deque subparts) override; private: BfLexer m_lex;