Merge branch 'master' of github.com:id101010/bfckr

This commit is contained in:
id101010
2019-08-03 19:24:04 +02:00
5 changed files with 134 additions and 42 deletions

View File

@@ -1,3 +1,2 @@
install: make get-deps
script: make script: make
language: c language: c

View File

@@ -30,3 +30,11 @@ run:
memtest: memtest:
$(RUN) ./$(PRGNAME) $(ARGS) $(RUN) ./$(PRGNAME) $(ARGS)
install:
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp -f bfckr $(DESTDIR)$(PREFIX)/bin
chmod 755 $(DESTDIR)$(PREFIX)/bin/bfckr
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/bfckr

View File

@@ -1,4 +1,4 @@
# bfckr # bfckr [![Build Status](https://travis-ci.org/id101010/bfckr.svg?branch=master)](https://travis-ci.org/id101010/bfckr)
A little brainfuck interpreter written in C. A little brainfuck interpreter written in C.
# How to run # How to run

153
bfckr.c
View File

@@ -30,13 +30,13 @@ typedef struct bf_code_s {
} bf_code_t; } bf_code_t;
// Prototypes // Prototypes
void bfuck_parser(bf_code_t *bf); static void bfuck_debugger(bf_code_t *bf);
void bfuck_debugger(bf_code_t *bf); static void print_sourceviewer(bf_code_t *bf);
void print_sourceviewer(bf_code_t *bf); static void print_memoryviewer(bf_code_t *bf);
void print_memoryviewer(bf_code_t *bf); static void init_bf_object(bf_code_t *bf);
void init_bf_object(bf_code_t *bf); static bool is_brainfuck(char c);
bool is_brainfuck(char c); static char *colorize(char c);
char *colorize(char c); static void print_delimiter(char c, size_t length);
int getopt(int argc, char * const argv[], const char *optstring); int getopt(int argc, char * const argv[], const char *optstring);
// Globals // Globals
@@ -53,10 +53,16 @@ char *colortheme[] = {
"\e[1;32m-\e[0m", // green - "\e[1;32m-\e[0m", // green -
"\e[1;31m.\e[0m", // red . "\e[1;31m.\e[0m", // red .
"\e[1;31m,\e[0m", // red , "\e[1;31m,\e[0m", // red ,
"\e[1;31m#\e[0m", // red #
}; };
// Colorize instructions /**
char *colorize(char c) * @brief Colorize the ouput string using a colorscheme table
* @type static
* @param[in] Single character to be colorized
* @return Colorized string
**/
static char *colorize(char c)
{ {
char *cs = 0; // colorstring char *cs = 0; // colorstring
@@ -85,13 +91,24 @@ char *colorize(char c)
case ',': case ',':
cs = colortheme[7]; cs = colortheme[7];
break; break;
case '#':
cs = colortheme[8];
break;
default:
;
break;
} }
return cs; return cs;
} }
/* initialize bf object */ /**
void init_bf_object(bf_code_t *bf) * @brief Initialize a brainfuck object by setting all values to zero
* @type static
* @param[in] Pointer to a bf_code_t type
* @return void
**/
static void init_bf_object(bf_code_t *bf)
{ {
bf->mp = 0; // set data pointer to zero bf->mp = 0; // set data pointer to zero
bf->ip = 0; // set instruction pointer to zero bf->ip = 0; // set instruction pointer to zero
@@ -111,13 +128,24 @@ void init_bf_object(bf_code_t *bf)
} }
bool is_brainfuck(char c) /**
* @brief Tests if a single character contains a valid brainfuck instruction
* @type static
* @param[in] char c containing a brainfuck instruction to test
* @return bool which is true if the instruction is in brainfuck set or false if not
**/
static bool is_brainfuck(char c)
{ {
return (c=='+') || (c=='-') || (c=='>') || (c=='<') || (c=='.') || (c==',') || (c=='[') || (c==']' || (c=='#')); return (c=='+') || (c=='-') || (c=='>') || (c=='<') || (c=='.') || (c==',') || (c=='[') || (c==']' || (c=='#'));
} }
/* Error handler */ /**
void die(const char *message) * @brief Error handler function wich shuts down the application and prints to stderr
* @type static
* @param[in] Message string
* @return void
**/
static void die(const char *message)
{ {
if(errno) { if(errno) {
perror(message); perror(message);
@@ -128,53 +156,81 @@ void die(const char *message)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* prints the current output buffered in global output_buffer */ /**
void print_output() * @brief Prints a delimiter line with the given length and character
* @type static
* @param[in] char delimiter Character for the delimiter line
* @param[in] size_t length Length of the line to print
* @return void
**/
static void print_delimiter(char c, size_t length)
{ {
printf("\nOutput viewer: \n"); for(size_t i = 0; i <= length; i++) {
printf("------------------------------------------------------------\n"); // 61 dashes printf("%c", c);
}
printf("\n");
}
/**
* @brief Prints the current ouput buffered in global output_buffer
* @type static
* @param[in] void
* @return void
**/
static void print_output()
{
printf("\nOutput viewer:\n");
print_delimiter('-', 61);
// print the output buffer // print the output buffer
for(size_t i = 0; i < n_output_buffer; i++) { for(size_t i = 0; i < n_output_buffer; i++) {
printf("\e[1;31m%c\e[0m", output_buffer[i]); printf("\e[1;31m%c\e[0m", output_buffer[i]);
} }
printf("\n------------------------------------------------------------\n"); printf("\n");
print_delimiter('-', 61);
} }
/* Prints the bf source at the current location */ /**
void print_sourceviewer(bf_code_t *bf) * @brief Prints the bf source code at the current location
* @type static
* @param[in] Pointer to a bf_code_t type
* @return void
**/
static void print_sourceviewer(bf_code_t *bf)
{ {
int ip = (int)bf->ip; // save instruction pointer int ip = (int)bf->ip; // save instruction pointer
printf("\nSource viewer: \n"); printf("\nSource viewer:\n");
printf("------------------------------------------------------------\n"); // 61 dashes print_delimiter('-', 61);
// print 30 valid chars before $ip and 30 after // print 30 valid chars before $ip and 30 after
for(int i=(ip-30); i<(ip+30); i++) { for(int i=(ip-30); i<(ip+30); i++) {
printf("%s",((i<0 || i>=strlen(bf->code)) ? " ": colorize(bf->code[i]))); printf("%s",((i<0 || i>=strlen(bf->code)) ? " ": colorize(bf->code[i])));
} }
printf("\n \e[1;31m^\e[0m \n"); printf("\n \e[1;31m^\e[0m \n");
printf(" \e[1;31mip=%d\e[0m \n", ip); printf(" \e[1;31mip=%d\e[0m \n", ip);
printf("------------------------------------------------------------\n"); print_delimiter('-', 61);
} }
/* Prints memory information at the current memory location */ /**
* @brief Prints a memory dump at the current memory location
* @type static
* @param[in] Pointer to a bf_code_t type
* @return void
**/
void print_memoryviewer(bf_code_t *bf) void print_memoryviewer(bf_code_t *bf)
{ {
int mp = (int)bf->mp; // save the current memory pointer int mp = (int)bf->mp; // save the current memory pointer
printf("\nMemory viewer: \n"); printf("\nMemory viewer:\n");
printf("------------------------------------------------------------\n"); // 61 dashes print_delimiter('-', 61);
// print the memory cells // print the memory cells
for(int i=(mp-7); i<(mp+8); i++) { for(int i=(mp-7); i<(mp+8); i++) {
printf("%03d ", ((i<0 || i>MEMORY_SIZE) ? 0 : bf->memory[i])); printf("%03d ", ((i<0 || i>MEMORY_SIZE) ? 0 : bf->memory[i]));
} }
// Print the pointers
printf("\n \e[1;31m^\e[0m \n"); printf("\n \e[1;31m^\e[0m \n");
printf(" \e[1;31mmp=%d\e[0m \n", mp); printf(" \e[1;31mmp=%d\e[0m \n", mp);
// print the adresses beneath the memory cells // print the adresses beneath the memory cells
for(int i=(mp-7); i<(mp+8); i++) { for(int i=(mp-7); i<(mp+8); i++) {
@@ -184,15 +240,17 @@ void print_memoryviewer(bf_code_t *bf)
printf("%03d ", i); printf("%03d ", i);
} }
} }
printf("\n");
print_delimiter('-', 61);
//"249 250 251 252 253 254 000 001 002 003 004 005 006 007 008\n"
printf("\n------------------------------------------------------------\n");
} }
/* Pauses the program flow and prints information */ /**
void bfuck_debugger(bf_code_t *bf) //char *bf_source_input, int instructionpointer) * @brief Pauses the program flow and prints information
* @type static
* @param[in] Pointer to a bf_code_t type
* @return void
**/
static void bfuck_debugger(bf_code_t *bf)
{ {
clear(); // clear terminal clear(); // clear terminal
@@ -213,8 +271,13 @@ void bfuck_debugger(bf_code_t *bf) //char *bf_source_input, int instructionpoint
} }
} }
/* Parses and executes a brainfuck expression */ /**
void bfuck_execute(bf_code_t *bf) * @brief Parses and executes a brainfuck expression using a simple state machine
* @type static
* @param[in] Pointer to a bf_code_t type
* @return void
**/
static void bfuck_execute(bf_code_t *bf)
{ {
int loop = 0; int loop = 0;
@@ -308,6 +371,13 @@ void bfuck_execute(bf_code_t *bf)
} }
} }
/**
* @brief Main function which handles the argument parsing
* @type static
* @param[in] int argc Argument counter
* @param[in] char **argv Argument vector
* @return int Exitcode Exitcode of the application
**/
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
// vars // vars
@@ -359,6 +429,9 @@ int main(int argc, char* argv[])
// try to interpret it // try to interpret it
bfuck_execute(&bf); bfuck_execute(&bf);
// test
printf("\n");
// exit // exit
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

12
examples/adder.bf Normal file
View File

@@ -0,0 +1,12 @@
, ; read to p1
> ; move to p2
, ; read to p2
[ ; enter loop
< ; move to p1
+ ; increment p1
> ; move to p2
- ; decrement p2
] ; exit when last cell is empty
< ; go back to p1
------------------------------------------------ ; subtract 48
. ; print p1