summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthing1 <thing1@seacrossedlovers.xyz>2025-06-17 20:41:36 +0100
committerthing1 <thing1@seacrossedlovers.xyz>2025-06-17 20:41:36 +0100
commitd07deb178676ca42778524e97f3b9729c83bff99 (patch)
tree8b52e65f796c925960bc2ef89b550429973168f8
init commitHEADmaster
-rw-r--r--.gitignore2
-rw-r--r--Makefile16
-rw-r--r--expr.c215
-rw-r--r--expr.h61
-rw-r--r--sheets.c268
-rw-r--r--sheets.h8
6 files changed, 570 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9eb9543
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.o
+sheets
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ad9f39f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+CFLAGS = -std=c23 -Os -ggdb
+LIBS = -lm
+
+SRC = sheets.c expr.c
+OBJ = $(SRC:.c=.o)
+
+all: sheets
+
+.c.o:
+ cc -c ${CFLAGS} $<
+
+sheets: ${OBJ}
+ cc ${OBJ} -o sheets ${CFLAGS} ${LIBS}
+
+clean:
+ rm -rf *.o sheets
diff --git a/expr.c b/expr.c
new file mode 100644
index 0000000..f50d42c
--- /dev/null
+++ b/expr.c
@@ -0,0 +1,215 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
+
+#include "sheets.h"
+
+/*
+EXPR := VALUE
+| VALUE POSTFIX
+| '(' EXPR ')'
+
+VALUE := NUM
+| LOC
+
+POSTFIX := OP EXPR
+OP := '+' | '-' | '*' | '/' | '^'
+lOC := '[' NUM ',' NUM ']'
+*/
+
+#define TODO(s) fprintf(stderr, "TODO:%d: %s\n", __LINE__, s); exit(1);
+
+typedef struct expr expr;
+typedef struct value value; /* for recursive case */
+typedef struct postfix postfix;
+
+typedef enum exprType {
+ VALUE,
+ POSTFIX,
+ NESTED,
+} exprType;
+
+typedef enum valueType {
+ NUM,
+ LOC,
+} valueType;
+
+typedef struct loc {
+ int x, y;
+} loc;
+
+typedef struct expr {
+ char *expr;
+ exprType t;
+ union {
+ expr *nested;
+ struct {
+ value *value;
+ postfix *postfix;
+ };
+ };
+} expr;
+
+typedef struct postfix {
+ char op;
+ expr *expr;
+} postfix;
+
+typedef struct value {
+ valueType t;
+ union {
+ int num;
+ loc *loc;
+ };
+} value;
+
+char isop(char c) {
+ switch (c) {
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '^':
+ return c;
+ }
+ return 0;
+}
+
+char *in;
+char *Pin;
+
+void consumeleading(char c) {
+loop:
+ if (*in == c) {
+ in++;
+ goto loop;
+ }
+}
+
+expr *parseExpr();
+
+loc *parseLoc() {
+ consumeleading(' ');
+ loc *l = malloc(sizeof(loc));
+ if (*in == '[') {
+ int i;
+ sscanf(in, "[%d,%d]%n", &l->x, &l->y, &i);
+ if (i != 0) {
+ in += i;
+ return l;
+ }
+ TODO("ERROR");
+ }
+ return NULL;
+}
+
+postfix *parsePostfix() {
+ consumeleading(' ');
+ postfix *p = malloc(sizeof(postfix));
+ if (p->op = isop(*in)) {
+ in++;
+ if (p->expr = parseExpr())
+ return p;
+ }
+ return NULL;
+}
+
+value *parseValue() {
+ consumeleading(' ');
+ value *v = malloc(sizeof(value));
+ if (v->loc = parseLoc()) {
+ v->t = LOC;
+ return v;
+ }
+ else if (isdigit(*in)) {
+ int i;
+ sscanf(in, "%d%n", &v->num, &i);
+ if (i != 0) {
+ in += i;
+ v->t = NUM;
+ return v;
+ }
+ TODO("ERROR");
+ }
+ return NULL;
+}
+
+expr *parseExpr() {
+ consumeleading(' ');
+ expr *e = malloc(sizeof(expr));
+ if (e->value = parseValue()) {
+ e->t = VALUE;
+ if (e->postfix = parsePostfix())
+ e->t = POSTFIX;
+
+ return e;
+ }
+
+ else if (*in == '(') {
+ in++;
+ if (e->nested = parseExpr())
+ if (*in == ')') {
+ e->t = NESTED;
+ return e;
+ }
+ TODO("ERROR");
+ }
+
+ return NULL;
+}
+
+double evalExpr(expr *e, sheet *s);
+
+double evalValue(value *v, sheet *s) {
+ if (v->t == NUM) return v->num;
+ return evalExpr(s->cells[v->loc->y][v->loc->x], s);
+}
+
+double evalPostfix(value *v, postfix *p, sheet *s) {
+ switch (p->op) {
+ case '+': return evalValue(v, s) + evalExpr(p->expr, s);
+ case '-': return evalValue(v, s) - evalExpr(p->expr, s);
+ case '*': return evalValue(v, s) * evalExpr(p->expr, s);
+ case '/': return evalValue(v, s) / evalExpr(p->expr, s);
+ case '^': return pow(evalValue(v, s), evalExpr(p->expr, s));
+ }
+}
+
+double evalExpr(expr *e, sheet *s) {
+ switch (e->t) {
+ case VALUE: return evalValue(e->value, s); break;
+ case POSTFIX: return evalPostfix(e->value, e->postfix, s); break;
+ case NESTED: return evalExpr(e->nested, s);
+ }
+}
+
+expr *makeNumber(int n) {
+ in = Pin;
+ memset(in, 0, 255);
+ snprintf(in, 16, "%d", n);
+ expr *e = parseExpr();
+ e->expr = strdup(Pin);
+ return e;
+}
+
+void freeValue(value *v) {
+ if (v->t == LOC) free(v->loc);
+ free(v);
+}
+
+void freePostfix(value *v, postfix *p) {
+ freeValue(v);
+ freeExpr(p->expr);
+ free(p);
+}
+
+void freeExpr(expr *e) {
+ switch (e->t) {
+ case VALUE: freeValue(e->value); break;
+ case POSTFIX: freePostfix(e->value, e->postfix); break;
+ case NESTED: freeExpr(e->nested); break;
+ }
+ free(e);
+}
diff --git a/expr.h b/expr.h
new file mode 100644
index 0000000..0d7422d
--- /dev/null
+++ b/expr.h
@@ -0,0 +1,61 @@
+typedef struct sheet sheet;
+
+typedef struct expr expr;
+typedef struct value value; /* for recursive case */
+typedef struct postfix postfix;
+
+typedef enum exprType {
+ VALUE,
+ POSTFIX,
+ NESTED,
+} exprType;
+
+typedef enum valueType {
+ NUM,
+ LOC,
+} valueType;
+
+typedef struct loc {
+ int x, y;
+} loc;
+
+typedef struct expr {
+ char *expr;
+ exprType t;
+ union {
+ expr *nested;
+ struct {
+ value *value;
+ postfix *postfix;
+ };
+ };
+} expr;
+
+typedef struct postfix {
+ char op;
+ expr *expr;
+} postfix;
+
+typedef struct value {
+ valueType t;
+ union {
+ int num;
+ loc *loc;
+ };
+} value;
+
+extern char *in;
+extern char *Pin;
+
+char isop(char c);
+void consumeleading(char c);
+expr *parseExpr();
+loc *parseLoc();
+postfix *parsePostfix();
+value *parseValue();
+expr *parseExpr();
+double evalValue(value *v, sheet *s);
+double evalPostfix(value *v, postfix *p, sheet *s);
+double evalExpr(expr *e, sheet *s);
+expr *makeNumber(int n);
+void freeExpr(expr *e);
diff --git a/sheets.c b/sheets.c
new file mode 100644
index 0000000..c9cba5d
--- /dev/null
+++ b/sheets.c
@@ -0,0 +1,268 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+
+#include "expr.h"
+#include "sheets.h"
+
+#define ACCURACY 2
+
+#define arg1(s, n) if (strcmp(argv[i], s) == 0) {\
+ i++; \
+ if (i >= argc) {\
+ fprintf(stderr, "expected value after %s option\n", s);\
+ exit(1);\
+ }
+
+#define arg2(s, n) else if (strcmp(argv[i], s) == 0) {\
+ i++; \
+ if (i >= argc) {\
+ fprintf(stderr, "expected value after %s option\n", s);\
+ exit(1);\
+ }
+
+
+void clearstdin() {
+ while (getc(stdin) != '\n') continue;
+}
+
+void freeSheet(sheet *s) {
+ for (int y = 0; y < s->height; y++) {
+ for (int x = 0; x < s->width; x++)
+ freeExpr(s->cells[y][x]);
+ free(s->cells[y]);
+ }
+ free(s->cells);
+ free(s);
+}
+
+sheet *makeSheet(int x, int y) {
+ sheet *s = calloc(1, sizeof(sheet));
+ s->width = x;
+ s->height = y;
+
+ s->cells = calloc(1, sizeof(expr **) * y);
+ for (int i = 0; i < y; i++) {
+ s->cells[i] = calloc(1, sizeof(expr *) * x);
+ for (int j = 0; j < x; j++)
+ s->cells[i][j] = makeNumber(0);
+ }
+ return s;
+}
+
+void export(sheet *s, FILE *f) {
+ fprintf(f, "%d %d\n", s->width, s->height);
+ for (int y = 0; y < s->height; y++) {
+ fprintf(f, "\n|");
+ for (int x = 0; x < s->width; x++)
+ fprintf(f, "%s|", s->cells[y][x]->expr);
+ }
+ fprintf(f, "\n");
+}
+
+sheet *import(FILE *f) {
+ int width, height;
+ sheet *s;
+
+ fscanf(f, "%d %d\n\n|", &width, &height);
+ s = makeSheet(width, height);
+
+ for (int y = 0; y < s->height; y++) {
+ for (int x = 0; x < s->width; x++) {
+ in = Pin;
+ char expr[256] = {0};
+ fscanf(f, "%[^|]s", expr);
+ fscanf(f, "|");
+
+ memcpy(in, expr, 256);
+ s->cells[y][x] = parseExpr();
+ s->cells[y][x]->expr = strdup(expr);
+ }
+ fscanf(f, "\n|");
+ }
+ return s;
+}
+
+void inputln(char *s, int size, FILE *f) {
+ fflush(stdout);
+ fgets(s, size, f);
+ *strchr(s, '\n') = 0;
+}
+
+void printSheetContents(sheet *s, int X, int Y) {
+ int longest[s->width];
+ memset(longest, 0, sizeof(int) * s->width);
+
+ for (int y = 0; y < s->height; y++)
+ for (int x = 0; x < s->width; x++)
+ if (strlen(s->cells[y][x]->expr) > longest[x])
+ longest[x] = strlen(s->cells[y][x]->expr);
+
+ for (int y = 0; y < s->height; y++) {
+ printf("\n|");
+ for (int x = 0; x < s->width; x++)
+ if (strcmp(s->cells[y][x]->expr, "0") == 0)
+ printf(" %*s |", longest[x], " ");
+ else if (X == x && Y == y)
+ printf("\e[1;34m %*s \e[0m|", longest[x], s->cells[y][x]->expr);
+ else
+ printf(" %*s |", longest[x], s->cells[y][x]->expr);
+ }
+ printf("\n");
+}
+
+void shell(char *prompt, FILE *fin) {
+ sheet *s;
+ if (!fin) {
+invalid:
+ int x = -1;
+ int y = -1;
+ printf("What size sheet do you want 'x,y': ");
+ scanf("%d,%d", &x, &y);
+ clearstdin();
+ if (x == -1 || y == -1) {
+ printf("Please input a valid expression!\n");
+ goto invalid;
+ }
+ s = makeSheet(x, y);
+ } else s = import(fin);
+
+
+ struct expr *e;
+ int x = 0;
+ int y = 0;
+ FILE *f;
+ char fname[256];
+
+
+ for (;;) {
+ in = Pin;
+ printf("(%d, %d) %s", x, y, prompt);
+ memset(in, 0, 256);
+ inputln(in, 256, stdin);
+
+ switch (in[0]) {
+ case 'u': y--; break;
+ case 'd': y++; break;
+ case 'l': x--; break;
+ case 'r': x++; break;
+ case 'q':
+ freeSheet(s);
+ printf("Exiting\n");
+ exit(0);
+ case 'p': printf("(%d,%d) %s\n", x, y,s->cells[y][x]->expr); break;
+ case 'P':
+ printSheetContents(s, x, y);
+ break;
+ case 'e':
+ for (int i = 0; i < s->height; i++) {
+ printf("\n|");
+ for (int j = 0; j < s->width; j++)
+ if (j == x && i == y)
+ printf("\e[1;34m %.*f \e[0m|", ACCURACY, evalExpr(s->cells[i][j], s));
+ else
+ printf(" %.*f |", ACCURACY, evalExpr(s->cells[i][j], s));
+ }
+ printf("\n");
+ break;
+ case 'i':
+ in = Pin;
+ memset(in, 0, 256);
+ inputln(in, 256, stdin);
+
+ freeExpr(s->cells[y][x]);
+
+ s->cells[y][x] = parseExpr();
+ s->cells[y][x]->expr = strdup(Pin);
+
+ break;
+ case 's':
+ printf("file to save to: ");
+ inputln(fname, 256, stdin);
+ f = fopen(fname, "w");
+ export(s, f);
+ fclose(f);
+ break;
+ case 'o':
+ printf("file to open: ");
+ inputln(fname, 256, stdin);
+ f = fopen(fname, "r");
+ if (!f)
+ fprintf(stderr, "couldn't open file!\n");
+ else {
+ freeSheet(s);
+ s = import(f);
+ fclose(f);
+ }
+ break;
+ default:
+ fprintf(stderr, "unknown cmd '%s'!\n", in);
+ break;
+
+ }
+
+ if (x > s->width) {
+ fprintf(stderr, "error: x:%d is out of range (0 - %d)\n", x, s->width);
+ x = s->width;
+ }
+ if (x < 0) {
+ fprintf(stderr, "error: x:%d is out of range (0 - %d)\n", x, s->width);
+ x = 0;
+ }
+ if (y > s->height) {
+ fprintf(stderr, "error: y:%d is out of range (0 - %d)\n", y, s->height);
+ y = s->height;
+ }
+ if (y < 0) {
+ fprintf(stderr, "error: y:%d is out of range (0 - %d)\n", y, s->height);
+ y = 0;
+ }
+ }
+}
+
+
+int main(int argc, char **argv) {
+ setbuf(stdout, NULL);
+
+ in = malloc(256);
+ Pin = in;
+
+ char *prompt = "> ";
+ FILE *input = NULL;
+
+ for (int i = 1; i < argc; i++) {
+ arg1("-p", true)
+ prompt = argv[i];
+ }
+ else {
+ input = fopen(argv[i], "r");
+ if (!input) {
+ fprintf(stderr, "couldn't open file\n");
+ exit(0);
+ }
+ }
+ }
+
+ shell(prompt, input);
+ free(in);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sheets.h b/sheets.h
new file mode 100644
index 0000000..23b7155
--- /dev/null
+++ b/sheets.h
@@ -0,0 +1,8 @@
+#ifndef __SHEETS_H_
+#define __SHEETS_H_
+#include "expr.h"
+typedef struct sheet {
+ int width, height;
+ expr ***cells;
+} sheet;
+#endif