diff options
author | dan <[email protected]> | 2023-06-02 16:22:29 -0400 |
---|---|---|
committer | dan <[email protected]> | 2023-06-02 16:22:29 -0400 |
commit | ac8a2fd77f7661b60cf2b272090ece67f65951db (patch) | |
tree | d45442d8bcf5c40febb85fc35d02c6c4f1d3684e /forthmachine_optable.c | |
parent | 558b0646c5580454dd35a6bdee07bcc711db134e (diff) | |
download | forth-ac8a2fd77f7661b60cf2b272090ece67f65951db.tar.gz forth-ac8a2fd77f7661b60cf2b272090ece67f65951db.tar.bz2 forth-ac8a2fd77f7661b60cf2b272090ece67f65951db.zip |
refactor: always output via buffer
Diffstat (limited to 'forthmachine_optable.c')
-rw-r--r-- | forthmachine_optable.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/forthmachine_optable.c b/forthmachine_optable.c new file mode 100644 index 0000000..9ac925c --- /dev/null +++ b/forthmachine_optable.c @@ -0,0 +1,371 @@ +#include "forthmachine.h" +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "drhstrings.h" + +static void not(forthmachine* fm); +static void drop(forthmachine* fm); +static void over(forthmachine* fm); +static void rot(forthmachine* fm); +static void swap(forthmachine* fm); +static void eq(forthmachine* fm); +static void add(forthmachine* fm); +static void mult(forthmachine* fm); +static void s_div(forthmachine* fm); +static void mod(forthmachine* fm); +static void negate(forthmachine* fm); +static void s_abs(forthmachine* fm); +static void max(forthmachine* fm); +static void min(forthmachine* fm); +static void sub(forthmachine* fm); +static void dup(forthmachine* fm); +static void popout(forthmachine* fm); +static void peekout(forthmachine* fm); +static void donothing(forthmachine* fm); +static void depth(forthmachine* fm); + +static void printall(forthmachine* fm); +static void pick(forthmachine* fm); +static void roll(forthmachine* fm); +static void clearstack(forthmachine* fm); + +static void ifdirective(forthmachine* fm, int len, char* line, int* i); +static void defineop(forthmachine* fm, int len, char* line, int* i); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wincompatible-function-pointer-types" +// clang seems to not realise that the union can contain fp types beyond the first +const static wordop inittable[] = { + {".", builtin, {popout}}, + {"peek", builtin, {peekout}}, + {"+", builtin, {add}}, + {"-", builtin, {sub}}, + {"*", builtin, {mult}}, + {"/", builtin, {s_div}}, + {"negate", builtin, {negate}}, + {"abs", builtin, {s_abs}}, + {"mod", builtin, {mod}}, + {"max", builtin, {max}}, + {"min", builtin, {min}}, + {"dup", builtin, {dup}}, + {"not", builtin, {not}}, + {"=", builtin, {eq}}, + {"swap", builtin, {swap}}, + {"drop", builtin, {drop}}, + {"over", builtin, {over}}, + {"rot", builtin, {rot}}, + {"pick", builtin, {pick}}, + {"roll", builtin, {roll}}, + {"then", builtin, {donothing}}, + {"depth", builtin, {depth}}, + {".s", builtin, {printall}}, + {"clearstack", builtin, {clearstack}}, + {"if", directive, {ifdirective}}, + {":", directive, {defineop}}, +}; +#pragma clang diagnostic pop + +compileditem* optable_compilewords(optable* ot, int len, char** script) { + compileditem* oplist = malloc(sizeof(compileditem) * len); + for (int i = 0; i < len; i++) { + wordop* wordop = optable_getop(ot, script[i]); + if (wordop) { + oplist[i].isliteral = false; + oplist[i].wordop = wordop; + } else { + oplist[i].isliteral = true; + oplist[i].literal = atoi(script[i]); + } + } + return oplist; +} + +void optable_addop(optable* ot, char* name, int len, char** words) { + ot->optable[ot->len].word = malloc(sizeof(name)); + strcpy(ot->optable[ot->len].word, name); + ot->optable[ot->len].optype = compiled; + ot->optable[ot->len].oplistlen = len; + compileditem* oplist = optable_compilewords(ot, len, words); + ot->optable[ot->len].oplist = oplist; + ot->len++; +} + +optable* optable_new() { + optable* ot = malloc(sizeof(optable)); + ot->optable = malloc(sizeof(wordop) * OPTABLE_MAX_SIZE); + int inittablesize = sizeof(inittable); + ot->len = inittablesize / sizeof(*inittable); + memcpy(ot->optable, inittable, inittablesize); + + typedef struct { + char* name; + int len; + char** words; + } tocompile; + tocompile defs[] = { + {"nip", 2, (char*[]){"swap","drop"}}, + {"tuck", 3, (char*[]){"dup", "rot", "rot"}}, + {"incr", 2, (char*[]){"1", "+"}}, + }; + int defslen = sizeof(defs) / sizeof(*defs); + for (int i = 0; i < defslen; i++) { + tocompile d = defs[i]; + char* nm = defs[i].name; + char** ws = d.words; + optable_addop(ot,nm, d.len,ws); + } + return ot; +} + +wordop* optable_getop(optable* optable, char *word) { + for (int i = 0; i < optable->len; i++) { + if (!strcmp(optable->optable[i].word, word)) { + return &optable->optable[i]; + } + } + return 0; +} + +/* Implementations of builtin functions */ + +static void not(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + stack_push(s, !x); +} + +static void drop(forthmachine* fm) { + stack* s = fm->s; + stack_pop(s); +} + +static void over(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + stack_push(s, y); + stack_push(s, x); + stack_push(s, y); +} + +static void rot(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + int z = stack_pop(s); + stack_push(s, y); + stack_push(s, x); + stack_push(s, z); +} + +static void swap(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + stack_push(s, x); + stack_push(s, y); +} + +static void eq(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + stack_push(s, x == y); +} + +static void add(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + stack_push(s, x + y); +} + +static void mult(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + stack_push(s, x * y); +} + +static void s_div(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + stack_push(s, y / x); +} + +static void mod(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + stack_push(s, y % x); +} + +static void sub(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + stack_push(s, y - x); +} + +static void dup(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + stack_push(s, x); + stack_push(s, x); +} + + +static void forthmachine_output(forthmachine* fm, stackitem v) { +if (fm->outputbuffer) { + char x[WORD_LEN_LIMIT]; + sprintf(x, "%d\n", v); + strcat(fm->outputbuffer, x); // TODO: fix: UNSAFE! +} else { + printf("%d\n", v); +} +} + +static void popout(forthmachine* fm) { + stack* s = fm->s; + forthmachine_output(fm, stack_pop(s)); +} + +static void peekout(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + stack_push(s, x); + forthmachine_output(fm, x); +} + +static void donothing(forthmachine* fm) { + // Do nothing at all (i.e. discard token) +} + +static void depth(forthmachine* fm) { + stack* s = fm->s; + stack_push(s, stack_depth(s)); +} + +static void max(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + if (x > y) { + stack_push(s, x); + } else { + stack_push(s, y); + } +} + +static void min(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + int y = stack_pop(s); + if (x < y) { + stack_push(s, x); + } else { + stack_push(s, y); + } +} + +static void negate(forthmachine* fm) { + stack* s = fm->s; + stack_push(s, 0 - stack_pop(s)); +} + +static void s_abs(forthmachine* fm) { + stack* s = fm->s; + int x = stack_pop(s); + stack_push(s, x < 0 ? 0 - x : x); +} + +static void printall(forthmachine* fm) { + stack_tostringappend(fm->s, MAX_OUTPUT_BUFFER_SIZE, fm->outputbuffer); +} + +static void pick(forthmachine* fm) { + stack_pick(fm->s); +} +static void roll(forthmachine* fm) { + stack_roll(fm->s); +} +static void clearstack(forthmachine* fm) { + stack_clear(fm->s); +} + +/* Directives */ + +static void ifdirective(forthmachine* fm, int len, char* line, int* starti) { + stack* s = fm->s; + int i = *starti; + stackitem predicate = stack_pop(s); + if (!predicate) { + while (len > i && i >= 4 && !( + line[i-4] == 't' && + line[i-3] == 'h' && + line[i-2] == 'e' && + line[i-1] == 'n' + )) { + i++; + } + } + *starti = i; +} + + +/** + * defineop reads a function identifier, followed by the commands to run when the function + * is called, stopping when a semicolon is reached. + * Reading is done from the input string. + * + * returns new position of input index + * + */ +static void defineop(forthmachine* fm, int len_IGNORED, char *input, int* starti) { + optable* optable = fm->ot; + // value easier to deal with (than pointer) + int i = *starti; + // name by which the function will be called + char* opcode = malloc(sizeof(char) * WORD_LEN_LIMIT); + int opcodei = 0; + + // code to be evaluated when function is called + char* funcscript = malloc(sizeof(char) * DEFINED_FUNC_MAX_LENGTH); + int funcscripti = 0; + + // skip ' ' and ':' + while (input[i] == ' ' || input[i] == ':') { + i++; + } + + // get name + while (input[i] != ' ' && opcodei < WORD_LEN_LIMIT) { + opcode[opcodei++] = input[i++]; + } + opcode[opcodei] = '\0'; + + // get code + while (input[i] != ';' && funcscripti < DEFINED_FUNC_MAX_LENGTH) { + funcscript[funcscripti++] = input[i++]; + } + funcscript[funcscripti] = '\0'; + + // optable->optable bounds check + if (optable->len >= OPTABLE_MAX_SIZE) { + // Error + fprintf(stderr, "Error: optable->optable reached max size, failed to create new user defined operation"); + exit(1); + } + // add op to end of table, and increment size + optable->optable[optable->len].word = opcode; + optable->optable[optable->len].optype = script; + optable->optable[optable->len].script = funcscript; + optable->optable[optable->len].scriptlen = funcscripti; + optable->len++; + + // move read position forwards + *starti = i; +} |