From ac6004730fa54a756d1627a4e8450cd32df86f75 Mon Sep 17 00:00:00 2001 From: Preston Pan Date: Tue, 9 Jan 2024 18:39:49 -0800 Subject: reorganize directory structure --- src/better_string.c | 66 +++ src/builtins.c | 1140 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/macros.c | 8 + src/main.c | 76 ++++ src/stem.c | 451 ++++++++++++++++++++ 5 files changed, 1741 insertions(+) create mode 100644 src/better_string.c create mode 100644 src/builtins.c create mode 100644 src/macros.c create mode 100644 src/main.c create mode 100644 src/stem.c (limited to 'src') diff --git a/src/better_string.c b/src/better_string.c new file mode 100644 index 0000000..bd358e3 --- /dev/null +++ b/src/better_string.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +string_t *init_string(char *s) { + string_t *str = malloc(sizeof(string_t)); + if (str == NULL) + die("malloc in init_string"); + /* If we pass in NULL we assume that we want to append things to this in the + * future */ + if (s == NULL || strcmp(s, "") == 0) { + str->bufsize = 10; + str->value = calloc(str->bufsize, sizeof(char)); + str->value[0] = '\0'; + if (str->value == NULL) + die("calloc in init_string"); + str->length = 0; + return str; + } + /* Otherwise we want the initial value to be equal to the parameter */ + str->length = strlen(s); + str->bufsize = 2 * strlen(s); + str->value = calloc(str->bufsize, sizeof(char)); + if (str->value == NULL) + die("calloc in init_string"); + strcpy(str->value, s); + return str; +} + +string_t *string_copy(string_t *s) { return init_string(s->value); } + +/* stackoverflow code */ +void *realloc_zero(void *pBuffer, size_t oldSize, size_t newSize) { + void *pNew = realloc(pBuffer, newSize); + if (pNew == NULL) + die("realloc on realloc_zero"); + if (newSize > oldSize && pNew) { + size_t diff = newSize - oldSize; + void *pStart = ((char *)pNew) + oldSize; + memset(pStart, 0, diff); + } + return pNew; +} + +void string_concat(string_t *s1, string_t *s2) { + for (int i = 0; i < s2->length; i++) { + string_append(s1, s2->value[i]); + } +} + +void string_append(string_t *s, char c) { + char str[2] = {c, '\0'}; + int oldsize = s->bufsize; + if (s->bufsize - 1 <= s->length) { + s->bufsize = s->bufsize * 2; + s->value = realloc_zero(s->value, oldsize, s->bufsize); + } + s->length++; + strcat(s->value, str); +} + +void string_free(string_t *s) { + free(s->value); + free(s); +} diff --git a/src/builtins.c b/src/builtins.c new file mode 100644 index 0000000..df958f4 --- /dev/null +++ b/src/builtins.c @@ -0,0 +1,1140 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX 1000 +#define JUSTDO(a) \ + if (!(a)) { \ + perror(#a); \ + exit(1); \ + } + +extern array_t *STACK; +extern array_t *EVAL_STACK; +extern ht_t *WORD_TABLE; +extern char *INBUF; +extern parser_t *PARSER; + +extern ht_t *FLIT; +extern ht_t *OBJ_TABLE; + +/* TODO: rotr, rotl, dip, map, filter, errstr, join (for strings), switch + * (for quotes), split (split array, string, word into two), del (deleting + * entries from quotes, strings, words) */ + +char *get_line(FILE *f) { + int len = MAX; + char buf[MAX], *e = NULL, *ret; + JUSTDO(ret = calloc(MAX, 1)); + while (fgets(buf, MAX, f)) { + if (len - strlen(ret) < MAX) + JUSTDO(ret = realloc(ret, len *= 2)); + strcat(ret, buf); + if ((e = strrchr(ret, '\n'))) + break; + } + if (e) + *e = '\0'; + return ret; +} + +void print_value(value_t *v) { + custom_t *c; + switch (v->type) { + case VINT: + printf("%.0Lf\n", v->int_float); + break; + case VFLOAT: + printf("%Lf\n", v->int_float); + break; + case VSTR: + printf("%s", v->str_word->value); + break; + case VWORD: + printf("W: %s\n", v->str_word->value); + break; + case VQUOTE: + printf("Q:\n"); + for (int i = 0; i < v->quote->size; i++) { + print_value(v->quote->items[i]); + } + break; + case VERR: + printf("STACK ERR\n"); + break; + case VCUSTOM: + c = ht_get(OBJ_TABLE, v->str_word); + c->printfunc(v->custom); + break; + } +} + +void eval_error() { + value_t *v = init_value(VERR); + array_append(STACK, v); +} + +void stemadd(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + if (v1->type == VINT && v2->type == VINT) { + retval->type = VINT; + } + if (v1->type != VINT && v1->type != VFLOAT || + v2->type != VINT && v2->type != VFLOAT) { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + retval->int_float = v1->int_float + v2->int_float; + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void stemsub(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + if (v1->type == VINT && v2->type == VINT) { + retval->type = VINT; + } + retval->int_float = v1->int_float - v2->int_float; + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void stemmul(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + if (v1->type == VINT && v2->type == VINT) { + retval->type = VINT; + } + retval->int_float = v1->int_float * v2->int_float; + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void stemdiv(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + if (v1->type == VINT && v2->type == VINT) { + retval->type = VINT; + } + retval->int_float = v1->int_float / v2->int_float; + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void stemfunc(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + if (v1->type != VWORD) { + eval_error(); + return; + } + ht_add(WORD_TABLE, string_copy(v1->str_word), v2); + value_free(v1); +} + +void nop(value_t *v) {} + +void stempow(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + if (v1->type == VINT && v2->type == VINT) { + retval->type = VINT; + } + retval->int_float = powl(v1->int_float, v2->int_float); + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void stemsin(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + retval->int_float = sinhl(v1->int_float); + array_append(STACK, retval); + value_free(v1); +} + +void stemcos(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + retval->int_float = coshl(v1->int_float); + array_append(STACK, retval); + value_free(v1); +} + +void stemexp(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + retval->int_float = expl(v1->int_float); + array_append(STACK, retval); + value_free(v1); +} + +void stemeval(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v1); + eval_error(); + return; + } + if (v1->type == VQUOTE) { + array_append(EVAL_STACK, v1); + for (int i = 0; i < v1->quote->size; i++) { + eval(value_copy(v1->quote->items[i])); + } + value_t *vf = array_pop(EVAL_STACK); + if (vf) { + value_free(vf); + } + } else { + eval(v1); + } +} + +void stemln(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + retval->int_float = logl(v1->int_float); + array_append(STACK, retval); + value_free(v1); +} + +void stemceil(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + retval->int_float = ceil(v1->int_float); + array_append(STACK, retval); + value_free(v1); +} + +void stemfloor(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + value_t *retval = init_value(VFLOAT); + retval->int_float = floor(v1->int_float); + array_append(STACK, retval); + value_free(v1); +} + +void strquote(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + if (v1->type != VSTR) { + array_append(STACK, v1); + eval_error(); + return; + } + value_t *retval = init_value(VQUOTE); + retval->quote = init_array(10); + char *s = malloc(strlen(v1->str_word->value) + 1); + strcpy(s, v1->str_word->value); + parser_t *p = init_parser(s); + value_t *cur; + while (1) { + cur = parser_get_next(p); + if (cur == NULL) + break; + array_append(retval->quote, cur); + } + array_append(STACK, retval); + value_free(v1); + free(p->source); + free(p); +} + +void curry(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + if (v2->type != VQUOTE) { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + + array_append(v2->quote, v1); + array_append(STACK, v2); +} + +void stemfread(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + if (v1->type != VSTR) { + array_append(STACK, v1); + eval_error(); + return; + } + char *val = NULL; + size_t len; + FILE *fp = fopen(v1->str_word->value, "rb"); + if (!fp) { + array_append(STACK, v1); + eval_error(); + return; + } + ssize_t bytes_read = getdelim(&val, &len, '\0', fp); + fclose(fp); + value_t *retval = init_value(VSTR); + retval->str_word = init_string(val); + array_append(STACK, retval); + value_free(v1); + free(val); +} + +void stemread(value_t *v) { + value_t *retval = init_value(VSTR); + char *a = get_line(stdin); + retval->str_word = init_string(a); + array_append(STACK, retval); + free(a); +} + +void stemexit(value_t *v) { + ht_free(WORD_TABLE, value_free); + ht_free(FLIT, func_free); + array_free(STACK); + free(INBUF); + free(PARSER); + array_free(EVAL_STACK); + ht_free(OBJ_TABLE, func_free); + exit(0); +} + +void quote(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + + value_t *retval = init_value(VQUOTE); + retval->quote = init_array(10); + array_append(retval->quote, v1); + array_append(STACK, retval); +} + +void stemtype(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + retval->int_float = v1->type; + array_append(STACK, v1); + array_append(STACK, retval); +} + +void dsc(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + + value_free(v1); +} + +void swap(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + array_append(STACK, v2); + array_append(STACK, v1); +} + +void isdef(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + if (v1->type != VWORD) { + retval->int_float = 0; + } else { + retval->int_float = ht_exists(WORD_TABLE, v1->str_word); + } + array_append(STACK, v1); + array_append(STACK, retval); +} + +void stemdup(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + + value_t *retval = value_copy(v1); + array_append(STACK, v1); + array_append(STACK, retval); +} + +void questionmark(value_t *v) { + for (int i = 0; i < STACK->size; i++) { + print_value(STACK->items[i]); + } +} + +void period(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + print_value(v1); + value_free(v1); +} + +void stemlen(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + if (v1->type == VINT || v1->type == VFLOAT) { + retval->int_float = 1; + } else if (v1->type == VSTR || v1->type == VWORD) { + retval->int_float = strlen(v1->str_word->value); + } else if (v1->type == VQUOTE) { + retval->int_float = v1->quote->size; + } + array_append(STACK, v1); + array_append(STACK, retval); +} + +void dip(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + if (v2->type == VQUOTE) { + array_append(EVAL_STACK, v1); + array_append(EVAL_STACK, v2); + for (int i = 0; i < v2->quote->size; i++) { + eval(value_copy(v2->quote->items[i])); + } + value_free(array_pop(EVAL_STACK)); + value_free(array_pop(EVAL_STACK)); + } else { + eval(v1); + } + array_append(STACK, v1); +} + +void keep(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + array_append(STACK, value_copy(v1)); + if (v2->type == VQUOTE) { + array_append(EVAL_STACK, v2); + for (int i = 0; i < v2->quote->size; i++) { + eval(value_copy(v2->quote->items[i])); + } + value_free(array_pop(EVAL_STACK)); + } else { + eval(v1); + } + array_append(STACK, v1); +} + +void del(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + if (v2->type != VINT) { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + switch (v1->type) { + case VQUOTE: + break; + case VSTR: + break; + case VWORD: + break; + default: + value_free(v1); + break; + } +} + +void clear(value_t *v) { + while (STACK->size != 0) { + value_t *v1 = array_pop(STACK); + value_free(v1); + } +} + +void stemif(value_t *v) { + value_t *v3 = array_pop(STACK); + if (v3 == NULL) { + eval_error(); + return; + } + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + array_append(STACK, v3); + eval_error(); + return; + } + + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + array_append(STACK, v3); + eval_error(); + return; + } + + if (v1->type != VINT) { + array_append(STACK, v1); + array_append(STACK, v2); + array_append(STACK, v3); + eval_error(); + return; + } + + if (v1->int_float) { + value_free(v3); + value_free(v1); + if (v2->type == VQUOTE) { + + array_append(EVAL_STACK, v2); + for (int i = 0; i < v2->quote->size; i++) { + eval(value_copy(v2->quote->items[i])); + } + value_t *vf = array_pop(EVAL_STACK); + if (vf) { + value_free(vf); + } + } else { + eval(v2); + } + } else { + value_free(v2); + value_free(v1); + if (v3->type == VQUOTE) { + array_append(EVAL_STACK, v3); + for (int i = 0; i < v3->quote->size; i++) { + eval(value_copy(v3->quote->items[i])); + } + value_t *vf = array_pop(EVAL_STACK); + if (vf) { + value_free(vf); + } + } else { + eval(v3); + } + } +} + +void gtequals(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + if (v1->type == VSTR && v2->type == VSTR || + v1->type == VWORD && v2->type == VWORD) { + retval->int_float = strcmp(v1->str_word->value, v2->str_word->value) <= 0; + } else if ((v1->type == VINT || v1->type == VFLOAT) && + (v2->type == VINT || v2->type == VFLOAT)) { + retval->int_float = v1->int_float >= v2->int_float; + } else { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void ltequals(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + if (v1->type == VSTR && v2->type == VSTR || + v1->type == VWORD && v2->type == VWORD) { + retval->int_float = strcmp(v1->str_word->value, v2->str_word->value) <= 0; + } else if ((v1->type == VINT || v1->type == VFLOAT) && + (v2->type == VINT || v2->type == VFLOAT)) { + retval->int_float = v1->int_float <= v2->int_float; + } else { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void clib(value_t *v) { + value_t *v1 = array_pop(STACK); + void *handle = dlopen(v1->str_word->value, RTLD_LAZY); + if (!handle) { + array_append(STACK, v1); + eval_error(); + return; + } + dlerror(); + void (*af)(void); + void (*aobjs)(void); + char *error; + *(void **)(&af) = dlsym(handle, "add_funcs"); + *(void **)(&aobjs) = dlsym(handle, "add_objs"); + if ((error = dlerror()) != NULL) { + value_free(v1); + fprintf(stderr, "%s\n", error); + eval_error(); + return; + } else { + (*af)(); + (*aobjs)(); + value_free(v1); + } +} + +void gthan(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + if (v1->type == VSTR && v2->type == VSTR || + v1->type == VWORD && v2->type == VWORD) { + retval->int_float = strcmp(v1->str_word->value, v2->str_word->value) > 0; + } else if ((v1->type == VINT || v1->type == VFLOAT) && + (v2->type == VINT || v2->type == VFLOAT)) { + retval->int_float = v1->int_float > v2->int_float; + } else { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void lthan(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + if (v1->type == VSTR && v2->type == VSTR || + v1->type == VWORD && v2->type == VWORD) { + retval->int_float = strcmp(v1->str_word->value, v2->str_word->value) < 0; + } else if ((v1->type == VINT || v1->type == VFLOAT) && + (v2->type == VINT || v2->type == VFLOAT)) { + retval->int_float = v1->int_float < v2->int_float; + } else { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void equals(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + if (v1->type == VSTR && v2->type == VSTR || + v1->type == VWORD && v2->type == VWORD) { + retval->int_float = strcmp(v1->str_word->value, v2->str_word->value) == 0; + } else if ((v1->type == VINT || v1->type == VFLOAT) && + (v2->type == VINT || v2->type == VFLOAT)) { + retval->int_float = v1->int_float == v2->int_float; + } else { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void nequals(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + if (v1->type == VSTR && v2->type == VSTR || + v1->type == VWORD && v2->type == VWORD) { + retval->int_float = strcmp(v1->str_word->value, v2->str_word->value) != 0; + } else if ((v1->type == VINT || v1->type == VFLOAT) && + (v2->type == VINT || v2->type == VFLOAT)) { + retval->int_float = v1->int_float != v2->int_float; + } else { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + array_append(STACK, retval); + value_free(v1); + value_free(v2); +} + +void wtostr(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + + if (v1->type != VWORD) { + array_append(STACK, v1); + eval_error(); + return; + } + v1->type = VSTR; + array_append(STACK, v1); +} + +void compose(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + value_t *retval; + if (v2->type == VSTR && v1->type == VSTR) { + retval = init_value(VSTR); + string_concat(v1->str_word, v2->str_word); + retval->str_word = string_copy(v1->str_word); + value_free(v1); + value_free(v2); + } else if (v2->type == VWORD && v1->type == VWORD) { + retval = init_value(VWORD); + string_concat(v1->str_word, v2->str_word); + retval->str_word = string_copy(v1->str_word); + value_free(v1); + value_free(v2); + } else if (v2->type == VQUOTE && v1->type == VQUOTE) { + retval = v1; + array_extend(v1->quote, v2->quote); + free(v2->quote); + free(v2); + } else { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + array_append(STACK, retval); +} + +void isnum(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + + bool isnum = true; + for (int i = 0; i < v1->str_word->length; i++) { + if (isspace(v1->str_word->value[i])) { + continue; + } else if (!isdigit(v1->str_word->value[i])) { + isnum = false; + break; + } + } + retval->int_float = isnum; + + array_append(STACK, v1); + array_append(STACK, retval); +} + +void stoi(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + + value_t *retval = init_value(VINT); + retval->int_float = atoi(v1->str_word->value); + array_append(STACK, retval); + value_free(v1); +} + +void ssize(value_t *v) { + value_t *retval = init_value(VINT); + retval->int_float = STACK->size; + array_append(STACK, retval); +} + +void qstack(value_t *v) { + value_t *retval = init_value(VQUOTE); + retval->quote = array_copy(STACK); + array_append(STACK, retval); +} + +void vat(value_t *v) { + value_t *v2 = array_pop(STACK); + if (v2 == NULL) { + eval_error(); + return; + } + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + array_append(STACK, v2); + eval_error(); + return; + } + + if (v1->type != VINT) { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + if (v2->type == VQUOTE) { + if (v2->quote->size <= v1->int_float) { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + array_append(STACK, v2); + array_append(STACK, value_copy(v2->quote->items[(int)v1->int_float])); + value_free(v1); + } else if (v2->type == VSTR) { + if (v2->str_word->length <= v1->int_float) { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } + char *a = (char[]){v2->str_word->value[(int)v1->int_float], '\0'}; + string_t *s = init_string(a); + value_t *retval = init_value(VINT); + retval->str_word = s; + array_append(STACK, v2); + array_append(STACK, retval); + value_free(v1); + } else { + array_append(STACK, v1); + array_append(STACK, v2); + eval_error(); + return; + } +} + +void stemfwrite(value_t *v) { + value_t *v1 = array_pop(STACK); + if (v1 == NULL) { + eval_error(); + return; + } + if (v1->type != VSTR) { + array_append(STACK, v1); + eval_error(); + return; + } + char *val; + size_t len; + FILE *fp = fopen(v1->str_word->value, "w+"); + if (!fp) { + array_append(STACK, v1); + eval_error(); + return; + } + fprintf(fp, "%s", v1->str_word->value); + value_free(v1); + fclose(fp); +} + +void add_func(ht_t *h, void (*func)(value_t *), char *key) { + string_t *s = init_string(key); + ht_add(h, s, func); +} + +void add_obj(ht_t *h, ht_t *h2, void (*printfunc)(void *), + void (*freefunc)(void *), void *(*copyfunc)(void *), + void (*createfunc)(void *), char *key) { + + custom_t *c = init_custom(printfunc, freefunc, copyfunc); + ht_add(h, init_string(key), c); + ht_add(h2, init_string(key), createfunc); +} + +void add_objs() {} + +void add_funcs() { + add_func(FLIT, period, "."); + add_func(FLIT, questionmark, "?"); + add_func(FLIT, stemadd, "+"); + add_func(FLIT, stemsub, "-"); + add_func(FLIT, stemdiv, "/"); + add_func(FLIT, stemmul, "*"); + add_func(FLIT, stempow, "pow"); + add_func(FLIT, stemsin, "sin"); + add_func(FLIT, stemcos, "cos"); + add_func(FLIT, stemexp, "exp"); + add_func(FLIT, strquote, "strquote"); + add_func(FLIT, stemeval, "eval"); + add_func(FLIT, stemfunc, "func"); + add_func(FLIT, nop, "nop"); + add_func(FLIT, stemln, "ln"); + add_func(FLIT, stemfloor, "floor"); + add_func(FLIT, stemceil, "ceil"); + add_func(FLIT, stemfread, "fread"); + add_func(FLIT, stemread, "read"); + add_func(FLIT, vat, "vat"); + add_func(FLIT, qstack, "qstack"); + add_func(FLIT, ssize, "ssize"); + add_func(FLIT, stoi, "stoi"); + add_func(FLIT, isnum, "isnum"); + add_func(FLIT, compose, "compose"); + add_func(FLIT, stemfwrite, "wtostr"); + add_func(FLIT, lthan, "<"); + add_func(FLIT, ltequals, "<="); + add_func(FLIT, gthan, ">"); + add_func(FLIT, gtequals, ">="); + add_func(FLIT, nequals, "!="); + add_func(FLIT, equals, "="); + add_func(FLIT, stemif, "if"); + add_func(FLIT, clear, "clear"); + add_func(FLIT, keep, "keep"); + add_func(FLIT, dip, "dip"); + add_func(FLIT, stemlen, "len"); + add_func(FLIT, quote, "quote"); + add_func(FLIT, stemexit, "exit"); + add_func(FLIT, stemtype, "type"); + add_func(FLIT, stemdup, "dup"); + add_func(FLIT, curry, "curry"); + add_func(FLIT, swap, "swap"); + add_func(FLIT, isdef, "isdef"); + add_func(FLIT, dsc, "dsc"); + add_func(FLIT, clib, "clib"); +} diff --git a/src/macros.c b/src/macros.c new file mode 100644 index 0000000..e9c8355 --- /dev/null +++ b/src/macros.c @@ -0,0 +1,8 @@ +#include +#include +#include + +void die(char *message) { + fprintf(stderr, "ERROR: %s\n", message); + exit(1); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..7e9f5d9 --- /dev/null +++ b/src/main.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include + +extern ht_t *WORD_TABLE; + +extern array_t *STACK; +extern char *INBUF; +extern parser_t *PARSER; +extern array_t *EVAL_STACK; +extern ht_t *OBJ_TABLE; +extern ht_t *FLIT; + +void usage() { + printf("Usage: stem [-hv] [file]\n"); + exit(1); +} + +void version() { + printf("Author: Preston Pan, MIT License 2023\n"); + printf("stem, version 1.2 alpha\n"); + exit(0); +} + +int main(int argc, char **argv) { + value_t *v; + size_t len; + + if (argc < 2) { + usage(); + } + + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) { + usage(); + } else if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) { + version(); + } + + FILE *FP = fopen(argv[1], "rb"); + + if (!FP) { + usage(); + } + + ssize_t bytes_read = getdelim(&INBUF, &len, '\0', FP); + fclose(FP); + + PARSER = init_parser(INBUF); + STACK = init_array(10); + WORD_TABLE = init_ht(500); + EVAL_STACK = init_array(10); + FLIT = init_ht(500); + OBJ_TABLE = init_ht(500); + + add_funcs(); + + while (1) { + v = parser_get_next(PARSER); + if (v == NULL) + break; + eval(v); + } + + free(INBUF); + ht_free(WORD_TABLE, value_free); + ht_free(FLIT, func_free); + ht_free(OBJ_TABLE, custom_free); + array_free(STACK); + free(PARSER); + array_free(EVAL_STACK); + return 0; +} diff --git a/src/stem.c b/src/stem.c new file mode 100644 index 0000000..f090940 --- /dev/null +++ b/src/stem.c @@ -0,0 +1,451 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +array_t *STACK; +array_t *EVAL_STACK; +ht_t *WORD_TABLE; +char *INBUF; +parser_t *PARSER; + +ht_t *FLIT; +ht_t *OBJ_TABLE; + +void func_free(void *f) {} + +array_t *init_array(size_t size) { + array_t *a = calloc(1, sizeof(array_t)); + a->size = 0; + a->capacity = size; + a->items = calloc(a->capacity, sizeof(value_t *)); + return a; +} + +void array_append(array_t *a, value_t *v) { + if (a->size >= a->capacity - 2) { + a->capacity = a->capacity * 2; + a->items = realloc(a->items, a->capacity * sizeof(value_t *)); + } + a->items[a->size] = v; + a->size++; +} + +value_t *array_pop(array_t *a) { + if (a->size > 0) { + value_t *v = a->items[a->size - 1]; + a->size--; + return v; + } + return NULL; +} + +void array_extend(array_t *a, array_t *b) { + for (int i = 0; i < b->size; i++) { + array_append(a, b->items[i]); + } +} + +void array_free(array_t *a) { + for (int i = 0; i < a->size; i++) { + value_free(a->items[i]); + } + free(a->items); + free(a); +} + +array_t *array_copy(array_t *a) { + array_t *b = calloc(1, sizeof(array_t)); + b->size = a->size; + b->capacity = a->capacity; + b->items = calloc(b->capacity, sizeof(value_t *)); + for (int i = 0; i < a->size; i++) { + b->items[i] = value_copy(a->items[i]); + } + return b; +} + +value_t *init_value(int type) { + value_t *v = calloc(1, sizeof(value_t)); + v->type = type; + v->escaped = false; + return v; +} + +value_t *value_copy(value_t *v) { + value_t *a = init_value(VINT); + a->type = v->type; + if (v->type == VINT || v->type == VFLOAT) { + a->int_float = v->int_float; + } else if (v->type == VSTR || v->type == VWORD) { + a->str_word = string_copy(v->str_word); + a->escaped = v->escaped; + } else if (v->type == VQUOTE) { + a->quote = array_copy(v->quote); + } else if (v->type == VCUSTOM) { + custom_t *c = ht_get(OBJ_TABLE, a->str_word); + a->custom = c->copyfunc(v->custom); + a->str_word = string_copy(v->str_word); + } + return a; +} + +void value_free(void *vtmp) { + value_t *v = (value_t *)vtmp; + if (v->type == VSTR || v->type == VWORD) { + string_free(v->str_word); + } + if (v->type == VQUOTE) { + array_free(v->quote); + } + if (v->type == VCUSTOM) { + void (*freefunc)(void *) = ht_get(OBJ_TABLE, v->str_word); + freefunc(v->custom); + } + free(v); +} + +custom_t *init_custom(void (*printfunc)(void *), void (*freefunc)(void *), + void *(*copyfunc)(void *)) { + custom_t *c = calloc(1, sizeof(custom_t)); + c->printfunc = printfunc; + c->freefunc = freefunc; + c->copyfunc = copyfunc; + return c; +} + +void custom_free(void *c) { free(c); } + +parser_t *init_parser(char *source) { + parser_t *p = calloc(1, sizeof(parser_t)); + p->i = 0; + p->source = source; + p->c = source[0]; + return p; +} + +void parser_reset(parser_t *p, char *source) { + p->source = source; + p->i = 0; + p->c = source[0]; +} + +void parser_move(parser_t *p) { + if (p->i < strlen(p->source) && p->c != '\0') { + p->i++; + p->c = p->source[p->i]; + } +} + +void parser_skip_whitespace(parser_t *p) { + while (isspace(p->c)) { + parser_move(p); + } +} + +value_t *parse_string(parser_t *p) { + value_t *retv = init_value(VSTR); + parser_move(p); + string_t *s = init_string(NULL); + bool escaped = false; + while (escaped || p->c != '"' && p->c != '\0') { + if (p->c == '\\') { + escaped = true; + parser_move(p); + continue; + } + if (escaped) { + switch (p->c) { + case '"': + string_append(s, '"'); + break; + case 'n': + string_append(s, '\n'); + break; + case 'r': + string_append(s, '\r'); + break; + case 't': + string_append(s, '\t'); + break; + case '\\': + string_append(s, '\\'); + break; + default: + string_append(s, p->c); + break; + } + parser_move(p); + escaped = false; + } else { + string_append(s, p->c); + parser_move(p); + escaped = false; + } + } + parser_move(p); + retv->str_word = s; + return retv; +} + +value_t *parse_quote(parser_t *p) { + value_t *retv = init_value(VQUOTE); + retv->quote = init_array(10); + parser_move(p); + parser_skip_whitespace(p); + while (p->c != ']') { + array_append(retv->quote, parser_get_next(p)); + parser_skip_whitespace(p); + } + parser_move(p); + return retv; +} + +void parser_error(parser_t *p) { exit(1); } + +value_t *parse_word(parser_t *p) { + value_t *retv = init_value(VWORD); + string_t *s = init_string(NULL); + if (p->c == '\\') { + retv->escaped = true; + parser_move(p); + if (isspace(p->c) || p->c == '\0') { + parser_error(p); + } + } + while (!isspace(p->c) && p->c != '\0') { + string_append(s, p->c); + parser_move(p); + } + retv->str_word = s; + return retv; +} + +value_t *parse_num(parser_t *p) { + value_t *retv; + string_t *s = init_string(NULL); + bool is_float = false; + while (isdigit(p->c) || (p->c == '.') && !is_float) { + if (p->c == '.') + is_float = true; + string_append(s, p->c); + parser_move(p); + } + if (is_float) + retv = init_value(VFLOAT); + else + retv = init_value(VINT); + retv->int_float = atof(s->value); + string_free(s); + return retv; +} + +value_t *parser_get_next(parser_t *p) { + parser_skip_whitespace(p); + if (isdigit(p->c)) { + return parse_num(p); + } + switch (p->c) { + case '"': + return parse_string(p); + case '[': + return parse_quote(p); + case '\0': + return NULL; + default: + return parse_word(p); + } +} + +node_t *init_node(string_t *key, void *value) { + node_t *n = calloc(1, sizeof(node_t)); + n->key = key; + n->value = value; + n->next = NULL; + return n; +} + +void node_free(node_t *n, void (*freefunc)(void *)) { + string_free(n->key); + freefunc(n->value); + free(n); +} + +sll_t *init_sll() { + sll_t *l = calloc(1, sizeof(sll_t)); + l->size = 0; + l->head = NULL; + return l; +} + +void sll_add(sll_t *l, string_t *s, void *v) { + if (l->head == NULL) { + node_t *n = init_node(s, v); + l->head = n; + l->size++; + return; + } + node_t *cur = l->head; + while (cur->next != NULL) { + if (strcmp(s->value, cur->key->value) == 0) { + value_free(cur->value); + string_free(s); + cur->value = v; + return; + } + cur = cur->next; + } + if (strcmp(s->value, cur->key->value) == 0) { + value_free(cur->value); + string_free(s); + cur->value = v; + return; + } + node_t *n = init_node(s, v); + cur->next = n; +} + +void sll_add_func(sll_t *l, string_t *s, void *v) { + if (l->head == NULL) { + node_t *n = init_node(s, v); + l->head = n; + l->size++; + return; + } + node_t *cur = l->head; + while (cur->next != NULL) { + if (strcmp(s->value, cur->key->value) == 0) { + string_free(s); + cur->value = v; + return; + } + cur = cur->next; + } + if (strcmp(s->value, cur->key->value) == 0) { + string_free(s); + cur->value = v; + return; + } + node_t *n = init_node(s, v); + cur->next = n; +} + +void *sll_get(sll_t *l, string_t *k) { + if (l->head == NULL) + return NULL; + node_t *cur = l->head; + while (cur != NULL) { + if (strcmp(k->value, cur->key->value) == 0) + return cur->value; + cur = cur->next; + } + return NULL; +} + +void sll_free(sll_t *l, void (*func)(void *)) { + node_t *cur = l->head; + node_t *tmp; + while (cur != NULL) { + tmp = cur; + cur = cur->next; + node_free(tmp, func); + } + free(l); +} + +ht_t *init_ht(size_t size) { + ht_t *h = calloc(1, sizeof(ht_t)); + h->size = size; + h->buckets = calloc(h->size, sizeof(sll_t *)); + for (int i = 0; i < size; i++) { + h->buckets[i] = init_sll(); + } + return h; +} + +void ht_add(ht_t *h, string_t *key, void *v) { + sll_add(h->buckets[hash(h, key->value)], key, v); +} + +void ht_add_func(ht_t *h, string_t *key, void *v) { + sll_add_func(h->buckets[hash(h, key->value)], key, v); +} + +void *ht_get(ht_t *h, string_t *key) { + return sll_get(h->buckets[hash(h, key->value)], key); +} + +bool ht_exists(ht_t *h, string_t *key) { return ht_get(h, key) != NULL; } + +void ht_free(ht_t *h, void (*func)(void *)) { + for (int i = 0; i < h->size; i++) { + sll_free(h->buckets[i], func); + } + free(h->buckets); + free(h); +} + +/* DJB2 HASH FUNCTION */ +unsigned long hash(ht_t *h, char *key) { + unsigned long hash = 5381; + int c; + + while ((c = *key++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return hash % h->size; +} + +bool eval_ht(value_t *v) { + value_t *func = ht_get(WORD_TABLE, v->str_word); + if (func == NULL) + return false; + value_free(v); + if (func->type == VQUOTE) { + for (int i = 0; i < func->quote->size; i++) { + eval(value_copy(func->quote->items[i])); + } + } else { + eval(value_copy(func)); + } + return true; +} + +bool eval_builtins(value_t *v) { + void (*func)(value_t *) = ht_get(FLIT, v->str_word); + if (func == NULL) + return false; + array_append(EVAL_STACK, v); + func(v); + array_pop(EVAL_STACK); + value_free(v); + return true; +} + +void eval(value_t *v) { + switch (v->type) { + case VINT: + case VFLOAT: + case VSTR: + case VQUOTE: + case VERR: + case VCUSTOM: + array_append(STACK, v); + break; + case VWORD: + if (v->escaped) { + v->escaped = false; + array_append(STACK, v); + } else { + if (!eval_builtins(v)) { + if (!eval_ht(v)) { + array_append(STACK, v); + } + } + } + } +} -- cgit