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

@ -30,54 +30,9 @@ 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);
}

View File

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

View File

@ -25,18 +25,118 @@
#ifndef INSTRUCTION_H
#define INSTRUCTION_H
#include <array>
#include <deque>
#include <iostream>
#include <memory>
namespace bf {
enum class Instruction {
EMPTY,
PLUS,
MINUS,
GREATER,
LESS,
POINT,
COMMA,
LBRACKET,
RBRACKET
using Data = std::array<int, 30000>;
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<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;
int main(int argc, char** argv) {
if (argc != 2) {
std::cerr << "Usage: bf <file.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;

View File

@ -29,55 +29,45 @@
namespace bf {
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() {
try {
BfLexer::Token orig = m_lex.nextToken();
std::deque<Instruction> pm;
auto pm = std::make_unique<std::deque<std::unique_ptr<Instruction>>>();
switch(orig.type) {
case BfLexer::PLUS: {
pm.push_back(Instruction::PLUS);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(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<InstructionInc>());
//std::cout << "PARSING: found PLUS " << (int)std::unique_ptr<Instruction>::PLUS << std::endl;
return Token{ bfParser_Symbol::T_PLUS, std::move(pm) };
} case BfLexer::MINUS: {
pm.push_back(Instruction::MINUS);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(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<InstructionDec>());
//std::cout << "PARSING: found MINUS" << (int)std::unique_ptr<Instruction>::MINUS << std::endl;
return Token{ bfParser_Symbol::T_MINUS, std::move(pm) };
} case BfLexer::GREATER: {
pm.push_back(Instruction::GREATER);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(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<InstructionRight>());
//std::cout << "PARSING: found GREATER" << (int)std::unique_ptr<Instruction>::GREATER << std::endl;
return Token{ bfParser_Symbol::T_GREATER, std::move(pm) };
} case BfLexer::LESS: {
pm.push_back(Instruction::LESS);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(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<InstructionLeft>());
//std::cout << "PARSING: found LESS" << (int)std::unique_ptr<Instruction>::LESS << std::endl;
return Token{ bfParser_Symbol::T_LESS, std::move(pm) };
} case BfLexer::POINT: {
pm.push_back(Instruction::POINT);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(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<InstructionOut>());
//std::cout << "PARSING: found POINT" << (int)std::unique_ptr<Instruction>::POINT << std::endl;
return Token{ bfParser_Symbol::T_POINT, std::move(pm) };
} case BfLexer::COMMA: {
pm.push_back(Instruction::COMMA);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(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<InstructionIn>());
//std::cout << "PARSING: found COMMA" << (int)std::unique_ptr<Instruction>::COMMA << std::endl;
return Token{ bfParser_Symbol::T_COMMA, std::move(pm) };
} case BfLexer::LBRACKET: {
pm.push_back(Instruction::LBRACKET);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(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<Instruction>::LBRACKET << std::endl;
return Token{ bfParser_Symbol::T_LBRACKET, nullptr };
} case BfLexer::RBRACKET: {
pm.push_back(Instruction::RBRACKET);
std::unique_ptr<std::deque<Instruction>> p = std::make_unique<std::deque<Instruction>>(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<Instruction>::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<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>
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<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> ::=
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"
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"
subparts[1].value->push_front(Instruction::LBRACKET);
subparts[1].value->push_back(Instruction::RBRACKET);
auto res = std::make_unique<std::deque<std::unique_ptr<Instruction>>>();
res->push_back(std::make_unique<InstructionLoop>(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);
}

View File

@ -33,17 +33,17 @@
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:
Parser(BfLexer lex);
protected:
Token lex() override;
std::unique_ptr<std::deque<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<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_PROGRAM(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<std::unique_ptr<Instruction>>> reduce_OPERATION(std::deque<Token> subparts) override;
std::unique_ptr<std::deque<std::unique_ptr<Instruction>>> reduce_LOOP(std::deque<Token> subparts) override;
private:
BfLexer m_lex;