/* * Run the given brainfuck string. * * @param code The brainfuck string to run. * @return EXIT_SUCCESS if no errors are encountered, otherwise EXIT_FAILURE. */ int run_string(char *code) { BrainfuckState *state = brainfuck_state(); BrainfuckExecutionContext *context = brainfuck_context(BRAINFUCK_TAPE_SIZE); BrainfuckInstruction *instruction = brainfuck_parse_string(code); brainfuck_add(state, instruction); brainfuck_execute(state->root, context); brainfuck_destroy_context(context); brainfuck_destroy_state(state); return EXIT_SUCCESS; }
/* * Run the brainfuck interpreter in interactive mode. */ void run_interactive_console() { printf("brainfuck %s (%s, %s)\n", BRAINFUCK_VERSION, __DATE__, __TIME__); BrainfuckState *state = brainfuck_state(); BrainfuckExecutionContext *context = brainfuck_context(BRAINFUCK_TAPE_SIZE); BrainfuckInstruction *instruction; printf(">> "); while(1) { fflush(stdout); instruction = brainfuck_parse_stream_until(stdin, '\n'); brainfuck_add(state, instruction); brainfuck_execute(instruction, context); printf("\n>> "); } }
/* * Runs the given brainfuck file. * * @param file The brainfuck file to run. * @return EXIT_SUCCESS if no errors are encountered, otherwise EXIT_FAILURE. */ int run_file(FILE *file) { BrainfuckState *state = brainfuck_state(); BrainfuckExecutionContext *context = brainfuck_context(BRAINFUCK_TAPE_SIZE); if (file == NULL) { brainfuck_destroy_context(context); brainfuck_destroy_state(state); return EXIT_FAILURE; } brainfuck_add(state, brainfuck_parse_stream(file)); brainfuck_execute(state->root, context); brainfuck_destroy_context(context); brainfuck_destroy_state(state); fclose(file); return EXIT_SUCCESS; }
/** * Executes the given linked list containing instructions. * * @param root The start of the linked list of instructions you want * to execute. * @param context The context of this execution that contains the tape and * other execution related variables. */ void brainfuck_execute(BrainfuckInstruction *root, BrainfuckExecutionContext *context) { if (root == NULL || context == NULL) return; BrainfuckInstruction *instruction = root; int index; while (instruction != NULL && instruction->type != BRAINFUCK_TOKEN_LOOP_END) { switch (instruction->type) { case BRAINFUCK_TOKEN_PLUS: context->tape[context->tape_index] += instruction->difference; break; case BRAINFUCK_TOKEN_MINUS: context->tape[context->tape_index] -= instruction->difference; break; case BRAINFUCK_TOKEN_NEXT: if ((unsigned long) instruction->difference >= INT_MAX - context->tape_size || (unsigned long) context->tape_index + instruction->difference >= context->tape_size) { fprintf(stderr, "error: tape memory out of bounds (overrun)\nexceeded the tape size of %zd cells\n", context->tape_size); exit(EXIT_FAILURE); } context->tape_index += instruction->difference; break; case BRAINFUCK_TOKEN_PREVIOUS: if ((unsigned long) instruction->difference >= INT_MAX - context->tape_size || context->tape_index - instruction->difference < 0) { fprintf(stderr, "error: tape memory out of bounds (underrun)\nundershot the tape size of %zd cells\n", context->tape_size); exit(EXIT_FAILURE); } context->tape_index -= instruction->difference; break; case BRAINFUCK_TOKEN_OUTPUT: for (index = 0; index < instruction->difference; index++) context->output_handler(context->tape[context->tape_index]); break; case BRAINFUCK_TOKEN_INPUT: for (index = 0; index < instruction->difference; index++) context->tape[context->tape_index] = context->input_handler(); break; case BRAINFUCK_TOKEN_LOOP_START: while(context->tape[context->tape_index]) brainfuck_execute(instruction->loop, context); break; case BRAINFUCK_TOKEN_BREAK: { int low = context->tape_index - 10; if (low < 0) low = 0; int high = low + 21; if (high >= (int) context->tape_size) high = context->tape_size-1; for (index = low; index < high; index++) printf("%i\t", index); printf("\n"); for (index = low; index < high; index++) printf("%d\t", context->tape[index]); printf("\n"); for (index = low; index < high; index++) if (index == context->tape_index) printf("^\t"); else printf(" \t"); printf("\n"); break; } default: return; } instruction = instruction->next; if (context->shouldStop == 1) { instruction = NULL; return; } } }