commit 458aa029a8b9dce801f9818497560e95cab17bb3
Author: Sophie <info@soophie.de>
Date: Fri, 16 May 2025 01:10:36 +0200
feat: Initial commit
Diffstat:
6 files changed, 616 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1 @@
+beep
diff --git a/Makefile b/Makefile
@@ -0,0 +1,19 @@
+TARGET=beep
+SOURCE=src/*.c
+
+CC=cc
+CFLAGS=-Wall -Wextra -Werror -pedantic
+LIBS=
+
+.PHONY: all build run clean
+
+all: build
+
+build:
+ $(CC) $(CFLAGS) -o ./$(TARGET) $(SOURCE) $(LIBS)
+
+run: build
+ ./$(TARGET)
+
+clean:
+ rm -f ./$(TARGET)
diff --git a/files/bus b/files/bus
@@ -0,0 +1,5 @@
+REG($1)--->[x]---+
+ |
+ +---ADD---REG($3)
+ |
+REG($2)--->[y]---+---<[x]---REG($4)
diff --git a/files/not b/files/not
@@ -0,0 +1,3 @@
++---NOT---+
+| |
++---------+
diff --git a/files/sample b/files/sample
@@ -0,0 +1,5 @@
+BTN---+
+ |
+ +---NOT---BULB
+ |
+BTN---+
diff --git a/src/main.c b/src/main.c
@@ -0,0 +1,583 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <wctype.h>
+
+#define BEEP_VALUE_HIGH 1
+#define BEEP_VALUE_LOW 0
+
+typedef enum {
+ BEEP_OK = 0,
+ BEEP_ERROR = -1,
+} beep_err_t;
+
+typedef long beep_uid_t;
+
+typedef struct beep_node beep_node_t;
+typedef struct beep_element beep_element_t;
+
+typedef enum {
+ BEEP_TYPE_NONE,
+ BEEP_TYPE_WIRE_Y,
+ BEEP_TYPE_WIRE_X,
+ BEEP_TYPE_NODE,
+ BEEP_TYPE_ELEMENT,
+} beep_type_t;
+
+typedef struct {
+ beep_type_t type;
+ char *str;
+ size_t len;
+ size_t ref_idx;
+} beep_token_t;
+
+typedef struct {
+ beep_token_t *token;
+} beep_cell_t;
+
+typedef int beep_value_t;
+
+typedef struct {
+ beep_uid_t element_uid;
+ size_t idx;
+ beep_value_t value;
+} beep_channel_t;
+
+struct beep_node {
+ beep_uid_t uid;
+ beep_node_t **nodes;
+ size_t nodes_len;
+ beep_channel_t *channels;
+ size_t channels_len;
+};
+
+struct beep_element {
+ beep_uid_t uid;
+ beep_node_t *in;
+ beep_node_t *out;
+ void (*update)(beep_element_t *self);
+};
+
+typedef struct {
+ beep_uid_t element_uid;
+ beep_value_t value;
+} beep_signal_t;
+
+typedef struct {
+ beep_element_t *elements;
+ size_t elements_len;
+ beep_node_t *nodes;
+ size_t nodes_len;
+} beep_state_t;
+
+static beep_uid_t _BEEP_UID_COUNT = 0;
+static beep_value_t _BEEP_BTN = BEEP_VALUE_LOW;
+
+beep_uid_t beep_uid(void) {
+ return ++_BEEP_UID_COUNT;
+}
+
+void beep_node_init(beep_node_t *self) {
+ *self = (beep_node_t) {
+ .uid = beep_uid(),
+ .nodes = NULL,
+ .nodes_len = 0,
+ .channels = NULL,
+ .channels_len = 0,
+ };
+}
+
+void beep_node_index(beep_node_t *self, beep_uid_t element_uid, size_t idx) {
+ size_t i = 0;
+ for (; i < self->channels_len; i++) {
+ if (self->channels[i].element_uid == element_uid) {
+ return;
+ }
+ }
+ self->channels = realloc(self->channels, sizeof(beep_channel_t) * (self->channels_len + 1));
+ beep_channel_t *channel = &self->channels[self->channels_len];
+ channel->element_uid = element_uid;
+ channel->idx = idx;
+ channel->value = 0;
+ self->channels_len++;
+ i = 0;
+ for (; i < self->nodes_len; i++) {
+ beep_node_t *node = self->nodes[i];
+ beep_node_index(node, element_uid, idx + 1);
+ }
+}
+
+void beep_node_update(beep_node_t *self, const beep_signal_t signal) {
+ size_t i = 0;
+ beep_channel_t *channel = NULL;
+ for (; i < self->channels_len; i++) {
+ if (self->channels[i].element_uid == signal.element_uid) {
+ channel = &self->channels[i];
+ break;
+ }
+ }
+ if (channel == NULL) {
+ return;
+ }
+ channel->value = signal.value;
+ i = 0;
+ for (; i < self->nodes_len; i++) {
+ beep_node_t *node = self->nodes[i];
+ size_t j = 0;
+ for (; j < node->channels_len; j++) {
+ beep_channel_t *node_channel = &node->channels[j];
+ if (node_channel->element_uid == channel->element_uid && node_channel->idx > channel->idx) {
+ beep_node_update(node, signal);
+ break;
+ }
+ }
+ }
+}
+
+beep_value_t beep_node_value(beep_node_t *self) {
+ size_t i = 0;
+ for (; i < self->channels_len; i++) {
+ beep_channel_t *channel = &self->channels[i];
+ if (channel->value == BEEP_VALUE_HIGH) {
+ return BEEP_VALUE_HIGH;
+ }
+ }
+ return BEEP_VALUE_LOW;
+}
+
+void beep_element_init(beep_element_t *self, void (*update)(beep_element_t *self)) {
+ beep_node_t *node_in = malloc(sizeof(beep_node_t));
+ beep_node_init(node_in);
+ beep_node_t *node_out = malloc(sizeof(beep_node_t));
+ beep_node_init(node_out);
+ *self = (beep_element_t) {
+ .uid = beep_uid(),
+ .in = node_in,
+ .out = node_out,
+ .update = update,
+ };
+}
+
+typedef struct {
+ char *buffer;
+ size_t rows;
+ size_t cols;
+ beep_cell_t *cells;
+ beep_token_t *tokens;
+ size_t len;
+ beep_state_t state;
+} beep_board_t;
+
+beep_cell_t *beep_board_at(beep_board_t *self, size_t row, size_t col) {
+ if (self == NULL) {
+ return NULL;
+ }
+ if (row >= self->rows || col >= self->cols) {
+ return NULL;
+ }
+ return &self->cells[row * self->cols + col];
+}
+
+beep_err_t beep_file_read(char *filename, char **buffer) {
+ FILE *file = fopen(filename, "r");
+ if (file == NULL) {
+ return BEEP_ERROR;
+ }
+ fseek(file, 0, SEEK_END);
+ size_t len = ftell(file);
+ fseek(file, 0, SEEK_SET);
+ *buffer = malloc(sizeof(char) * (len + 1));
+ fread(*buffer, sizeof(char), len, file);
+ (*buffer)[len] = '\0';
+ fclose(file);
+ return BEEP_OK;
+}
+
+beep_err_t beep_board_read(beep_board_t *self, char *buffer) {
+ if (self == NULL) {
+ return BEEP_ERROR;
+ }
+ // read dimensions (rows, cols)
+ size_t len = strlen(buffer);
+ size_t i = 0;
+ size_t ln_set = i;
+ for (; i < len; i++) {
+ char c = buffer[i];
+ if (c == '\n') {
+ size_t ln_len = i - ln_set;
+ if (i > 0 && buffer[i - 1] == '\r') {
+ ln_len--;
+ }
+ if (ln_len > self->cols) {
+ self->cols = ln_len;
+ }
+ ln_set = i + 1;
+ self->rows++;
+ }
+ }
+ if (ln_set < len) {
+ size_t ln_len = i - ln_set;
+ if (i > 0 && buffer[i - 1] == '\r') {
+ ln_len--;
+ }
+ if (ln_len > self->cols) {
+ self->cols = ln_len;
+ }
+ self->rows++;
+ }
+ // fill board
+ self->buffer = malloc(sizeof(char) * self->rows * self->cols);
+ memset(self->buffer, ' ', self->rows * self->cols);
+ i = 0;
+ ln_set = i;
+ size_t ln = i;
+ for (; i < len; i++) {
+ size_t ln_idx = i - ln_set;
+ char c = buffer[i];
+ if (c == '\r') {
+ continue;
+ }
+ if (c == '\n') {
+ ln_set = i + 1;
+ ln++;
+ continue;
+ }
+ if (ln_idx < self->cols) {
+ self->buffer[ln * self->cols + ln_idx] = c;
+ }
+ }
+ return BEEP_OK;
+}
+
+beep_err_t beep_board_tokenize(beep_board_t *self) {
+ if (self == NULL) {
+ return BEEP_ERROR;
+ }
+ // read tokens
+ size_t i = 0;
+ size_t len = self->rows * self->cols;
+ for (; i < len; i++) {
+ char c = self->buffer[i];
+ if (c == ' ' || c == '-' || c == '|' || c == '+') {
+ self->tokens = realloc(self->tokens, sizeof(beep_token_t) * (self->len + 1));
+ beep_token_t *token = &self->tokens[self->len];
+ switch (c) {
+ case ' ':
+ token->type = BEEP_TYPE_NONE;
+ break;
+ case '-':
+ token->type = BEEP_TYPE_WIRE_X;
+ break;
+ case '|':
+ token->type = BEEP_TYPE_WIRE_Y;
+ break;
+ case '+':
+ token->type = BEEP_TYPE_NODE;
+ break;
+ }
+ token->str = self->buffer + i;
+ token->len = 1;
+ self->len++;
+ }
+ if (isalpha(c)) {
+ size_t token_set = i;
+ while (i < len && isalpha(self->buffer[i])) {
+ i++;
+ }
+ self->tokens = realloc(self->tokens, sizeof(beep_token_t) * (self->len + 1));
+ beep_token_t *token = &self->tokens[self->len];
+ token->type = BEEP_TYPE_ELEMENT;
+ token->str = self->buffer + token_set;
+ token->len = i - token_set;
+ self->len++;
+ i--;
+ }
+ }
+ // create cells
+ self->cells = calloc(self->rows * self->cols, sizeof(beep_cell_t));
+ i = 0;
+ size_t cell_idx = i;
+ for (; i < self->len; i++) {
+ beep_token_t *token = &self->tokens[i];
+ size_t j = 0;
+ for (; j < token->len; j++) {
+ beep_cell_t *cell = &self->cells[cell_idx + j];
+ cell->token = token;
+ }
+ cell_idx += token->len;
+ }
+ return BEEP_OK;
+}
+
+void BEEP_BTN_UPDATE(beep_element_t *self) {
+ beep_value_t value_out = _BEEP_BTN;
+ printf("[BTN] %s\n", value_out ? "HIGH" : "LOW");
+ beep_node_update(self->out, (beep_signal_t) { self->uid, value_out });
+}
+
+void BEEP_NOT_UPDATE(beep_element_t *self) {
+ beep_value_t value_in = beep_node_value(self->in);
+ beep_value_t value_out = !value_in;
+ printf("[NOT] %s --> %s\n", value_in ? "HIGH" : "LOW", value_out ? "HIGH" : "LOW");
+ beep_node_update(self->out, (beep_signal_t) { self->uid, value_out });
+}
+
+void BEEP_BULB_UPDATE(beep_element_t *self) {
+ beep_value_t value_in = beep_node_value(self->in);
+ printf("[BULB] %s\n", value_in ? "HIGH" : "LOW");
+}
+
+beep_err_t beep_board_construct(beep_board_t *self) {
+ if (self == NULL) {
+ return BEEP_ERROR;
+ }
+ beep_state_t *state = &self->state;
+ // create elements/nodes
+ size_t i = 0;
+ for (; i < self->len; i++) {
+ beep_token_t *token = &self->tokens[i];
+ if (token->type == BEEP_TYPE_ELEMENT) {
+ state->elements = realloc(state->elements, sizeof(beep_element_t) * (state->elements_len + 1));
+ beep_element_t *element = &state->elements[state->elements_len];
+ char element_type[token->len + 1];
+ memcpy(element_type, token->str, token->len);
+ element_type[token->len] = '\0';
+ void (*update)(beep_element_t *self) = NULL;
+ if (strcmp(element_type, "BTN") == 0) {
+ update = BEEP_BTN_UPDATE;
+ }
+ if (strcmp(element_type, "NOT") == 0) {
+ update = BEEP_NOT_UPDATE;
+ }
+ if (strcmp(element_type, "BULB") == 0) {
+ update = BEEP_BULB_UPDATE;
+ }
+ beep_element_init(element, update);
+ token->ref_idx = state->elements_len;
+ state->elements_len++;
+ }
+ if (token->type == BEEP_TYPE_NODE) {
+ state->nodes = realloc(state->nodes, sizeof(beep_node_t) * (state->nodes_len + 1));
+ beep_node_t *node = &state->nodes[state->nodes_len];
+ beep_node_init(node);
+ token->ref_idx = state->nodes_len;
+ state->nodes_len++;
+ }
+ }
+ // link all horizontal wires
+ for (size_t y = 0; y < self->rows; y++) {
+ size_t x = 0;
+ beep_cell_t *cell_set = NULL;
+ while (x < self->cols) {
+ beep_cell_t *cell = beep_board_at(self, y, x);
+ if (cell->token->type == BEEP_TYPE_WIRE_X) {
+ if (x > 0) {
+ cell_set = beep_board_at(self, y, x - 1);
+ }
+ while (x < self->cols && cell->token->type == BEEP_TYPE_WIRE_X) {
+ cell = beep_board_at(self, y, ++x);
+ }
+ if (cell != NULL && cell_set != NULL) {
+ beep_type_t type_set = cell_set->token->type;
+ beep_type_t type_end = cell->token->type;
+ if (
+ (type_set == BEEP_TYPE_ELEMENT || type_set == BEEP_TYPE_NODE) &&
+ (type_end == BEEP_TYPE_ELEMENT || type_end == BEEP_TYPE_NODE)
+ ) {
+ beep_node_t *node_set = NULL;
+ beep_node_t *node_end = NULL;
+ if (type_set == BEEP_TYPE_ELEMENT) {
+ beep_element_t *element = &state->elements[cell_set->token->ref_idx];
+ node_set = element->out;
+ }
+ if (type_set == BEEP_TYPE_NODE) {
+ node_set = &state->nodes[cell_set->token->ref_idx];
+ }
+ if (type_end == BEEP_TYPE_ELEMENT) {
+ beep_element_t *element = &state->elements[cell->token->ref_idx];
+ node_end = element->in;
+ }
+ if (type_end == BEEP_TYPE_NODE) {
+ node_end = &state->nodes[cell->token->ref_idx];
+ }
+ if (node_set != NULL && node_end != NULL) {
+ node_set->nodes = realloc(node_set->nodes, sizeof(beep_node_t *) * (node_set->nodes_len + 1));
+ node_set->nodes[node_set->nodes_len] = node_end;
+ node_set->nodes_len++;
+ node_end->nodes = realloc(node_end->nodes, sizeof(beep_node_t *) * (node_end->nodes_len + 1));
+ node_end->nodes[node_end->nodes_len] = node_set;
+ node_end->nodes_len++;
+ }
+ }
+ }
+ x--;
+ }
+ x++;
+ }
+ }
+ // link all vertical wires
+ for (size_t x = 0; x < self->cols; x++) {
+ size_t y = 0;
+ beep_cell_t *cell_set = NULL;
+ while (y < self->rows) {
+ beep_cell_t *cell = beep_board_at(self, y, x);
+ if (cell->token->type == BEEP_TYPE_WIRE_Y) {
+ if (y > 0) {
+ cell_set = beep_board_at(self, y - 1, x);
+ }
+ while (y < self->rows && cell->token->type == BEEP_TYPE_WIRE_Y) {
+ cell = beep_board_at(self, ++y, x);
+ }
+ if (cell != NULL && cell_set != NULL) {
+ beep_type_t type_set = cell_set->token->type;
+ beep_type_t type_end = cell->token->type;
+ if (type_set == BEEP_TYPE_NODE && type_end == BEEP_TYPE_NODE) {
+ beep_node_t *node_set = &state->nodes[cell_set->token->ref_idx];
+ beep_node_t *node_end = &state->nodes[cell->token->ref_idx];
+ node_set->nodes = realloc(node_set->nodes, sizeof(beep_node_t *) * (node_set->nodes_len + 1));
+ node_set->nodes[node_set->nodes_len] = node_end;
+ node_set->nodes_len++;
+ node_end->nodes = realloc(node_end->nodes, sizeof(beep_node_t *) * (node_end->nodes_len + 1));
+ node_end->nodes[node_end->nodes_len] = node_set;
+ node_end->nodes_len++;
+ }
+ }
+ y--;
+ }
+ y++;
+ }
+ }
+ // channel indexing
+ i = 0;
+ for (; i < state->elements_len; i++) {
+ beep_element_t *element = &state->elements[i];
+ beep_node_index(element->out, element->uid, 0);
+ }
+ return BEEP_OK;
+}
+
+beep_err_t beep_board_init(beep_board_t *self, char *buffer) {
+ if (buffer == NULL) {
+ return BEEP_ERROR;
+ }
+ *self = (beep_board_t) {
+ .buffer = NULL,
+ .rows = 0,
+ .cols = 0,
+ .cells = NULL,
+ .tokens = NULL,
+ .len = 0,
+ .state = {0},
+ };
+ beep_err_t ret;
+ if ((ret = beep_board_read(self, buffer)) == BEEP_ERROR) {
+ return ret;
+ }
+ if ((ret = beep_board_tokenize(self)) == BEEP_ERROR) {
+ return ret;
+ }
+ if ((ret = beep_board_construct(self)) == BEEP_ERROR) {
+ return ret;
+ }
+ return BEEP_OK;
+}
+
+beep_err_t beep_board_load(beep_board_t *self, char *filename) {
+ char *buffer = NULL;
+ if (beep_file_read(filename, &buffer) < 0) {
+ return BEEP_ERROR;
+ }
+ beep_err_t ret = beep_board_init(self, buffer);
+ free(buffer);
+ return ret;
+}
+
+void beep_board_free(beep_board_t *self) {
+ if (self == NULL) {
+ return;
+ }
+ free(self->buffer);
+ free(self->cells);
+ free(self->tokens);
+ beep_state_t *state = &self->state;
+ if (state->elements_len > 0) {
+ size_t i = 0;
+ for (; i < state->elements_len; i++) {
+ beep_element_t *element = &state->elements[i];
+ free(element->in);
+ free(element->out);
+ }
+ free(state->elements);
+ }
+ if (state->nodes_len > 0) {
+ size_t i = 0;
+ for (; i < state->nodes_len; i++) {
+ beep_node_t *node = &state->nodes[i];
+ if (node->nodes_len > 0) {
+ free(node->nodes);
+ }
+ if (node->channels_len > 0) {
+ free(node->channels);
+ }
+ }
+ free(state->nodes);
+ }
+}
+
+void beep_update(beep_board_t *self) {
+ printf("----- update -----\n");
+ beep_state_t *state = &self->state;
+ size_t i = 0;
+ for (; i < state->elements_len; i++) {
+ beep_element_t *element = &state->elements[i];
+ element->update(element);
+ }
+}
+
+int main(void) {
+ beep_board_t board;
+ if (beep_board_load(&board, "./files/not") < 0) {
+ return BEEP_ERROR;
+ }
+ for (size_t y = 0; y < board.rows; y++) {
+ for (size_t x = 0; x < board.cols; x++) {
+ printf("%c", board.buffer[y * board.cols + x]);
+ }
+ printf("\n");
+ }
+ printf("\n");
+ for (size_t y = 0; y < board.rows; y++) {
+ for (size_t x = 0; x < board.cols; x++) {
+ size_t idx = y * board.cols + x;
+ beep_cell_t *cell = &board.cells[idx];
+ switch (cell->token->type) {
+ case BEEP_TYPE_NONE:
+ printf(".");
+ break;
+ case BEEP_TYPE_WIRE_Y:
+ printf("Y");
+ break;
+ case BEEP_TYPE_WIRE_X:
+ printf("X");
+ break;
+ case BEEP_TYPE_NODE:
+ printf("N");
+ break;
+ case BEEP_TYPE_ELEMENT:
+ printf("E");
+ break;
+ }
+ }
+ printf("\n");
+ }
+ printf("\n");
+ beep_update(&board);
+ _BEEP_BTN = BEEP_VALUE_HIGH;
+ beep_update(&board);
+ _BEEP_BTN = BEEP_VALUE_LOW;
+ beep_update(&board);
+ beep_update(&board);
+ beep_board_free(&board);
+ return BEEP_OK;
+}