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