aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README0
-rw-r--r--brainfuck.c250
-rw-r--r--hello.bf4
3 files changed, 254 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README
diff --git a/brainfuck.c b/brainfuck.c
new file mode 100644
index 0000000..ba573db
--- /dev/null
+++ b/brainfuck.c
@@ -0,0 +1,250 @@
+/*
+ * gcc -ansi -pedantic -Wall -Wextra -Werror -o brainfuck brainfuck.c
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+
+#define DATATYPE int
+
+FILE * prog;
+
+char * code = NULL;
+DATATYPE * data = NULL;
+unsigned int * stack = NULL;
+
+unsigned int data_size = 30000;
+unsigned int stack_size = 128;
+
+char format = 'u';
+
+unsigned int cp = 0;
+unsigned int dp = 0;
+unsigned int sp = 0;
+
+void read_code()
+{
+ int allocated, n, c;
+
+ allocated = 1000;
+ n = 0;
+
+ code = (char*) malloc(allocated * sizeof(char));
+ while (EOF != (c = getc(prog)))
+ {
+ if (n >= allocated)
+ {
+ allocated <<= 1;
+ code = (char*) realloc(code, allocated * sizeof(char));
+ }
+ code[n++] = (char) c;
+ }
+
+ if (n >= allocated)
+ {
+ allocated <<= 1;
+ code = (char*) realloc(code, allocated * sizeof(char));
+ }
+ code[n++] = '\0';
+}
+
+void init_data()
+{
+ data = (DATATYPE*) calloc(data_size, sizeof(DATATYPE));
+}
+
+void init_stack()
+{
+ stack = (unsigned int*) malloc(stack_size);
+}
+
+
+int inc_dp()
+{
+ if (dp < data_size)
+ {
+ ++dp;
+ return 1;
+ }
+ else
+ {
+ fprintf(stderr, "Data overflow\n");
+ return 0;
+ }
+}
+
+void dec_dp()
+{
+ if (dp > 0)
+ --dp;
+ else
+ fprintf(stderr, "Data underflow\n");
+}
+
+
+void push_cp()
+{
+ if (sp < stack_size)
+ stack[sp++] = cp;
+ else
+ fprintf(stderr, "Stack overflow\n");
+}
+
+void pop_cp()
+{
+ if (sp > 0)
+ cp = stack[--sp];
+ else
+ fprintf(stderr, "Stack underflow\n");
+}
+
+int skip()
+{
+ while (code[cp] != '\0')
+ {
+ if (code[++cp] == ']')
+ return 1;
+ }
+ return 0;
+}
+
+
+void print()
+{
+ switch (format)
+ {
+ case 'i': printf("%i\n", data[dp]); break;
+ case 'u': printf("%u\n", data[dp]); break;
+ case 'c': printf("%c", data[dp]); break;
+ case 'o': printf("0%o\n", data[dp]); break;
+ case 'x': printf("0x%X\n", data[dp]); break;
+ }
+}
+
+void run_code()
+{
+ char cmd;
+ while ('\0' != (cmd = code[cp]))
+ {
+ /*fprintf(stderr, "%c", cmd);*/
+ switch (cmd)
+ {
+ case '[': if (data[dp])
+ {
+ push_cp(); ++cp;
+ }
+ else
+ {
+ skip(); ++cp;
+ }
+ break;
+ case ']': pop_cp(); break;
+ case '+': ++(data[dp]); ++cp; break;
+ case '-': --(data[dp]); ++cp; break;
+ case '>': inc_dp(); ++cp; break;
+ case '<': dec_dp(); ++cp; break;
+ case '.': print(); ++cp; break;
+
+ case 'i':
+ case 'u':
+ case 'c':
+ case 'o':
+ case 'x':
+ format = cmd; ++cp; break;
+ default: ++cp;
+ }
+ }
+}
+
+void free_all()
+{
+ if (code != NULL) free(code);
+ if (data != NULL) free(data);
+ if (stack != NULL) free(stack);
+}
+
+void usage(char * self)
+{
+ printf("%s: Brainfuck programming language interpreter\n", self);
+ printf("See http://en.wikipedia.org/wiki/Brainfuck for more details\n\n");
+
+ printf("Usage: %s [options] [file]\n\n", self);
+
+ printf("Size of each data cell is %u byte(s)\n\n", sizeof(DATATYPE));
+ printf("Options (defaults are in brackets):\n");
+ printf(" -s num stack size (%u)\n", stack_size);
+ printf(" -d num data size (%u)\n", data_size);
+ printf("\n");
+ printf("Output formats for operator '.':\n");
+ printf(" -c, -i, -u, -o, -x char, signed int, unsigned int, octal, hexadecimal\n");
+ printf("\n");
+ printf(" -h this help message\n");
+ printf("\n");
+ printf(" file file to execute,\n");
+ printf(" if omitted read stdin\n");
+ printf("\n");
+ printf("Standard operators: <>+-[].,\n");
+ printf("Extensions: ciuox - change format output (same as -c & others, see above)\n");
+ printf("\n");
+ printf("Example:\n");
+ printf(" echo '+++[.-]' | %s\n", self);
+
+ exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char ** argv)
+{
+ char * filename;
+ char * self = argv[0];
+ int opt;
+
+ while (-1 != (opt = getopt(argc, argv, "s:d:h?iucox")))
+ {
+ switch (opt)
+ {
+ case 's':
+ sscanf(optarg, "%u", &stack_size);
+ break;
+ case 'd':
+ sscanf(optarg, "%u", &data_size);
+ break;
+ case 'i':
+ case 'u':
+ case 'c':
+ case 'o':
+ case 'x':
+ format = opt;
+ break;
+ default: usage(self);
+ }
+ }
+
+ if (optind < argc)
+ {
+ filename = argv[optind];
+ if (NULL == (prog = fopen(filename, "r")))
+ {
+ fprintf(stderr, "%s: open '%s': %s\n", self, filename, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+ else
+ prog = stdin;
+
+ read_code();
+
+ if (prog != stdin)
+ fclose(prog);
+
+ init_data();
+ init_stack();
+
+ run_code();
+
+ free_all();
+ return 0;
+}
+
diff --git a/hello.bf b/hello.bf
new file mode 100644
index 0000000..a2fce2b
--- /dev/null
+++ b/hello.bf
@@ -0,0 +1,4 @@
+c++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++
+.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
+------.--------.>+.>.
+