-
-
Save exallium/9182376 to your computer and use it in GitHub Desktop.
BF Interpreter in C... Because I can. And I was a bit bored.
This file contains hidden or 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
| /** | |
| * usage: ./bf "<program>" | |
| * example: ./bf ",[>++<-]>. ; multiplies a number by 2" | |
| * | |
| * Brainfuck Interpreter | |
| * | |
| * BF has the following commands: | |
| * > Move to next memory position | |
| * < Move to prev memory position | |
| * + Increment current memory position | |
| * - Decrement current memory position | |
| * [ Begin loop frame | |
| * ] End loop frame | |
| * , Read value from stdin | |
| * . Print value to stdout | |
| * | |
| */ | |
| #include<stdio.h> | |
| #include<stdlib.h> | |
| #include<string.h> | |
| #define D_SEG_SIZE 64 | |
| #define INC(a, b) (a + 1 < b ? a + 1 : b) | |
| #define DEC(a) (a > 0 ? a - 1 : a) | |
| typedef struct _STACK { | |
| struct _STACK *next; | |
| unsigned int start; | |
| } Stack; | |
| typedef struct _VM { | |
| unsigned int ip; // Instruction pointer | |
| char *is; // Instruction segment | |
| unsigned int is_len; // Instruction segment length | |
| unsigned int dp; // Data pointer | |
| unsigned int ds[D_SEG_SIZE]; // Data Segment | |
| Stack *frames; // Loop frames | |
| } State; | |
| void push_frame(State *state) { | |
| #ifdef DEBUG | |
| printf("pushstack(%d)\n", state->ip); | |
| #endif | |
| Stack *stack = (Stack *) malloc(sizeof(Stack)); | |
| stack->next = state->frames; | |
| stack->start = state->ip; | |
| state->frames = stack; | |
| } | |
| void pop_frame(State *state) { | |
| #ifdef DEBUG | |
| printf("popstack(%d)\n", state->ip); | |
| #endif | |
| Stack *stack = state->frames; | |
| state->frames = state->frames->next; | |
| free(stack); | |
| } | |
| int perform_action(State *state) { | |
| switch (state->is[state->ip]) { | |
| case '>': // Move to position right | |
| state->dp = INC(state->dp, D_SEG_SIZE - 1); | |
| break; | |
| case '<': // Move to position left | |
| state->dp = DEC(state->dp); | |
| break; | |
| case '+': // Increment current position | |
| state->ds[state->dp]++; | |
| break; | |
| case '-': // Decrement current position | |
| state->ds[state->dp] = DEC(state->ds[state->dp]); | |
| break; | |
| case '[': // Begin loop frame | |
| if (state->frames == NULL || state->frames->start != state->dp) | |
| push_frame(state); | |
| break; | |
| case ']': // End loop frame | |
| if (state->ds[state->dp] == 0) | |
| pop_frame(state); | |
| else { | |
| state->ip = state->frames->start; | |
| } | |
| break; | |
| case ',': // Read value from stdin | |
| scanf("%d", (state->ds + state->dp)); | |
| break; | |
| case '.': // Print current location to screen | |
| printf("%d", *(state->ds + state->dp)); | |
| break; | |
| default: // Ignore anything else | |
| break; | |
| } | |
| #ifdef DEBUG | |
| printf("BF LOG :: ip(%d) dp(%d) :: is(%c) ds(%d) \n", state->ip, state->dp, state->is[state->ip], state->ds[state->dp]); | |
| #endif | |
| state->ip++; | |
| return state->ip < state->is_len; | |
| } | |
| int main(int argc, char **argv) { | |
| State state; | |
| memset(&state, 0, sizeof(state)); | |
| state.is = argv[1]; | |
| state.is_len = strlen(argv[1]); | |
| while(perform_action(&state)) ; | |
| while(state.frames != NULL) { pop_frame(&state); } | |
| return EXIT_SUCCESS; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment