Implemented a brainfuck object which holds all variables
This commit is contained in:
2
Makefile
2
Makefile
@@ -7,7 +7,7 @@ HFILES=$(shell find . -name '*.h')
|
|||||||
STYLE=astyle --style=1tbs
|
STYLE=astyle --style=1tbs
|
||||||
RUN=valgrind --leak-check=full
|
RUN=valgrind --leak-check=full
|
||||||
DEBUG=gdb --args
|
DEBUG=gdb --args
|
||||||
ARGS="examples/rot13.bf"
|
ARGS="examples/pi.bf"
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
|
|||||||
146
bfckr.c
146
bfckr.c
@@ -12,21 +12,46 @@
|
|||||||
#include<errno.h>
|
#include<errno.h>
|
||||||
#include<assert.h>
|
#include<assert.h>
|
||||||
#include<ctype.h>
|
#include<ctype.h>
|
||||||
|
#include<stdbool.h>
|
||||||
|
|
||||||
// Amount of memory on the band tape
|
// Defines
|
||||||
#define MEMORY_SIZE 10000
|
#define MEMORY_SIZE 10000
|
||||||
#define MAX_INPUT_SIZE 10000
|
#define MAX_INPUT_SIZE 10000
|
||||||
#define clear() printf("\033[H\033[J")
|
#define clear() printf("\033[H\033[J")
|
||||||
|
|
||||||
// Memory initialized with zeros and its pointer
|
// Struct which holds the brainfuck code, the bandtape and some helpervariables
|
||||||
char memory[MEMORY_SIZE] = {0};
|
typedef struct bf_code_s {
|
||||||
char *p = memory;
|
char memory[MEMORY_SIZE]; // Memory initialized
|
||||||
int memcnt = 0;
|
size_t mp; // Memory pointer
|
||||||
|
char code[MAX_INPUT_SIZE]; // Input buffer for the bf code
|
||||||
|
size_t ip; // Instruction pointer
|
||||||
|
bool debug; // debug flag
|
||||||
|
} bf_code_t;
|
||||||
|
|
||||||
// Prototypes
|
// Prototypes
|
||||||
void bfuck_parser(char *input);
|
void bfuck_parser(bf_code_t *bf);
|
||||||
|
void bfuck_debugger(bf_code_t *bf);
|
||||||
|
void print_sourceviewer(bf_code_t *bf);
|
||||||
|
void print_memoryviewer(bf_code_t *bf);
|
||||||
|
void init_bf_object(bf_code_t *bf);
|
||||||
|
|
||||||
// Error handler
|
/* initialize bf object */
|
||||||
|
void init_bf_object(bf_code_t *bf)
|
||||||
|
{
|
||||||
|
bf->mp = 0; // set data pointer to zero
|
||||||
|
bf->ip = 0; // set instruction pointer to zero
|
||||||
|
bf->debug = false; // reset the debug flag
|
||||||
|
|
||||||
|
for(size_t i = 0; i < MEMORY_SIZE; i++) {
|
||||||
|
bf->memory[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < MAX_INPUT_SIZE; i++) {
|
||||||
|
bf->code[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error handler */
|
||||||
void die(const char *message)
|
void die(const char *message)
|
||||||
{
|
{
|
||||||
if(errno) {
|
if(errno) {
|
||||||
@@ -38,40 +63,40 @@ void die(const char *message)
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints the bf source at the current location
|
/* Prints the bf source at the current location */
|
||||||
void print_sourceviewer()
|
void print_sourceviewer(bf_code_t *bf)
|
||||||
{
|
{
|
||||||
printf("Source viewer:"
|
printf("\nSource viewer: \n"
|
||||||
"-----------------------------------------------------------"
|
"-----------------------------------------------------------\n"
|
||||||
"_____________________________>+++++++++++++++[<+>>>>>>>>+++"
|
"_____________________________>+++++++++++++++[<+>>>>>>>>+++\n"
|
||||||
" ^ "
|
" ^ \n"
|
||||||
" ip=0 "
|
" ip=0 \n"
|
||||||
"-----------------------------------------------------------"); // just to get the idea ...
|
"-----------------------------------------------------------\n"); // just to get the idea ...
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints memory information at the current memory location
|
/* Prints memory information at the current memory location */
|
||||||
void print_memoryviewer()
|
void print_memoryviewer(bf_code_t *bf)
|
||||||
{
|
{
|
||||||
int pointerlocation = (p - memory)*sizeof(*memory); // find the arrayindex at which the pointer is pointing
|
// int pointerlocation = (p - memory)*sizeof(*memory); // find the arrayindex at which the pointer is pointing
|
||||||
|
|
||||||
printf("Memory viewer: "
|
printf("\nMemory viewer: \n"
|
||||||
"-----------------------------------------------------------"
|
"-----------------------------------------------------------\n"
|
||||||
"000 000 000 000 000 000 001 001 000 000 000 000 000 000 000"
|
"000 000 000 000 000 000 001 001 000 000 000 000 000 000 000\n"
|
||||||
" ^ "
|
" ^ \n"
|
||||||
" mp=1 "
|
" mp=1 \n"
|
||||||
"249 250 251 252 253 254 000 001 002 003 004 005 006 007 008"
|
"249 250 251 252 253 254 000 001 002 003 004 005 006 007 008\n"
|
||||||
"-----------------------------------------------------------"); // just to get the idea ...
|
"-----------------------------------------------------------\n"); // just to get the idea ...
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pauses the program flow and prints information
|
/* Pauses the program flow and prints information */
|
||||||
void bfuck_debugger(char *bf_source_input, int instructionpointer)
|
void bfuck_debugger(bf_code_t *bf) //char *bf_source_input, int instructionpointer)
|
||||||
{
|
{
|
||||||
clear(); // clear terminal
|
clear(); // clear terminal
|
||||||
|
|
||||||
printf("[s]: single step [c]: continue");
|
printf("[s]: single step [c]: continue\n");
|
||||||
|
|
||||||
print_sourceviewer();
|
print_sourceviewer(bf);
|
||||||
print_memoryviewer();
|
print_memoryviewer(bf);
|
||||||
|
|
||||||
switch(getchar()) {
|
switch(getchar()) {
|
||||||
case 's':
|
case 's':
|
||||||
@@ -79,64 +104,61 @@ void bfuck_debugger(char *bf_source_input, int instructionpointer)
|
|||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
// continue
|
// continue
|
||||||
|
bf->debug = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses and executes a brainfuck expression
|
/* Parses and executes a brainfuck expression */
|
||||||
void bfuck_execute(char *input)
|
void bfuck_execute(bf_code_t *bf)
|
||||||
{
|
{
|
||||||
int loop = 0;
|
int loop = 0;
|
||||||
|
|
||||||
for(size_t i = 0; input[i] != 0; i++) { // where i is the instruction pointer
|
for(size_t i = bf->ip; bf->code[i] != 0; bf->ip=i++) { // where i is the instruction pointer
|
||||||
switch(input[i]) {
|
switch(bf->code[i]) {
|
||||||
case '>':
|
case '>':
|
||||||
if(memcnt >= MEMORY_SIZE) { // prevent overrun
|
if(bf->mp >= MEMORY_SIZE) { // prevent overrun
|
||||||
p = &memory[0];
|
bf->mp = 0;
|
||||||
memcnt = 0;
|
|
||||||
} else {
|
} else {
|
||||||
++p; // increment data pointer
|
++(bf->mp); // increment memory pointer
|
||||||
++memcnt;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '<':
|
case '<':
|
||||||
if(memcnt < 0) { // prevent underun
|
if(bf->mp < 0) { // prevent underun
|
||||||
p = &memory[MEMORY_SIZE - 1];
|
bf->mp = MEMORY_SIZE-1;
|
||||||
memcnt = MEMORY_SIZE - 1;
|
|
||||||
} else {
|
} else {
|
||||||
--p; // decrement data pointer
|
--(bf->mp); // decrement memory pointer
|
||||||
--memcnt;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '+':
|
case '+':
|
||||||
++(*p); // increment byte at data pointer
|
++(bf->memory[bf->mp]); // increment byte at memory pointer
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
--(*p); // decrement byte at data pointer
|
--(bf->memory[bf->mp]); // decrement byte at memory pointer
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '.':
|
case '.':
|
||||||
putchar(*p); // output the byte at data pointer
|
putchar(bf->memory[bf->mp]); // output the byte at memory pointer
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ',':
|
case ',':
|
||||||
*p = getchar(); // accept one byte of input and store it at data pointer
|
bf->memory[bf->mp] = getchar(); // accept one byte of input and store it at memory pointer
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '[':
|
case '[':
|
||||||
if(*p == 0) { // if the byte at the data pointer is zero
|
if(bf->memory[bf->mp] == 0) { // if the byte at the memory pointer is zero
|
||||||
// jump forward to the command after the next ]
|
// jump forward to the command after the next ]
|
||||||
loop = 1;
|
loop = 1;
|
||||||
while(loop > 0) { // count nested loops and make sure to get the matching ]
|
while(loop > 0) { // count nested loops and make sure to get the matching ]
|
||||||
i++;
|
bf->ip = i++;
|
||||||
if(input[i] == '[') {
|
if(bf->code[i] == '[') {
|
||||||
loop++;
|
loop++;
|
||||||
}
|
}
|
||||||
if(input[i] == ']') {
|
if(bf->code[i] == ']') {
|
||||||
loop--;
|
loop--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,15 +168,15 @@ void bfuck_execute(char *input)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ']':
|
case ']':
|
||||||
if(*p != 0) { // if the byte at the data pointer is nonzero
|
if(bf->memory[bf->mp] != 0) { // if the byte at the memory pointer is nonzero
|
||||||
// jump back to the command after the matching [
|
// jump back to the command after the matching [
|
||||||
loop = 1;
|
loop = 1;
|
||||||
while(loop > 0) { // count nested loops and make sure to get the matching [
|
while(loop > 0) { // count nested loops and make sure to get the matching [
|
||||||
i--;
|
bf->ip = i--;
|
||||||
if(input[i] == '[') {
|
if(bf->code[i] == '[') {
|
||||||
loop--;
|
loop--;
|
||||||
}
|
}
|
||||||
if(input[i] == ']') {
|
if(bf->code[i] == ']') {
|
||||||
loop++;
|
loop++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,6 +188,7 @@ void bfuck_execute(char *input)
|
|||||||
|
|
||||||
case '#':
|
case '#':
|
||||||
// Breakpoint reached, start debugger ...
|
// Breakpoint reached, start debugger ...
|
||||||
|
bf->debug = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -180,13 +203,16 @@ int main(int argc, char* argv[])
|
|||||||
FILE *fp;
|
FILE *fp;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int c;
|
int c;
|
||||||
char input[MAX_INPUT_SIZE];
|
bf_code_t bf;
|
||||||
|
|
||||||
// check arguments
|
// check arguments
|
||||||
if(argc < 2) {
|
if(argc < 2) {
|
||||||
die("Need more arguments.");
|
die("Need more arguments.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initialize bf object
|
||||||
|
init_bf_object(&bf);
|
||||||
|
|
||||||
// try to open file
|
// try to open file
|
||||||
if((fp = fopen(argv[1], "rt")) == NULL) {
|
if((fp = fopen(argv[1], "rt")) == NULL) {
|
||||||
die("Couldn't open file.");
|
die("Couldn't open file.");
|
||||||
@@ -194,14 +220,14 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
// read the file and store it in the input buffer
|
// read the file and store it in the input buffer
|
||||||
while((c = getc(fp)) != EOF) {
|
while((c = getc(fp)) != EOF) {
|
||||||
input[i++] = c;
|
bf.code[i++] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// close file after reading
|
// close file after reading
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
// try to interpret it
|
// try to interpret it
|
||||||
bfuck_execute(input);
|
bfuck_execute(&bf);
|
||||||
|
|
||||||
// exit
|
// exit
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|||||||
Reference in New Issue
Block a user