bf rewrite, fixes tests
This commit is contained in:
parent
f4bba7dd5e
commit
e4647f0ed4
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue