Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- // dont change cuz we rely on wrap around of tape_idx(uint16_t)
- #define TAPE_SIZE 65536
- char *get_ops(FILE *f) {
- if (!f) {
- return NULL;
- }
- size_t capacity = 64;
- size_t idx = 0;
- char *ops = malloc(capacity);
- if (!ops) {
- perror("malloc");
- return NULL;
- }
- for (int ch = fgetc(f); ch != EOF; ch = fgetc(f)) {
- switch (ch) {
- case '>':
- case '<':
- case '+':
- case '-':
- case '.':
- case ',':
- case '[':
- case ']': {
- if (idx + 1 >= capacity) {
- capacity *= 2;
- char *tmp = realloc(ops, capacity);
- if (!tmp) {
- free(ops);
- perror("realloc");
- return NULL;
- }
- ops = tmp;
- }
- ops[idx++] = (char)ch;
- break;
- }
- default:
- break;
- }
- }
- ops[idx] = '\0';
- return ops;
- }
- int64_t *calculate_offsets(const char *code) {
- size_t len = strlen(code);
- int64_t *offsets = calloc(len, sizeof(int64_t));
- if (!offsets) {
- perror("calloc");
- return NULL;
- }
- size_t *stack = malloc(len * sizeof *stack);
- if (!stack) {
- perror("malloc");
- free(offsets);
- return NULL;
- }
- size_t stack_top = 0;
- for (size_t i = 0; i < len; i++) {
- if (code[i] == '[') {
- stack[stack_top++] = i;
- } else if (code[i] == ']') {
- if (stack_top == 0) {
- fprintf(stderr, "Error: unmatched ']'\n");
- free(stack);
- free(offsets);
- return NULL;
- }
- size_t open = stack[--stack_top];
- offsets[open] = i;
- offsets[i] = open;
- } else if (code[i] == '>' || code[i] == '<' ||
- code[i] == '+' || code[i] == '-') {
- char op = code[i];
- int64_t count = 0;
- size_t j;
- for (j = i; j < len && code[j] == op; j++) {
- count++;
- }
- offsets[i] = count;
- i = j - 1;
- }
- }
- if (stack_top != 0) {
- fprintf(stderr, "Error: unmatched '['\n");
- free(stack);
- free(offsets);
- return NULL;
- }
- free(stack);
- return offsets;
- }
- int execute_code(char *code) {
- uint8_t *tape = calloc(TAPE_SIZE, sizeof(uint8_t));
- if (!tape) {
- perror("calloc");
- return 1;
- }
- int64_t *offsets = calculate_offsets(code);
- if (!offsets) {
- free(tape);
- return 1;
- }
- uint16_t tape_idx = 0;
- for (size_t code_idx = 0; code[code_idx] != '\0';) {
- switch (code[code_idx]) {
- case '>': {
- int64_t count = offsets[code_idx];
- tape_idx += (uint16_t)count;
- code_idx += count;
- break;
- }
- case '<': {
- int64_t count = offsets[code_idx];
- tape_idx -= (uint16_t)count;
- code_idx += count;
- break;
- }
- case '+': {
- int64_t count = offsets[code_idx];
- tape[tape_idx] += (uint8_t)count;
- code_idx += count;
- break;
- }
- case '-': {
- int64_t count = offsets[code_idx];
- tape[tape_idx] -= (uint8_t)count;
- code_idx += count;
- break;
- }
- case '.': {
- write(STDOUT_FILENO, &tape[tape_idx], 1);
- code_idx++;
- break;
- }
- case ',': {
- fflush(stdout);
- int input = getchar();
- tape[tape_idx] = (input == EOF) ? 0 : (uint8_t)input;
- code_idx++;
- break;
- }
- case '[': {
- if (tape[tape_idx] == 0) {
- code_idx = offsets[code_idx] + 1;
- } else {
- code_idx++;
- }
- break;
- }
- case ']': {
- if (tape[tape_idx] != 0) {
- code_idx = offsets[code_idx] + 1;
- } else {
- code_idx++;
- }
- break;
- }
- default:
- code_idx++;
- break;
- }
- }
- free(offsets);
- free(tape);
- return 0;
- }
- int main(int argc, char *argv[]) {
- if (argc < 2) {
- fprintf(stderr, "Usage: %s /path/to/file\n", argv[0]);
- return EXIT_FAILURE;
- }
- FILE *f = fopen(argv[1], "r");
- if (!f) {
- perror("fopen");
- return EXIT_FAILURE;
- }
- char *code = get_ops(f);
- fclose(f);
- if (!code) {
- return EXIT_FAILURE;
- }
- int res = execute_code(code);
- free(code);
- return res;
- }
Advertisement
Add Comment
Please, Sign In to add comment