diff --git a/build.sh b/build.sh index 605426f..b249881 100644 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ CFLAGS="-Wall -Wextra -Wpedantic -Wswitch-enum -Werror -std=c23 -ggdb" LDFLAGS="-lm -lraylib" -SRC="src/sv.c src/vec.c src/main.c" +SRC="src/sv.c src/vec.c src/program_iter.c src/main.c" OUT="main.out" set -xe diff --git a/src/main.c b/src/main.c index 3af069f..b25f5a5 100644 --- a/src/main.c +++ b/src/main.c @@ -14,161 +14,14 @@ #include "sv.h" #include "vec.h" +#include "program_iter.h" + struct ProgramConcat { sv_t A, B; u8 tape[SIZEOF_PROGRAM * 2]; }; -void program_concat(struct ProgramConcat *ret, sv_t a, sv_t b) -{ - assert(a.size == SIZEOF_PROGRAM && b.size == SIZEOF_PROGRAM); - memset(ret, 0, sizeof(*ret)); - ret->A = a; - ret->B = b; - memcpy(ret->tape, a.data, SIZEOF_PROGRAM); - memcpy(ret->tape + SIZEOF_PROGRAM, b.data, SIZEOF_PROGRAM); -} - -u64 vec_pop(vec_t *vec) -{ - u64 ret = 0; - if (vec->size < sizeof(ret)) - return ret; - vec->size -= sizeof(ret); - memcpy(&ret, (typeof(ret) *)(((u8 *)vec_data(vec)) + vec->size), sizeof(ret)); - return ret; -} - -bool vec_in(vec_t *vec, u64 n) -{ - for (u64 i = 0; i < vec->size / sizeof(n); ++i) - { - if (VEC_GET(vec, i, typeof(n)) == n) - { - return true; - } - } - return false; -} - -void program_execute(struct ProgramConcat *prg) -{ - vec_t cond_stack = {0}; - vec_ensure_capacity(&cond_stack, sizeof(prg->tape) * sizeof(u64)); - - for (u64 ip = 0, head0 = 0, head1 = 0, total_iters = 0; - ip < sizeof(prg->tape) && total_iters < (1LU << 13); ++total_iters) - { - u8 opcode = prg->tape[ip]; - switch (opcode) - { - case '<': - head0 = SAFE_SUB(head0, 1); - ++ip; - break; - case '>': - head0++; - ++ip; - break; - case '{': - head1 = SAFE_SUB(head1, 1); - ++ip; - break; - case '}': - head1++; - ++ip; - break; - case '-': - prg->tape[head0]--; - ++ip; - break; - case '+': - prg->tape[head0]++; - ++ip; - break; - case '.': - prg->tape[head1] = prg->tape[head0]; - ++ip; - break; - case ',': - prg->tape[head0] = prg->tape[head1]; - ++ip; - break; - case '[': - { - if (!vec_in(&cond_stack, ip)) - { - vec_append(&cond_stack, &ip, sizeof(ip)); - } - if (!prg->tape[head0]) - { - // Iterate forward, trying to find a matching closed bracket - u64 square_brackets = 0; - u64 close_ip; - for (close_ip = ip + 1; close_ip < sizeof(prg->tape); ++close_ip) - { - if (prg->tape[close_ip] == '[') - { - ++square_brackets; - } - else if (prg->tape[close_ip] == ']') - { - if (square_brackets == 0) - { - break; - } - --square_brackets; - } - } - if (square_brackets != 0) - { - // NOTE: as per paper, terminate. - ip = sizeof(prg->tape); - } - else - { - ip = close_ip; - } - } - break; - } - case ']': - { - if (prg->tape[head0]) - { - if (cond_stack.size < sizeof(u64)) - { - // NOTE: as per paper, terminate. - ip = sizeof(prg->tape); - } - else - { - ip = vec_pop(&cond_stack); - } - } - else - { - ++ip; - } - break; - } - default: - ++ip; - break; - } - } - - vec_free(&cond_stack); -} - -void program_split(struct ProgramConcat *prg) -{ - assert(prg->A.data && prg->B.data); - memcpy((char *)prg->A.data, prg->tape, SIZEOF_PROGRAM); - memcpy((char *)prg->B.data, prg->tape + SIZEOF_PROGRAM, SIZEOF_PROGRAM); -} - #define WIDTH 800 #define HEIGHT 600 diff --git a/src/program_iter.c b/src/program_iter.c new file mode 100644 index 0000000..4bdd578 --- /dev/null +++ b/src/program_iter.c @@ -0,0 +1,172 @@ +/* program_iter.c: Program iteration implementation + * Created: 2026-03-10 + * Author: Aryadev Chavali + * License: See end of file + */ + +#include + +#include "program_iter.h" +#include "vec.h" + +void program_concat(struct ProgramConcat *ret, sv_t a, sv_t b) +{ + assert(a.size == SIZEOF_PROGRAM && b.size == SIZEOF_PROGRAM); + memset(ret, 0, sizeof(*ret)); + ret->A = a; + ret->B = b; + memcpy(ret->tape, a.data, SIZEOF_PROGRAM); + memcpy(ret->tape + SIZEOF_PROGRAM, b.data, SIZEOF_PROGRAM); +} + +u64 vec_pop(vec_t *vec) +{ + u64 ret = 0; + if (vec->size < sizeof(ret)) + return ret; + vec->size -= sizeof(ret); + memcpy(&ret, (typeof(ret) *)(((u8 *)vec_data(vec)) + vec->size), sizeof(ret)); + return ret; +} + +bool vec_in(vec_t *vec, u64 n) +{ + for (u64 i = 0; i < vec->size / sizeof(n); ++i) + { + if (VEC_GET(vec, i, typeof(n)) == n) + { + return true; + } + } + return false; +} + +void program_execute(struct ProgramConcat *prg) +{ + vec_t cond_stack = {0}; + vec_ensure_capacity(&cond_stack, sizeof(prg->tape) * sizeof(u64)); + + for (u64 ip = 0, head0 = 0, head1 = 0, total_iters = 0; + ip < sizeof(prg->tape) && total_iters < (1LU << 13); ++total_iters) + { + u8 opcode = prg->tape[ip]; + switch (opcode) + { + case '<': + head0 = SAFE_SUB(head0, 1); + ++ip; + break; + case '>': + head0++; + ++ip; + break; + case '{': + head1 = SAFE_SUB(head1, 1); + ++ip; + break; + case '}': + head1++; + ++ip; + break; + case '-': + prg->tape[head0]--; + ++ip; + break; + case '+': + prg->tape[head0]++; + ++ip; + break; + case '.': + prg->tape[head1] = prg->tape[head0]; + ++ip; + break; + case ',': + prg->tape[head0] = prg->tape[head1]; + ++ip; + break; + case '[': + { + if (!vec_in(&cond_stack, ip)) + { + vec_append(&cond_stack, &ip, sizeof(ip)); + } + if (!prg->tape[head0]) + { + // Iterate forward, trying to find a matching closed bracket + u64 square_brackets = 0; + u64 close_ip; + for (close_ip = ip + 1; close_ip < sizeof(prg->tape); ++close_ip) + { + if (prg->tape[close_ip] == '[') + { + ++square_brackets; + } + else if (prg->tape[close_ip] == ']') + { + if (square_brackets == 0) + { + break; + } + --square_brackets; + } + } + if (square_brackets != 0) + { + // NOTE: as per paper, terminate. + ip = sizeof(prg->tape); + } + else + { + ip = close_ip; + } + } + break; + } + case ']': + { + if (prg->tape[head0]) + { + if (cond_stack.size < sizeof(u64)) + { + // NOTE: as per paper, terminate. + ip = sizeof(prg->tape); + } + else + { + ip = vec_pop(&cond_stack); + } + } + else + { + ++ip; + } + break; + } + default: + ++ip; + break; + } + } + + vec_free(&cond_stack); +} + +void program_split(struct ProgramConcat *prg) +{ + assert(prg->A.data && prg->B.data); + memcpy((char *)prg->A.data, prg->tape, SIZEOF_PROGRAM); + memcpy((char *)prg->B.data, prg->tape + SIZEOF_PROGRAM, SIZEOF_PROGRAM); +} + +/* Copyright (C) 2026 Aryadev Chavali + + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for + * details. + + * You may distribute and modify this code under the terms of the GNU General + * Public License Version 2, which you should have received a copy of along with + * this program. If not, please go to . + + */ diff --git a/src/program_iter.h b/src/program_iter.h new file mode 100644 index 0000000..5be1b80 --- /dev/null +++ b/src/program_iter.h @@ -0,0 +1,38 @@ +/* program_iter.h: Program iteration procedure + * Created: 2026-03-10 + * Author: Aryadev Chavali + * License: See end of file + */ + +#ifndef PROGRAM_ITER_H +#define PROGRAM_ITER_H + +#include "base.h" +#include "sv.h" + +// Result of concatenating two programs. Maintains a concatenated tape of the +// two programs fed for ease of use. +struct ProgramConcat +{ + sv_t A, B; + u8 tape[SIZEOF_PROGRAM * 2]; +}; + +void program_concat(struct ProgramConcat *, sv_t, sv_t); +void program_execute(struct ProgramConcat *); +void program_split(struct ProgramConcat *); + +#endif + +/* Copyright (C) 2026 Aryadev Chavali + + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License Version 2 for + * details. + + * You may distribute and modify this code under the terms of the GNU General + * Public License Version 2, which you should have received a copy of along with + * this program. If not, please go to . + + */