QUOTE: Life is a journey, not a destination.

beep

A tiny terminal-based ASCII circuit simulator

commit 4e89eae142309f7acf4f7b59212edfc7960abdce
parent 458aa029a8b9dce801f9818497560e95cab17bb3
Author: Sophie <info@soophie.de>
Date:   Fri, 16 May 2025 12:34:36 +0000

feat: Added registers

Diffstat:
Mfiles/sample | 10+++++-----
Msrc/main.c | 295++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
2 files changed, 216 insertions(+), 89 deletions(-)

diff --git a/files/sample b/files/sample @@ -1,5 +1,5 @@ -BTN---+ - | - +---NOT---BULB - | -BTN---+ +REG(0)--->[x]---+ + | + +---REG(2)---+---ADD---REG(3) + | | +REG(1)--->[y]---+ +---<[x]---REG(4) diff --git a/src/main.c b/src/main.c @@ -1,12 +1,14 @@ #include <stdio.h> #include <stdlib.h> +#include <stdbool.h> #include <string.h> #include <ctype.h> -#include <wctype.h> #define BEEP_VALUE_HIGH 1 #define BEEP_VALUE_LOW 0 +#define BEEP_REGISTER_COUNT 50 + typedef enum { BEEP_OK = 0, BEEP_ERROR = -1, @@ -14,11 +16,13 @@ typedef enum { typedef long beep_uid_t; +typedef struct beep_board beep_board_t; typedef struct beep_node beep_node_t; typedef struct beep_element beep_element_t; typedef enum { BEEP_TYPE_NONE, + BEEP_TYPE_UNKNOWN, BEEP_TYPE_WIRE_Y, BEEP_TYPE_WIRE_X, BEEP_TYPE_NODE, @@ -30,6 +34,8 @@ typedef struct { char *str; size_t len; size_t ref_idx; + char *var_str; + size_t var_len; } beep_token_t; typedef struct { @@ -50,13 +56,16 @@ struct beep_node { size_t nodes_len; beep_channel_t *channels; size_t channels_len; + bool is_dirty; }; struct beep_element { beep_uid_t uid; + char *type; + char *var; beep_node_t *in; beep_node_t *out; - void (*update)(beep_element_t *self); + void (*update)(beep_board_t *self, beep_element_t *element); }; typedef struct { @@ -71,13 +80,38 @@ typedef struct { size_t nodes_len; } beep_state_t; +typedef struct { + beep_value_t values[BEEP_REGISTER_COUNT]; +} beep_registry_t; + +struct beep_board { + char *buffer; + size_t rows; + size_t cols; + beep_cell_t *cells; + beep_token_t *tokens; + size_t len; + beep_state_t state; + beep_registry_t registry; +}; + 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_token_init(beep_token_t *self) { + *self = (beep_token_t) { + .type = BEEP_TYPE_UNKNOWN, + .str = NULL, + .len = 0, + .ref_idx = -1, + .var_str = NULL, + .var_len = 0, + }; +} + void beep_node_init(beep_node_t *self) { *self = (beep_node_t) { .uid = beep_uid(), @@ -85,6 +119,7 @@ void beep_node_init(beep_node_t *self) { .nodes_len = 0, .channels = NULL, .channels_len = 0, + .is_dirty = false, }; } @@ -121,6 +156,7 @@ void beep_node_update(beep_node_t *self, const beep_signal_t signal) { return; } channel->value = signal.value; + self->is_dirty = true; i = 0; for (; i < self->nodes_len; i++) { beep_node_t *node = self->nodes[i]; @@ -143,32 +179,110 @@ beep_value_t beep_node_value(beep_node_t *self) { return BEEP_VALUE_HIGH; } } + self->is_dirty = false; return BEEP_VALUE_LOW; } -void beep_element_init(beep_element_t *self, void (*update)(beep_element_t *self)) { +void beep_registry_set(beep_board_t *self, size_t idx, beep_value_t value) { + if (idx >= BEEP_REGISTER_COUNT) { + return; + } + self->registry.values[idx] = value; +} + +beep_value_t *beep_registry_get(beep_board_t *self, size_t idx) { + if (idx >= BEEP_REGISTER_COUNT) { + return NULL; + } + return &self->registry.values[idx]; +} + +void BEEP_REG_UPDATE(beep_board_t *self, beep_element_t *element) { + if (element->var == NULL) { + return; + } + size_t idx = atoi(element->var); + if (element->in->is_dirty) { + beep_value_t value_in = beep_node_value(element->in); + beep_registry_set(self, idx, value_in); + printf("[REG] %s --> [%zu]\n", value_in ? "HIGH" : "LOW", idx); + } + beep_value_t value_out = *beep_registry_get(self, idx); + beep_node_update(element->out, (beep_signal_t) { element->uid, value_out }); + printf("[REG] [%zu] --> %s\n", idx, value_out ? "HIGH" : "LOW"); +} + +void BEEP_BTN_UPDATE(beep_board_t *self, beep_element_t *element) { + (void) self; + (void) element; +} + +void BEEP_NOT_UPDATE(beep_board_t *self, beep_element_t *element) { + (void) self; + beep_value_t value_in = beep_node_value(element->in); + beep_value_t value_out = !value_in; + printf("[NOT] %s --> %s\n", value_in ? "HIGH" : "LOW", value_out ? "HIGH" : "LOW"); + beep_node_update(element->out, (beep_signal_t) { element->uid, value_out }); +} + +void BEEP_ADD_UPDATE(beep_board_t *self, beep_element_t *element) { + (void) self; + (void) element; +} + +void BEEP_BULB_UPDATE(beep_board_t *self, beep_element_t *element) { + (void) self; + beep_value_t value_in = beep_node_value(element->in); + printf("[BULB] %s\n", value_in ? "HIGH" : "LOW"); +} + +void beep_element_init(beep_element_t *self, beep_token_t *token) { + size_t i = 0; + for (; i < token->len; i++) { + if (i < token->len && token->str[i] == '(') { + break; + } + } + size_t type_len = i; + char *type = malloc(sizeof(char) * (type_len + 1)); + memcpy(type, token->str, type_len); + type[type_len] = '\0'; + char *var = NULL; + if (token->var_str != NULL) { + var = malloc(sizeof(char) * (type_len + 1)); + memcpy(var, token->var_str, token->var_len); + var[token->var_len] = '\0'; + } + void (*update)(beep_board_t *self, beep_element_t *element) = NULL; + if (strcmp(type, "REG") == 0) { + update = BEEP_REG_UPDATE; + } + if (strcmp(type, "BTN") == 0) { + update = BEEP_BTN_UPDATE; + } + if (strcmp(type, "NOT") == 0) { + update = BEEP_NOT_UPDATE; + } + if (strcmp(type, "ADD") == 0) { + update = BEEP_ADD_UPDATE; + } + if (strcmp(type, "BULB") == 0) { + update = BEEP_BULB_UPDATE; + } 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(), + .type = type, + .var = var, .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; @@ -262,6 +376,7 @@ beep_err_t beep_board_tokenize(beep_board_t *self) { 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]; + beep_token_init(token); switch (c) { case ' ': token->type = BEEP_TYPE_NONE; @@ -280,19 +395,49 @@ beep_err_t beep_board_tokenize(beep_board_t *self) { token->len = 1; self->len++; } - if (isalpha(c)) { + else if (isalpha(c)) { size_t token_set = i; + char *var_str = NULL; + size_t var_len = -1; while (i < len && isalpha(self->buffer[i])) { i++; } + if (i < len && self->buffer[i] == '(') { + size_t i_reset = i; + i++; + size_t var_set = i; + while (i < len && self->buffer[i] != ')') { + i++; + } + if (i < len && self->buffer[i] == ')') { + var_str = self->buffer + var_set; + var_len = i - var_set; + i++; + } + else { + i = i_reset; + } + } 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; + if (var_str != NULL) { + token->var_str = var_str; + token->var_len = var_len; + } self->len++; i--; } + else { + self->tokens = realloc(self->tokens, sizeof(beep_token_t) * (self->len + 1)); + beep_token_t *token = &self->tokens[self->len]; + token->type = BEEP_TYPE_UNKNOWN; + token->str = self->buffer + i; + token->len = 1; + self->len++; + } } // create cells self->cells = calloc(self->rows * self->cols, sizeof(beep_cell_t)); @@ -310,24 +455,6 @@ beep_err_t beep_board_tokenize(beep_board_t *self) { 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; @@ -340,20 +467,7 @@ beep_err_t beep_board_construct(beep_board_t *self) { 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); + beep_element_init(element, token); token->ref_idx = state->elements_len; state->elements_len++; } @@ -469,14 +583,53 @@ beep_err_t beep_board_init(beep_board_t *self, char *buffer) { .tokens = NULL, .len = 0, .state = {0}, + .registry = { + .values = {0}, + }, }; + memset(self->registry.values, BEEP_VALUE_LOW, sizeof(beep_value_t) * BEEP_REGISTER_COUNT); beep_err_t ret; if ((ret = beep_board_read(self, buffer)) == BEEP_ERROR) { return ret; } + for (size_t y = 0; y < self->rows; y++) { + for (size_t x = 0; x < self->cols; x++) { + printf("%c", self->buffer[y * self->cols + x]); + } + printf("\n"); + } + printf("\n"); if ((ret = beep_board_tokenize(self)) == BEEP_ERROR) { return ret; } + for (size_t y = 0; y < self->rows; y++) { + for (size_t x = 0; x < self->cols; x++) { + size_t idx = y * self->cols + x; + beep_cell_t *cell = &self->cells[idx]; + switch (cell->token->type) { + case BEEP_TYPE_NONE: + printf("."); + break; + case BEEP_TYPE_UNKNOWN: + 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"); if ((ret = beep_board_construct(self)) == BEEP_ERROR) { return ret; } @@ -505,6 +658,10 @@ void beep_board_free(beep_board_t *self) { size_t i = 0; for (; i < state->elements_len; i++) { beep_element_t *element = &state->elements[i]; + free(element->type); + if (element->var != NULL) { + free(element->var); + } free(element->in); free(element->out); } @@ -531,52 +688,22 @@ void beep_update(beep_board_t *self) { size_t i = 0; for (; i < state->elements_len; i++) { beep_element_t *element = &state->elements[i]; - element->update(element); + if (element->update == NULL) { + continue; + } + element->update(self, element); } } int main(void) { beep_board_t board; - if (beep_board_load(&board, "./files/not") < 0) { + if (beep_board_load(&board, "./files/sample") < 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_registry_set(&board, 0, BEEP_VALUE_HIGH); beep_update(&board); + beep_registry_set(&board, 0, BEEP_VALUE_LOW); beep_update(&board); beep_board_free(&board); return BEEP_OK;