bf rewrite, fixes tests

This commit is contained in:
Robin Jadoul 2017-01-31 16:35:27 +01:00
parent f4bba7dd5e
commit e4647f0ed4
6 changed files with 161 additions and 115 deletions

View File

@ -29,55 +29,10 @@
namespace bf { namespace bf {
void Generator::run() { 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]) { std::size_t data_ptr = 0;
case Instruction::EMPTY: break; for (auto& i : m_program)
case Instruction::PLUS: i->execute(m_data, data_ptr);
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;
}
}
} }

View File

@ -33,17 +33,14 @@ namespace bf {
class Generator { class Generator {
public: public:
Generator(std::deque<Instruction> program) : Generator(std::deque<std::unique_ptr<Instruction>>&& program) :
program(program) { } m_program(std::move(program)) { }
void run(); void run();
private: private:
std::deque<Instruction> program; std::deque<std::unique_ptr<Instruction>> m_program;
int array[30000]; std::array<int, 30000> m_data;
int counter;
std::stack<int> lbrackets;
}; };
} // namespace bf } // namespace bf

View File

@ -25,18 +25,118 @@
#ifndef INSTRUCTION_H #ifndef INSTRUCTION_H
#define INSTRUCTION_H #define INSTRUCTION_H
#include <array>
#include <deque>
#include <iostream>
#include <memory>
namespace bf { namespace bf {
enum class Instruction { using Data = std::array<int, 30000>;
EMPTY,
PLUS, class Instruction {
MINUS, public:
GREATER, virtual void execute(Data& d, std::size_t& data_ptr) const = 0;
LESS, virtual void print() const = 0;
POINT, };
COMMA,
LBRACKET, class InstructionRight : public Instruction {
RBRACKET 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<char>(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<std::unique_ptr<Instruction>>&& 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<std::unique_ptr<Instruction>> m_body;
}; };
} }

View File

@ -31,11 +31,15 @@ using namespace std;
using namespace bf; using namespace bf;
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (argc != 2) {
std::cerr << "Usage: bf <file.bf>" << std::endl;
std::exit(1);
}
ifstream file(argv[1]); ifstream file(argv[1]);
BfLexer lex(file); BfLexer lex(file);
Parser parser(lex); Parser parser(lex);
Generator gen(*(parser.parse())); Generator gen(std::move(*(parser.parse().release())));
gen.run(); gen.run();
return 0; return 0;

View File

@ -29,55 +29,45 @@
namespace bf { namespace bf {
Parser::Parser(BfLexer lex) : Parser::Parser(BfLexer lex) :
bfParser<std::unique_ptr<std::deque<Instruction>>>(), m_lex(lex) { bfParser<std::unique_ptr<std::deque<std::unique_ptr<Instruction>>>>(), m_lex(lex) {
} }
Parser::Token Parser::lex() { Parser::Token Parser::lex() {
try { try {
BfLexer::Token orig = m_lex.nextToken(); BfLexer::Token orig = m_lex.nextToken();
std::deque<Instruction> pm; auto pm = std::make_unique<std::deque<std::unique_ptr<Instruction>>>();
switch(orig.type) { switch(orig.type) {
case BfLexer::PLUS: { case BfLexer::PLUS: {
pm.push_back(Instruction::PLUS); pm->push_back(std::make_unique<InstructionInc>());
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm); //std::cout << "PARSING: found PLUS " << (int)std::unique_ptr<Instruction>::PLUS << std::endl;
//std::cout << "PARSING: found PLUS " << (int)Instruction::PLUS << std::endl; return Token{ bfParser_Symbol::T_PLUS, std::move(pm) };
return Token{ bfParser_Symbol::T_PLUS, std::move(p) };
} case BfLexer::MINUS: { } case BfLexer::MINUS: {
pm.push_back(Instruction::MINUS); pm->push_back(std::make_unique<InstructionDec>());
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm); //std::cout << "PARSING: found MINUS" << (int)std::unique_ptr<Instruction>::MINUS << std::endl;
//std::cout << "PARSING: found MINUS" << (int)Instruction::MINUS << std::endl; return Token{ bfParser_Symbol::T_MINUS, std::move(pm) };
return Token{ bfParser_Symbol::T_MINUS, std::move(p) };
} case BfLexer::GREATER: { } case BfLexer::GREATER: {
pm.push_back(Instruction::GREATER); pm->push_back(std::make_unique<InstructionRight>());
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm); //std::cout << "PARSING: found GREATER" << (int)std::unique_ptr<Instruction>::GREATER << std::endl;
//std::cout << "PARSING: found GREATER" << (int)Instruction::GREATER << std::endl; return Token{ bfParser_Symbol::T_GREATER, std::move(pm) };
return Token{ bfParser_Symbol::T_GREATER, std::move(p) };
} case BfLexer::LESS: { } case BfLexer::LESS: {
pm.push_back(Instruction::LESS); pm->push_back(std::make_unique<InstructionLeft>());
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm); //std::cout << "PARSING: found LESS" << (int)std::unique_ptr<Instruction>::LESS << std::endl;
//std::cout << "PARSING: found LESS" << (int)Instruction::LESS << std::endl; return Token{ bfParser_Symbol::T_LESS, std::move(pm) };
return Token{ bfParser_Symbol::T_LESS, std::move(p) };
} case BfLexer::POINT: { } case BfLexer::POINT: {
pm.push_back(Instruction::POINT); pm->push_back(std::make_unique<InstructionOut>());
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm); //std::cout << "PARSING: found POINT" << (int)std::unique_ptr<Instruction>::POINT << std::endl;
//std::cout << "PARSING: found POINT" << (int)Instruction::POINT << std::endl; return Token{ bfParser_Symbol::T_POINT, std::move(pm) };
return Token{ bfParser_Symbol::T_POINT, std::move(p) };
} case BfLexer::COMMA: { } case BfLexer::COMMA: {
pm.push_back(Instruction::COMMA); pm->push_back(std::make_unique<InstructionIn>());
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm); //std::cout << "PARSING: found COMMA" << (int)std::unique_ptr<Instruction>::COMMA << std::endl;
//std::cout << "PARSING: found COMMA" << (int)Instruction::COMMA << std::endl; return Token{ bfParser_Symbol::T_COMMA, std::move(pm) };
return Token{ bfParser_Symbol::T_COMMA, std::move(p) };
} case BfLexer::LBRACKET: { } case BfLexer::LBRACKET: {
pm.push_back(Instruction::LBRACKET); //std::cout << "PARSING: found LBRACKET" << (int)std::unique_ptr<Instruction>::LBRACKET << std::endl;
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm); return Token{ bfParser_Symbol::T_LBRACKET, nullptr };
//std::cout << "PARSING: found LBRACKET" << (int)Instruction::LBRACKET << std::endl;
return Token{ bfParser_Symbol::T_LBRACKET, std::move(p) };
} case BfLexer::RBRACKET: { } case BfLexer::RBRACKET: {
pm.push_back(Instruction::RBRACKET); //std::cout << "PARSING: found RBRACKET" << (int)std::unique_ptr<Instruction>::RBRACKET << std::endl;
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(pm); return Token{ bfParser_Symbol::T_RBRACKET, nullptr };
//std::cout << "PARSING: found RBRACKET" << (int)Instruction::RBRACKET << std::endl;
return Token{ bfParser_Symbol::T_RBRACKET, std::move(p) };
} }
default: default:
return Token { bfParser_Symbol::T_EOF, nullptr }; return Token { bfParser_Symbol::T_EOF, nullptr };
@ -87,27 +77,27 @@ Parser::Token Parser::lex() {
} }
} }
std::unique_ptr<std::deque<Instruction>> Parser::reduce_PROGRAM(std::deque<Token> subparts) { std::unique_ptr<std::deque<std::unique_ptr<Instruction>>> Parser::reduce_PROGRAM(std::deque<Token> subparts) {
// <program> ::= <instruction> <program> // <program> ::= <instruction> <program>
for(auto& instr : *(subparts[1].value)) 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); return std::move(subparts[0].value);
} }
std::unique_ptr<std::deque<Instruction>> Parser::reduce_EMPTY(std::deque<Token>) { std::unique_ptr<std::deque<std::unique_ptr<Instruction>>> Parser::reduce_EMPTY(std::deque<Token>) {
// <program> ::= // <program> ::=
return std::make_unique<std::deque<Instruction>>(); return std::make_unique<std::deque<std::unique_ptr<Instruction>>>();
} }
std::unique_ptr<std::deque<Instruction>> Parser::reduce_OPERATION(std::deque<Token> subparts) { std::unique_ptr<std::deque<std::unique_ptr<Instruction>>> Parser::reduce_OPERATION(std::deque<Token> subparts) {
// <instruction> ::= "PLUS" | "MINUS" | ... | "COMMA" // <instruction> ::= "PLUS" | "MINUS" | ... | "COMMA"
return std::move(subparts[0].value); return std::move(subparts[0].value);
} }
std::unique_ptr<std::deque<Instruction>> Parser::reduce_LOOP(std::deque<Token> subparts) { std::unique_ptr<std::deque<std::unique_ptr<Instruction>>> Parser::reduce_LOOP(std::deque<Token> subparts) {
// <instruction> ::= "LBRACKET" <program> "RBRACKET" // <instruction> ::= "LBRACKET" <program> "RBRACKET"
subparts[1].value->push_front(Instruction::LBRACKET); auto res = std::make_unique<std::deque<std::unique_ptr<Instruction>>>();
subparts[1].value->push_back(Instruction::RBRACKET); res->push_back(std::make_unique<InstructionLoop>(std::move(*subparts[1].value.release())));
return res;
//std::cout << "PARSING: found LOOP" << std::endl; //std::cout << "PARSING: found LOOP" << std::endl;
//for(auto& s : *(subparts[1].value)) std::cout << "LOOP: " << (int)s << std::endl; //for(auto& s : *(subparts[1].value)) std::cout << "LOOP: " << (int)s << std::endl;
return std::move(subparts[1].value);
} }

