main: split off program iteration to its own unit
This commit is contained in:
2
build.sh
2
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
|
||||
|
||||
151
src/main.c
151
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
|
||||
|
||||
|
||||
172
src/program_iter.c
Normal file
172
src/program_iter.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/* program_iter.c: Program iteration implementation
|
||||
* Created: 2026-03-10
|
||||
* Author: Aryadev Chavali
|
||||
* License: See end of file
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
38
src/program_iter.h
Normal file
38
src/program_iter.h
Normal file
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
Reference in New Issue
Block a user