#include #include #include #include #include #include #define BRACKETS_NB_MAX 1024 #define DATA_SIZE_MAX 65536 // The advanced version of operations should always have value = simple version + 1 enum operations_t { NONE, MEM_POINTER_ADD, MEM_POINTER_ADD_NB, MEM_POINTER_SUB, MEM_POINTER_SUB_NB, MEM_ADD, MEM_ADD_NB, MEM_SUB, MEM_SUB_NB, JUMP_IF_0, JUMP_IF_NOT_0, PRINT_CHAR, GET_CHAR }; typedef uint8_t operation_t; int main(int argc, char *argv[]) { int status = EXIT_FAILURE; if(argc != 2) { puts("usage : brainfuck program"); return EXIT_FAILURE; } FILE *program_file = NULL; FILE *intermediate_representation_file = NULL; program_file = fopen(argv[1], "r"); if(program_file == NULL) { fprintf(stderr, "Error opening program file: %d\n", errno); goto end; } intermediate_representation_file = tmpfile(); if(intermediate_representation_file == NULL) { fprintf(stderr, "Error creating tmp file: %d\n", errno); goto end; } // Strip program file while(true) { int c = fgetc(program_file); if(c == EOF) { int err = ferror(program_file); if(err) { fprintf(stderr, "Error reading file: %d\n", ferror(program_file)); goto end; } break; } operation_t operation = NONE; static operation_t last_operation = NONE; switch(c) { case '>': operation = MEM_POINTER_ADD; break; case '<': operation = MEM_POINTER_SUB; break; case '+': operation = MEM_ADD; break; case '-': operation = MEM_SUB; break; case '[': operation = JUMP_IF_0; break; case ']': operation = JUMP_IF_NOT_0; break; case '.': operation = PRINT_CHAR; break; case ',': operation = GET_CHAR; break; default: break; } if(operation == NONE) { continue; } switch(operation) { case MEM_POINTER_ADD: case MEM_POINTER_SUB: case MEM_ADD: case MEM_SUB: if(operation == last_operation) { operation++; // Go to advanced version of operation if(fseek(intermediate_representation_file, -1, SEEK_CUR)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } if(fwrite(&operation, sizeof(operation), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error writing file: %d\n", errno); goto end; } size_t nb = 2; if(fwrite(&nb, sizeof(nb), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error writing file: %d\n", errno); goto end; } } else if(operation + 1 == last_operation) { operation++; size_t nb; if(fseek(intermediate_representation_file, -sizeof(nb), SEEK_CUR)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } if(fread(&nb, sizeof(nb), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error reading file: %d\n", errno); goto end; } nb++; if(fseek(intermediate_representation_file, -sizeof(nb), SEEK_CUR)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } if(fwrite(&nb, sizeof(nb), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error writing file: %d\n", errno); goto end; } } else { if(fwrite(&operation, sizeof(operation), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error writing file: %d\n", errno); goto end; } } break; case JUMP_IF_0: case JUMP_IF_NOT_0: if(fwrite(&operation, sizeof(operation), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error writing file: %d\n", errno); goto end; } size_t jump_pos = 0; if(fwrite(&jump_pos, sizeof(jump_pos), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error writing file: %d\n", errno); goto end; } break; case PRINT_CHAR: case GET_CHAR: if(fwrite(&operation, sizeof(operation), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error writing file: %d\n", errno); goto end; } break; default: break; } last_operation = operation; } if(fclose(program_file) == EOF) { program_file = NULL; fprintf(stderr, "Error closing program file: %d\n", errno); goto end; } program_file = NULL; // Parse brackets rewind(intermediate_representation_file); while(true) { operation_t operation; size_t nb_read = fread(&operation, sizeof(operation), 1, intermediate_representation_file); if(nb_read != 1) { if(feof(intermediate_representation_file)) { break; } else { fprintf(stderr, "Error reading file: %d\n", ferror(intermediate_representation_file)); goto end; } } if(operation == JUMP_IF_0) { long bracket_pos = ftell(intermediate_representation_file); if(bracket_pos == -1) { fprintf(stderr, "Error getting file pointer: %d\n", errno); goto end; } // Find corresponding closing bracket index for(size_t bracket_index = 1; bracket_index;) { operation_t operation_search; nb_read = fread(&operation_search, sizeof(operation_search), 1, intermediate_representation_file); if(nb_read != 1) { if(feof(intermediate_representation_file)) { fprintf(stderr, "Reached end of file before finding closing bracket.\n"); } else { fprintf(stderr, "Error reading file: %d\n", ferror(intermediate_representation_file)); } goto end; } switch(operation_search) { case MEM_POINTER_ADD_NB: case MEM_POINTER_SUB_NB: case MEM_ADD_NB: case MEM_SUB_NB: case JUMP_IF_NOT_0: if(fseek(intermediate_representation_file, sizeof(size_t), SEEK_CUR)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } break; default: break; } if(operation_search == JUMP_IF_0) { bracket_index++; } else if(operation_search == JUMP_IF_NOT_0) { bracket_index--; } } long corresponding_bracket_pos = ftell(intermediate_representation_file); if(corresponding_bracket_pos == -1) { fprintf(stderr, "Error getting file pointer: %d\n", errno); goto end; } if(fseek(intermediate_representation_file, -sizeof(size_t), SEEK_CUR)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } size_t bracket_pos_size_t = (size_t)bracket_pos + sizeof(size_t); if(fwrite(&bracket_pos_size_t, sizeof(bracket_pos_size_t), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error writing file: %d\n", errno); goto end; } if(fseek(intermediate_representation_file, bracket_pos, SEEK_SET)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } size_t corresponding_bracket_pos_size_t = corresponding_bracket_pos; if(fwrite(&corresponding_bracket_pos_size_t, sizeof(corresponding_bracket_pos_size_t), 1, intermediate_representation_file) != 1) { fprintf(stderr, "Error writing file: %d\n", errno); goto end; } } switch(operation) { case MEM_POINTER_ADD_NB: case MEM_POINTER_SUB_NB: case MEM_ADD_NB: case MEM_SUB_NB: case JUMP_IF_NOT_0: fseek(intermediate_representation_file, sizeof(size_t), SEEK_CUR); break; default: break; } } rewind(intermediate_representation_file); // Program memory uint8_t mem[DATA_SIZE_MAX] = {0}; size_t mem_pointer = 0; size_t nb_read; size_t operand; while(true) { operation_t operation; nb_read = fread(&operation, sizeof(operation), 1, intermediate_representation_file); if(nb_read != 1) { if(feof(intermediate_representation_file)) { break; } else { fprintf(stderr, "Error reading file: %d\n", ferror(intermediate_representation_file)); goto end; } } switch(operation) { case MEM_POINTER_ADD: mem_pointer++; break; case MEM_POINTER_ADD_NB: nb_read = fread(&operand, sizeof(operand), 1, intermediate_representation_file); if(nb_read != 1) { fprintf(stderr, "Error reading file: %d\n", ferror(intermediate_representation_file)); goto end; } mem_pointer += operand; break; case MEM_POINTER_SUB: mem_pointer--; break; case MEM_POINTER_SUB_NB: nb_read = fread(&operand, sizeof(operand), 1, intermediate_representation_file); if(nb_read != 1) { fprintf(stderr, "Error reading file: %d\n", ferror(intermediate_representation_file)); goto end; } mem_pointer -= operand; break; case MEM_ADD: mem[mem_pointer]++; break; case MEM_ADD_NB: nb_read = fread(&operand, sizeof(operand), 1, intermediate_representation_file); if(nb_read != 1) { fprintf(stderr, "Error reading file: %d\n", ferror(intermediate_representation_file)); goto end; } mem[mem_pointer] += operand; break; case MEM_SUB: mem[mem_pointer]--; break; case MEM_SUB_NB: nb_read = fread(&operand, sizeof(operand), 1, intermediate_representation_file); if(nb_read != 1) { fprintf(stderr, "Error reading file: %d\n", ferror(intermediate_representation_file)); goto end; } mem[mem_pointer] -= operand; break; case JUMP_IF_0: if(mem[mem_pointer] == 0) { nb_read = fread(&operand, sizeof(operand), 1, intermediate_representation_file); if(nb_read != 1) { fprintf(stderr, "Error reading file: %d\n", ferror(intermediate_representation_file)); goto end; } if(fseek(intermediate_representation_file, operand, SEEK_SET)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } } else { if(fseek(intermediate_representation_file, sizeof(size_t), SEEK_CUR)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } } break; case JUMP_IF_NOT_0: if(mem[mem_pointer]) { nb_read = fread(&operand, sizeof(operand), 1, intermediate_representation_file); if(nb_read != 1) { fprintf(stderr, "Error reading file: %d\n", ferror(intermediate_representation_file)); goto end; } if(fseek(intermediate_representation_file, operand, SEEK_SET)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } } else { if(fseek(intermediate_representation_file, sizeof(size_t), SEEK_CUR)) { fprintf(stderr, "Error seeking file: %d\n", errno); goto end; } } break; case PRINT_CHAR: putchar(mem[mem_pointer]); break; case GET_CHAR: mem[mem_pointer] = getchar(); break; default: fprintf(stderr, "Invalid operation : %02d\n", operation); goto end; } } status = EXIT_SUCCESS; end: if(intermediate_representation_file != NULL) { if(fclose(intermediate_representation_file)) { fprintf(stderr, "Error closing tmp file: %d\n", errno); } } if(program_file != NULL) { if(fclose(program_file)) { fprintf(stderr, "Error closing tmp file: %d\n", errno); } } return status; }