Created
March 12, 2022 21:34
-
-
Save LucasWolschick/7bf85baeb36a912d16e9f7c5e91791a3 to your computer and use it in GitHub Desktop.
brainfuck interpreter written in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Lucas Wolschick (C) 2022 | |
// You should probably not use this as this has not been tested | |
// Usage: brainfuck [file] | |
// | |
// Try it with this code (available at en.wikipedia.org/wiki/Brainfuck, not mine!) | |
// ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
typedef struct VM VM; | |
struct VM { | |
size_t iptr; | |
size_t dptr; | |
uint8_t* data; | |
}; | |
typedef enum VM_STATUS VM_STATUS; | |
enum VM_STATUS { | |
VM_RUNNING, | |
VM_DONE, | |
}; | |
VM* vm_new(void) { | |
VM* vm = malloc(sizeof(VM)); | |
vm->iptr = 0; | |
vm->dptr = 0; | |
vm->data = calloc(30*1000, sizeof(uint8_t)); | |
return vm; | |
} | |
VM_STATUS vm_run(VM* vm, size_t src_len, const char* src) { | |
if (vm->iptr >= src_len) { | |
return VM_DONE; | |
} else { | |
switch(src[vm->iptr]) { | |
case '>': | |
if (vm->dptr == 30*1000) | |
// silently ignore | |
; | |
else | |
vm->dptr++; | |
break; | |
case '<': | |
if (vm->dptr > 0) | |
vm->dptr--; | |
break; | |
case '+': | |
vm->data[vm->dptr]++; | |
break; | |
case '-': | |
vm->data[vm->dptr]--; | |
break; | |
case '.': | |
putc(vm->data[vm->dptr], stdout); | |
break; | |
case ',': | |
vm->data[vm->dptr] = getc(stdin); | |
break; | |
case '[': | |
if (!vm->data[vm->dptr]) { | |
// jump to after matching ] | |
size_t idx = vm->iptr + 1; | |
int counter = 1; | |
while (idx < src_len && counter > 0) { | |
if (src[idx] == '[') { | |
counter++; | |
} else if (src[idx] == ']') { | |
counter--; | |
} | |
idx++; | |
} | |
vm->iptr = idx-1; | |
} | |
break; | |
case ']': | |
if (vm->iptr < 1) | |
// we can't have ] at the beginning of the src... | |
// silently ignore | |
break; | |
if (vm->data[vm->dptr] != 0) { | |
int counter = 1; | |
size_t idx = vm->iptr-1; | |
do { | |
if (src[idx] == ']') { | |
counter++; | |
} else if (src[idx] == '[') { | |
counter--; | |
} | |
idx--; | |
} while (idx > 0 && counter > 0); | |
vm->iptr = idx+1; | |
} | |
break; | |
// everything else are commentss | |
} | |
vm->iptr++; | |
} | |
return VM_RUNNING; | |
} | |
char* read_to_string(const char* path, size_t* length) { | |
char* source = 0; | |
// load file | |
FILE* src = fopen(path, "rb"); | |
if (!src) { | |
perror("Could not read brainfuck source"); | |
return source; | |
} | |
// get file length | |
int begin = ftell(src); | |
if (begin == -1) { | |
perror("Error seeking file"); | |
goto fail; | |
} | |
if (fseek(src, 0, SEEK_END) != 0) { | |
puts("Error reading file"); | |
goto fail; | |
} | |
int len = ftell(src); | |
if (len == -1) { | |
perror("Error reading file"); | |
goto fail; | |
} | |
if (fseek(src, 0, begin) != 0) { | |
puts("Error reading file"); | |
goto fail; | |
}; | |
// allocate and populate string | |
source = malloc(len); | |
if (!source) { | |
puts("Out of memory"); | |
goto fail; | |
} | |
int err = fread(source, 1, len, src); | |
if (err < len) { | |
if (feof(src)) { | |
puts("Error: end of file reached"); | |
goto fail; | |
} else if (ferror(src)) { | |
perror("Error reading source file"); | |
goto fail; | |
} | |
} | |
fclose(src); | |
*length = len; | |
return source; | |
fail: | |
fclose(src); | |
free(source); | |
return source; | |
} | |
int main(int argc, char* argv[]) { | |
if (argc > 1) { | |
size_t length = 0; | |
char* source = read_to_string(argv[1], &length); | |
if (!source) { | |
return EXIT_FAILURE; | |
} | |
VM* vm = vm_new(); | |
while (vm_run(vm, length, source) == VM_RUNNING) {} | |
free(source); | |
return EXIT_SUCCESS; | |
} else { | |
puts("Usage: brainfuck <file>"); | |
return EXIT_FAILURE; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment