Split BFMachine into its own files
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
project(BrainfuckInterpretter)
|
||||
project(BFInterpreter)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
add_executable(BrainfuckInterpretter main.cpp)
|
||||
set(SOURCE
|
||||
src/main.cpp
|
||||
src/BFMachine.cpp)
|
||||
|
||||
add_executable(BFInterpreter ${SOURCE})
|
||||
|
||||
target_include_directories(BFInterpreter PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
41
include/BFMachine.hpp
Normal file
41
include/BFMachine.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Created by Aaron Helton on 5/28/22.
|
||||
*/
|
||||
|
||||
#ifndef BRAINFUCKINTERPRETTER_BFMACHINE_HPP
|
||||
#define BRAINFUCKINTERPRETTER_BFMACHINE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#define MAX_MEMORY_SIZE 30000
|
||||
|
||||
#define RETURN_SUCCESS 0
|
||||
#define RETURN_INVALID_MEMORY_ADDRESS 1
|
||||
#define RETURN_INVALID_INSTRUCTION 2
|
||||
|
||||
class BFMachine
|
||||
{
|
||||
public:
|
||||
BFMachine();
|
||||
~BFMachine();
|
||||
void load(const char *instructions);
|
||||
int execute();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
uint8_t* memory;
|
||||
const char *program{};
|
||||
size_t programIndex{};
|
||||
size_t dataIndex{};
|
||||
int error{};
|
||||
|
||||
void increment();
|
||||
void decrement();
|
||||
void incrementDataPointer();
|
||||
void decrementDataPointer();
|
||||
void printByte();
|
||||
void readByte();
|
||||
};
|
||||
|
||||
#endif //BRAINFUCKINTERPRETTER_BFMACHINE_HPP
|
||||
229
main.cpp
229
main.cpp
@@ -1,229 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#define MAX_MEMORY_SIZE 30000
|
||||
|
||||
#define RETURN_SUCCESS 0
|
||||
#define RETURN_INVALID_MEMORY_ADDRESS 1
|
||||
#define RETURN_INVALID_INSTRUCTION 2
|
||||
|
||||
class BFMachine
|
||||
{
|
||||
public:
|
||||
BFMachine();
|
||||
~BFMachine();
|
||||
void load(const char *instructions);
|
||||
int execute();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
uint8_t* memory;
|
||||
const char *program{};
|
||||
size_t programIndex{};
|
||||
size_t dataIndex{};
|
||||
int error{};
|
||||
|
||||
void increment();
|
||||
void decrement();
|
||||
void incrementDataPointer();
|
||||
void decrementDataPointer();
|
||||
void printByte();
|
||||
void readByte();
|
||||
};
|
||||
|
||||
BFMachine::BFMachine()
|
||||
{
|
||||
this->memory = new uint8_t[MAX_MEMORY_SIZE];
|
||||
this->reset();
|
||||
}
|
||||
|
||||
BFMachine::~BFMachine()
|
||||
{
|
||||
delete[] memory;
|
||||
memory = nullptr;
|
||||
}
|
||||
|
||||
void BFMachine::load(const char *instructions)
|
||||
{
|
||||
this->program = instructions;
|
||||
}
|
||||
|
||||
void BFMachine::reset()
|
||||
{
|
||||
memset(this->memory, 0, sizeof(uint8_t)*MAX_MEMORY_SIZE);
|
||||
this->dataIndex = 0;
|
||||
this->programIndex = 0;
|
||||
this->program = nullptr;
|
||||
this->error = RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
int BFMachine::execute()
|
||||
{
|
||||
if(!this->program)
|
||||
return RETURN_SUCCESS;
|
||||
while(this->error == RETURN_SUCCESS && program[programIndex] != '\0')
|
||||
{
|
||||
unsigned char command = program[programIndex];
|
||||
switch(command)
|
||||
{
|
||||
case '>': incrementDataPointer(); break;
|
||||
case '<': decrementDataPointer(); break;
|
||||
case '+': increment(); break;
|
||||
case '-': decrement(); break;
|
||||
case '.': printByte(); break;
|
||||
case ',': readByte(); break;
|
||||
case '[':
|
||||
if(this->memory[this->dataIndex] == 0)
|
||||
{
|
||||
uint8_t depth = 1;
|
||||
while(this->program[programIndex] != ']' || depth != 0)
|
||||
{
|
||||
programIndex++;
|
||||
if(program[programIndex] == '\0')
|
||||
{
|
||||
this->error = RETURN_INVALID_INSTRUCTION;
|
||||
break;
|
||||
}
|
||||
if(program[programIndex] == '[')
|
||||
depth++;
|
||||
if(program[programIndex] == ']')
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ']':
|
||||
if(this->memory[this->dataIndex] != 0)
|
||||
{
|
||||
uint8_t depth = 1;
|
||||
while(this->program[programIndex] != '[' || depth != 0)
|
||||
{
|
||||
if(programIndex == 0)
|
||||
{
|
||||
this->error = RETURN_INVALID_INSTRUCTION;
|
||||
break;
|
||||
}
|
||||
programIndex--;
|
||||
if(program[programIndex] == '[')
|
||||
depth--;
|
||||
if(program[programIndex] == ']')
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
programIndex++;
|
||||
}
|
||||
return this->error;
|
||||
}
|
||||
|
||||
void BFMachine::increment()
|
||||
{
|
||||
this->memory[this->dataIndex]++;
|
||||
}
|
||||
|
||||
void BFMachine::decrement()
|
||||
{
|
||||
this->memory[this->dataIndex]--;
|
||||
}
|
||||
|
||||
void BFMachine::incrementDataPointer()
|
||||
{
|
||||
this->dataIndex++;
|
||||
if(this->dataIndex >= MAX_MEMORY_SIZE)
|
||||
{
|
||||
this->error = RETURN_INVALID_MEMORY_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
void BFMachine::decrementDataPointer()
|
||||
{
|
||||
if(this->dataIndex == 0)
|
||||
{
|
||||
this->error = RETURN_INVALID_MEMORY_ADDRESS;
|
||||
return;
|
||||
}
|
||||
this->dataIndex--;
|
||||
}
|
||||
|
||||
void BFMachine::printByte()
|
||||
{
|
||||
auto c = reinterpret_cast<unsigned char>(this->memory[this->dataIndex]);
|
||||
std::cout << c;
|
||||
}
|
||||
|
||||
void BFMachine::readByte()
|
||||
{
|
||||
unsigned char c;
|
||||
std::cin >> c;
|
||||
this->memory[this->dataIndex] = reinterpret_cast<uint8_t>(c);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BFMachine machine;
|
||||
const char* instructions =
|
||||
"[ This program prints \"Hello World!\" and a newline to the screen, its\n"
|
||||
" length is 106 active command characters. [It is not the shortest.]\n"
|
||||
"\n"
|
||||
" This loop is an \"initial comment loop\", a simple way of adding a comment\n"
|
||||
" to a BF program such that you don't have to worry about any command\n"
|
||||
" characters. Any \".\", \",\", \"+\", \"-\", \"<\" and \">\" characters are simply\n"
|
||||
" ignored, the \"[\" and \"]\" characters just have to be balanced. This\n"
|
||||
" loop and the commands it contains are ignored because the current cell\n"
|
||||
" defaults to a value of 0; the 0 value causes this loop to be skipped.\n"
|
||||
"]\n"
|
||||
"++++++++ Set Cell #0 to 8\n"
|
||||
"[\n"
|
||||
" >++++ Add 4 to Cell #1; this will always set Cell #1 to 4\n"
|
||||
" [ as the cell will be cleared by the loop\n"
|
||||
" >++ Add 2 to Cell #2\n"
|
||||
" >+++ Add 3 to Cell #3\n"
|
||||
" >+++ Add 3 to Cell #4\n"
|
||||
" >+ Add 1 to Cell #5\n"
|
||||
" <<<<- Decrement the loop counter in Cell #1\n"
|
||||
" ] Loop until Cell #1 is zero; number of iterations is 4\n"
|
||||
" >+ Add 1 to Cell #2\n"
|
||||
" >+ Add 1 to Cell #3\n"
|
||||
" >- Subtract 1 from Cell #4\n"
|
||||
" >>+ Add 1 to Cell #6\n"
|
||||
" [<] Move back to the first zero cell you find; this will\n"
|
||||
" be Cell #1 which was cleared by the previous loop\n"
|
||||
" <- Decrement the loop Counter in Cell #0\n"
|
||||
"] Loop until Cell #0 is zero; number of iterations is 8\n"
|
||||
"\n"
|
||||
"The result of this is:\n"
|
||||
"Cell no : 0 1 2 3 4 5 6\n"
|
||||
"Contents: 0 0 72 104 88 32 8\n"
|
||||
"Pointer : ^\n"
|
||||
"\n"
|
||||
">>. Cell #2 has value 72 which is 'H'\n"
|
||||
">---. Subtract 3 from Cell #3 to get 101 which is 'e'\n"
|
||||
"+++++++..+++. Likewise for 'llo' from Cell #3\n"
|
||||
">>. Cell #5 is 32 for the space\n"
|
||||
"<-. Subtract 1 from Cell #4 for 87 to give a 'W'\n"
|
||||
"<. Cell #3 was set to 'o' from the end of 'Hello'\n"
|
||||
"+++.------.--------. Cell #3 for 'rl' and 'd'\n"
|
||||
">>+. Add 1 to Cell #5 gives us an exclamation point\n"
|
||||
">++. And finally a newline from Cell #6";
|
||||
|
||||
machine.load(instructions);
|
||||
int ret = machine.execute();
|
||||
if(ret != 0)
|
||||
{
|
||||
std::cout << "An error occurred. Error is: ";
|
||||
switch(ret)
|
||||
{
|
||||
case RETURN_INVALID_INSTRUCTION:
|
||||
std::cout << "Invalid Instruction"; break;
|
||||
case RETURN_INVALID_MEMORY_ADDRESS:
|
||||
std::cout << "Invalid Memory Access"; break;
|
||||
default:
|
||||
std::cout << "Unknown Error"; break;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout.flush();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
136
src/BFMachine.cpp
Normal file
136
src/BFMachine.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Created by Aaron Helton on 5/28/22.
|
||||
*/
|
||||
|
||||
#include <BFMachine.hpp>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
BFMachine::BFMachine()
|
||||
{
|
||||
this->memory = new uint8_t[MAX_MEMORY_SIZE];
|
||||
this->reset();
|
||||
}
|
||||
|
||||
BFMachine::~BFMachine()
|
||||
{
|
||||
delete[] memory;
|
||||
memory = nullptr;
|
||||
}
|
||||
|
||||
void BFMachine::load(const char *instructions)
|
||||
{
|
||||
this->program = instructions;
|
||||
}
|
||||
|
||||
void BFMachine::reset()
|
||||
{
|
||||
memset(this->memory, 0, sizeof(uint8_t)*MAX_MEMORY_SIZE);
|
||||
this->dataIndex = 0;
|
||||
this->programIndex = 0;
|
||||
this->program = nullptr;
|
||||
this->error = RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
int BFMachine::execute()
|
||||
{
|
||||
if(!this->program)
|
||||
return RETURN_SUCCESS;
|
||||
while(this->error == RETURN_SUCCESS && program[programIndex] != '\0')
|
||||
{
|
||||
unsigned char command = program[programIndex];
|
||||
switch(command)
|
||||
{
|
||||
case '>': incrementDataPointer(); break;
|
||||
case '<': decrementDataPointer(); break;
|
||||
case '+': increment(); break;
|
||||
case '-': decrement(); break;
|
||||
case '.': printByte(); break;
|
||||
case ',': readByte(); break;
|
||||
case '[':
|
||||
if(this->memory[this->dataIndex] == 0)
|
||||
{
|
||||
uint8_t depth = 1;
|
||||
while(this->program[programIndex] != ']' || depth != 0)
|
||||
{
|
||||
programIndex++;
|
||||
if(program[programIndex] == '\0')
|
||||
{
|
||||
this->error = RETURN_INVALID_INSTRUCTION;
|
||||
break;
|
||||
}
|
||||
if(program[programIndex] == '[')
|
||||
depth++;
|
||||
if(program[programIndex] == ']')
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ']':
|
||||
if(this->memory[this->dataIndex] != 0)
|
||||
{
|
||||
uint8_t depth = 1;
|
||||
while(this->program[programIndex] != '[' || depth != 0)
|
||||
{
|
||||
if(programIndex == 0)
|
||||
{
|
||||
this->error = RETURN_INVALID_INSTRUCTION;
|
||||
break;
|
||||
}
|
||||
programIndex--;
|
||||
if(program[programIndex] == '[')
|
||||
depth--;
|
||||
if(program[programIndex] == ']')
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
programIndex++;
|
||||
}
|
||||
return this->error;
|
||||
}
|
||||
|
||||
void BFMachine::increment()
|
||||
{
|
||||
this->memory[this->dataIndex]++;
|
||||
}
|
||||
|
||||
void BFMachine::decrement()
|
||||
{
|
||||
this->memory[this->dataIndex]--;
|
||||
}
|
||||
|
||||
void BFMachine::incrementDataPointer()
|
||||
{
|
||||
this->dataIndex++;
|
||||
if(this->dataIndex >= MAX_MEMORY_SIZE)
|
||||
{
|
||||
this->error = RETURN_INVALID_MEMORY_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
void BFMachine::decrementDataPointer()
|
||||
{
|
||||
if(this->dataIndex == 0)
|
||||
{
|
||||
this->error = RETURN_INVALID_MEMORY_ADDRESS;
|
||||
return;
|
||||
}
|
||||
this->dataIndex--;
|
||||
}
|
||||
|
||||
void BFMachine::printByte()
|
||||
{
|
||||
auto c = reinterpret_cast<unsigned char>(this->memory[this->dataIndex]);
|
||||
std::cout << c;
|
||||
}
|
||||
|
||||
void BFMachine::readByte()
|
||||
{
|
||||
unsigned char c;
|
||||
std::cin >> c;
|
||||
this->memory[this->dataIndex] = reinterpret_cast<uint8_t>(c);
|
||||
}
|
||||
70
src/main.cpp
Normal file
70
src/main.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include <BFMachine.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main()
|
||||
{
|
||||
BFMachine machine;
|
||||
const char* instructions =
|
||||
"[ This program prints \"Hello World!\" and a newline to the screen, its\n"
|
||||
" length is 106 active command characters. [It is not the shortest.]\n"
|
||||
"\n"
|
||||
" This loop is an \"initial comment loop\", a simple way of adding a comment\n"
|
||||
" to a BF program such that you don't have to worry about any command\n"
|
||||
" characters. Any \".\", \",\", \"+\", \"-\", \"<\" and \">\" characters are simply\n"
|
||||
" ignored, the \"[\" and \"]\" characters just have to be balanced. This\n"
|
||||
" loop and the commands it contains are ignored because the current cell\n"
|
||||
" defaults to a value of 0; the 0 value causes this loop to be skipped.\n"
|
||||
"]\n"
|
||||
"++++++++ Set Cell #0 to 8\n"
|
||||
"[\n"
|
||||
" >++++ Add 4 to Cell #1; this will always set Cell #1 to 4\n"
|
||||
" [ as the cell will be cleared by the loop\n"
|
||||
" >++ Add 2 to Cell #2\n"
|
||||
" >+++ Add 3 to Cell #3\n"
|
||||
" >+++ Add 3 to Cell #4\n"
|
||||
" >+ Add 1 to Cell #5\n"
|
||||
" <<<<- Decrement the loop counter in Cell #1\n"
|
||||
" ] Loop until Cell #1 is zero; number of iterations is 4\n"
|
||||
" >+ Add 1 to Cell #2\n"
|
||||
" >+ Add 1 to Cell #3\n"
|
||||
" >- Subtract 1 from Cell #4\n"
|
||||
" >>+ Add 1 to Cell #6\n"
|
||||
" [<] Move back to the first zero cell you find; this will\n"
|
||||
" be Cell #1 which was cleared by the previous loop\n"
|
||||
" <- Decrement the loop Counter in Cell #0\n"
|
||||
"] Loop until Cell #0 is zero; number of iterations is 8\n"
|
||||
"\n"
|
||||
"The result of this is:\n"
|
||||
"Cell no : 0 1 2 3 4 5 6\n"
|
||||
"Contents: 0 0 72 104 88 32 8\n"
|
||||
"Pointer : ^\n"
|
||||
"\n"
|
||||
">>. Cell #2 has value 72 which is 'H'\n"
|
||||
">---. Subtract 3 from Cell #3 to get 101 which is 'e'\n"
|
||||
"+++++++..+++. Likewise for 'llo' from Cell #3\n"
|
||||
">>. Cell #5 is 32 for the space\n"
|
||||
"<-. Subtract 1 from Cell #4 for 87 to give a 'W'\n"
|
||||
"<. Cell #3 was set to 'o' from the end of 'Hello'\n"
|
||||
"+++.------.--------. Cell #3 for 'rl' and 'd'\n"
|
||||
">>+. Add 1 to Cell #5 gives us an exclamation point\n"
|
||||
">++. And finally a newline from Cell #6";
|
||||
|
||||
machine.load(instructions);
|
||||
int ret = machine.execute();
|
||||
if(ret != 0)
|
||||
{
|
||||
std::cout << "An error occurred. Error is: ";
|
||||
switch(ret)
|
||||
{
|
||||
case RETURN_INVALID_INSTRUCTION:
|
||||
std::cout << "Invalid Instruction"; break;
|
||||
case RETURN_INVALID_MEMORY_ADDRESS:
|
||||
std::cout << "Invalid Memory Access"; break;
|
||||
default:
|
||||
std::cout << "Unknown Error"; break;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout.flush();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user