View File

@ -33,17 +33,17 @@
namespace bf { namespace bf {
class Parser : public bfParser<std::unique_ptr<std::deque<Instruction>>> { class Parser : public bfParser<std::unique_ptr<std::deque<std::unique_ptr<Instruction>>>> {
public: public:
Parser(BfLexer lex); Parser(BfLexer lex);
protected: protected:
Token lex() override; Token lex() override;
std::unique_ptr<std::deque<Instruction>> reduce_PROGRAM(std::deque<Token> subparts) override; std::unique_ptr<std::deque<std::unique_ptr<Instruction>>> reduce_PROGRAM(std::deque<Token> subparts) override;
std::unique_ptr<std::deque<Instruction>> reduce_EMPTY(std::deque<Token> subparts) override; std::unique_ptr<std::deque<std::unique_ptr<Instruction>>> reduce_EMPTY(std::deque<Token> subparts) override;
std::unique_ptr<std::deque<Instruction>> reduce_OPERATION(std::deque<Token> subparts) override; std::unique_ptr<std::deque<std::unique_ptr<Instruction>>> reduce_OPERATION(std::deque<Token> subparts) override;
std::unique_ptr<std::deque<Instruction>> reduce_LOOP(std::deque<Token> subparts) override; std::unique_ptr<std::deque<std::unique_ptr<Instruction>>> reduce_LOOP(std::deque<Token> subparts) override;
private: private:
BfLexer m_lex; BfLexer m_lex;