From ac8a2fd77f7661b60cf2b272090ece67f65951db Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 2 Jun 2023 16:22:29 -0400 Subject: refactor: always output via buffer --- drhstrings.c | 15 ++ drhstrings.h | 8 + forth.c | 101 +------ forthmachine.c | 66 +++++ forthmachine.h | 79 ++++++ forthmachine_optable.c | 371 ++++++++++++++++++++++++++ makefile | 2 +- optable.c | 340 ----------------------- optable.h | 66 ----- stack.c | 56 +++- stack.h | 2 +- tests/lxiny-examples/stack-manipulation.forth | 2 +- 12 files changed, 592 insertions(+), 516 deletions(-) create mode 100644 drhstrings.c create mode 100644 drhstrings.h create mode 100644 forthmachine.c create mode 100644 forthmachine.h create mode 100644 forthmachine_optable.c delete mode 100644 optable.c delete mode 100644 optable.h diff --git a/drhstrings.c b/drhstrings.c new file mode 100644 index 0000000..7585149 --- /dev/null +++ b/drhstrings.c @@ -0,0 +1,15 @@ +#include +#include + +bool isnumber(char* text) { + for(int j = strlen(text); j > 0; j--) { + if(text[j] < '0' && text[j] > '9') { + return false; + } + } + return true; +} + +bool notdelim(char c) { + return c != ' ' && c != '\n' && c != '\t' && c != '\0'; +} diff --git a/drhstrings.h b/drhstrings.h new file mode 100644 index 0000000..03fa40c --- /dev/null +++ b/drhstrings.h @@ -0,0 +1,8 @@ +#ifndef DRHSTRINGS_H +#define DRHSTRINGS_H +#include + +bool isnumber(char *text); +bool notdelim(char c); + +#endif diff --git a/forth.c b/forth.c index b2c6552..e44d372 100644 --- a/forth.c +++ b/forth.c @@ -5,108 +5,21 @@ #include #include -#ifndef STACK_H #include "stack.h" -#endif -#ifndef OPTABLE_H -#include "optable.h" -#endif - -bool isnumber(char *text) { - for(int j = strlen(text); j > 0; j--) { - if(text[j] < '0' && text[j] > '9') { - return false; - } - } - return true; -} - -bool notdelim(char c) { - return c != ' ' && c != '\n' && c != '\t' && c != '\0'; -} - -typedef struct { - optable* ot; - stack* s; -} forthmachine; - -forthmachine* forthmachine_new() { - forthmachine* fm = malloc(sizeof(forthmachine)); - fm->ot = optable_new(); - fm->s = stack_new(); - return fm; -} - -void eval(forthmachine* fm, int len, char* line); - -void op_exec(wordop* op, forthmachine* fm, char *word, int len, char* line, int* i) { - switch (op->optype) { - case script: - eval(fm, op->scriptlen, op->script); - break; - case builtin: - op->op(fm->s); - break; - case directive: - op->directive(fm->s, len, line, i, fm->ot); - break; - case compiled: - for (int j = 0; j < op->oplistlen; j++) { - if (op->oplist[j].isliteral) { - stack_push(fm->s, op->oplist[j].literal); - } else { - op_exec(op->oplist[j].wordop, fm, word, len, line, i); - } - } - } -} - -void exec(forthmachine* fm, char *word, int len, char* line, int* i) { - wordop* op = optable_getop(fm->ot, word); - if (op) { - op_exec(op, fm, word, len, line, i); - } else if (isnumber(word)) { - stack_push(fm->s, atoi(word)); - } -} - -void eval(forthmachine* fm, int len, char* line) { - char word[WORD_LEN_LIMIT]; - int wordi = 0; - for (int i = 0; i < len; i++) { - if (notdelim(line[i]) && wordi < WORD_LEN_LIMIT - 1) { - word[wordi++] = line[i]; - } else { // end of word - if (wordi > 0) { // don't exec an empty string - word[wordi] = '\0'; - exec(fm, word, len, line, &i); - } - // start new word - wordi = 0; - } - // end of input string - if (line[i] == '\0') { - return; - } - } -} +#include "forthmachine.h" int initialised = false; forthmachine* fm; int lastline = 0; - char* buffer_eval(int len, char* line) { if (!initialised) { fm = forthmachine_new(); initialised = true; - outputline = 0; - outputbuffer = malloc(sizeof(char) * 1024); } - strcpy(outputbuffer, ""); - eval(fm, len, line); - if (outputline) { - outputline = 0; - return outputbuffer; + strcpy(fm->outputbuffer, ""); + forthmachine_eval(fm, len, line); + if (fm->outputbuffer && strlen(fm->outputbuffer)) { + return fm->outputbuffer; } else { return ""; } @@ -118,7 +31,9 @@ void stdin_eval() { size_t len = 0; ssize_t read; while ((read = getline(&line, &len, stdin)) != -1) { - eval(fm, len, line); + forthmachine_eval(fm, len, line); + printf("%s", fm->outputbuffer); + strcpy(fm->outputbuffer, ""); } } diff --git a/forthmachine.c b/forthmachine.c new file mode 100644 index 0000000..91c77ff --- /dev/null +++ b/forthmachine.c @@ -0,0 +1,66 @@ +#include "forthmachine.h" +#include +#include "drhstrings.h" +/****/ + +forthmachine* forthmachine_new() { + forthmachine* fm = (forthmachine*)malloc(sizeof(forthmachine)); + fm->ot = optable_new(); + fm->s = stack_new(); + fm->outputbuffer = (char*)malloc(sizeof(char) * MAX_OUTPUT_BUFFER_SIZE); + strcpy(fm->outputbuffer, ""); + return fm; +} + +static void op_exec(wordop* op, forthmachine* fm, char *word, int len, char* line, int* i) { + switch (op->optype) { + case script: + forthmachine_eval(fm, op->scriptlen, op->script); + break; + case builtin: + op->op(fm); + break; + case directive: + op->directive(fm, len, line, i); + break; + case compiled: + for (int j = 0; j < op->oplistlen; j++) { + if (op->oplist[j].isliteral) { + stack_push(fm->s, op->oplist[j].literal); + } else { + op_exec(op->oplist[j].wordop, fm, word, len, line, i); + } + } + break; + } +} + +static void forthmachine_exec(forthmachine* fm, char *word, int len, char* line, int* i) { + wordop* op = optable_getop(fm->ot, word); + if (op) { + op_exec(op, fm, word, len, line, i); + } else if (isnumber(word)) { + stack_push(fm->s, atoi(word)); + } +} + +void forthmachine_eval(forthmachine* fm, int len, char* line) { + char word[WORD_LEN_LIMIT]; + int wordi = 0; + for (int i = 0; i < len; i++) { + if (notdelim(line[i]) && wordi < WORD_LEN_LIMIT - 1) { + word[wordi++] = line[i]; + } else { // end of word + if (wordi > 0) { // don't exec an empty string + word[wordi] = '\0'; + forthmachine_exec(fm, word, len, line, &i); + } + // start new word + wordi = 0; + } + // end of input string + if (line[i] == '\0') { + return; + } + } +} diff --git a/forthmachine.h b/forthmachine.h new file mode 100644 index 0000000..8854eac --- /dev/null +++ b/forthmachine.h @@ -0,0 +1,79 @@ +#ifndef OPTABLE_H +#define OPTABLE_H +#include +#include +#include "stack.h" + + +#define OPTABLE_MAX_SIZE 1024 +#define DEFINED_FUNC_MAX_LENGTH 1024 +#define WORD_LEN_LIMIT 255 + +typedef struct optable optable; +typedef struct wordop wordop; +typedef struct forthmachine forthmachine; + + +typedef void (*stackop)(forthmachine* fm); +typedef void (*directiveop)(forthmachine* fm, int len, char* line, int* i); + +extern char* outputbuffer; +extern int outputline; + +typedef struct { + bool isliteral; + union { + wordop* wordop; + stackitem literal; + }; +} compileditem; + +typedef enum { + directive = 0, + builtin = 1, + script = 2, + compiled = 3, +} optype; + +struct wordop { + char* word; + optype optype; + union { + directiveop directive; + stackop op; + struct { + char* script; + int scriptlen; + }; + struct { + compileditem* oplist; + int oplistlen; + }; + }; +}; + +struct optable { + int len; + wordop* optable; +}; + +/** + * getop returns the first wordop in the optable which is called by the word given as a parameter + * if none exist, returns 0 + */ +wordop* optable_getop(optable* optable, char *word); + +optable* optable_new(); + +struct forthmachine { + optable* ot; + stack* s; + char* outputbuffer; +}; + +#define MAX_OUTPUT_BUFFER_SIZE 1024 + +forthmachine* forthmachine_new(); +void forthmachine_eval(forthmachine* fm, int len, char* line); + +#endif //OPTABLE_H 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 +#include +#include +#include +#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; +} diff --git a/makefile b/makefile index 80753a3..d2c106e 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -srcfiles := forth.c optable.c stack.c +srcfiles := drhstrings.c forthmachine.c forthmachine_optable.c forth.c stack.c nativeexe := ./forth diff --git a/optable.c b/optable.c deleted file mode 100644 index de2aab0..0000000 --- a/optable.c +++ /dev/null @@ -1,340 +0,0 @@ -#include "optable.h" -#include -#include -#include -#include - -static void not(stack *s); -static void drop(stack *s); -static void over(stack *s); -static void rot(stack *s); -static void swap(stack *s); -static void eq(stack *s); -static void add(stack *s); -static void mult(stack *s); -static void s_div(stack *s); -static void mod(stack *s); -static void negate(stack *s); -static void s_abs(stack *s); -static void max(stack *s); -static void min(stack *s); -static void sub(stack *s); -static void dup(stack *s); -static void popout(stack *s); -static void peekout(stack *s); -static void donothing(stack *s); -static void depth(stack *s); - -static void ifdirective(stack *s, int len, char* line, int* i, optable* ot); -static void defineop(stack *s, int len, char* line, int* i, optable* ot); - -#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, {stack_pick}}, - {"roll", builtin, {stack_roll}}, - {"then", builtin, {donothing}}, - {"depth", builtin, {depth}}, - {".s", builtin, {stack_printall}}, - {"clearstack", builtin, {stack_clear}}, - {"if", directive, {ifdirective}}, - {":", directive, {defineop}}, -}; - -//static int optable->len = 26; -#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(stack *s) { - int x = stack_pop(s); - stack_push(s, !x); -} - -static void drop(stack *s) { - stack_pop(s); -} - -static void over(stack *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(stack *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(stack *s) { - int x = stack_pop(s); - int y = stack_pop(s); - stack_push(s, x); - stack_push(s, y); -} - -static void eq(stack *s) { - int x = stack_pop(s); - int y = stack_pop(s); - stack_push(s, x == y); -} - -static void add(stack *s) { - int x = stack_pop(s); - int y = stack_pop(s); - stack_push(s, x + y); -} - -static void mult(stack *s) { - int x = stack_pop(s); - int y = stack_pop(s); - stack_push(s, x * y); -} - -static void s_div(stack *s) { - int x = stack_pop(s); - int y = stack_pop(s); - stack_push(s, y / x); -} - -static void mod(stack *s) { - int x = stack_pop(s); - int y = stack_pop(s); - stack_push(s, y % x); -} - -static void sub(stack *s) { - int x = stack_pop(s); - int y = stack_pop(s); - stack_push(s, y - x); -} - -static void dup(stack *s) { - int x = stack_pop(s); - stack_push(s, x); - stack_push(s, x); -} - -//#ifdef __EMSCRIPTEN__ -int outputline = 0; -char* outputbuffer; -//#endif - -static void popout(stack *s) { -if (outputbuffer) { - char x[WORD_LEN_LIMIT]; - sprintf(x, "%d\n", stack_pop(s)); - strcat(outputbuffer, x); - outputline++; -} else { - printf("%d\n", stack_pop(s)); -} -} - -static void peekout(stack *s) { - int x = stack_pop(s); - stack_push(s, x); -if (outputbuffer) { - char y[WORD_LEN_LIMIT]; - sprintf(y, "%d\n", x); - strcat(outputbuffer, y); - outputline++; -} else { - printf("%d\n", x); -} -} - -static void donothing(stack *s) { - // Do nothing at all (i.e. discard token) -} - -static void depth(stack *s) { - stack_push(s, stack_depth(s)); -} - -static void max(stack *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(stack *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(stack *s) { - stack_push(s, 0 - stack_pop(s)); -} - -static void s_abs(stack *s) { - int x = stack_pop(s); - stack_push(s, x < 0 ? 0 - x : x); -} - -/* Directives */ - -static void ifdirective(stack *s, int len, char* line, int* starti, optable* ot_IDNORED) { - 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(stack* s_IGNORED, int len_IGNORED, char *input, int* starti, optable* optable) { - // 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; -} diff --git a/optable.h b/optable.h deleted file mode 100644 index 811da9f..0000000 --- a/optable.h +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include "stack.h" - -#ifndef OPTABLE_H -#define OPTABLE_H - -#define OPTABLE_MAX_SIZE 1024 -#define DEFINED_FUNC_MAX_LENGTH 1024 -#define WORD_LEN_LIMIT 255 - -typedef struct optable optable; -typedef struct wordop wordop; - -typedef void (*stackop)(stack *); -typedef void (*directiveop)(stack *, int len, char* line, int* i, optable* optable); - -extern char* outputbuffer; -extern int outputline; - -typedef struct { - bool isliteral; - union { - wordop* wordop; - stackitem literal; - }; -} compileditem; - -typedef enum { - directive = 0, - builtin = 1, - script = 2, - compiled = 3, -} optype; - -struct wordop { - char* word; - optype optype; - union { - directiveop directive; - stackop op; - struct { - char* script; - int scriptlen; - }; - struct { - compileditem* oplist; - int oplistlen; - }; - }; -}; - -struct optable { - int len; - wordop* optable; -}; - -/** - * getop returns the first wordop in the optable which is called by the word given as a parameter - * if none exist, returns 0 - */ -wordop* optable_getop(optable* optable, char *word); - -optable* optable_new(); - -#endif //OPTABLE_H diff --git a/stack.c b/stack.c index 0fe7235..8393a2a 100644 --- a/stack.c +++ b/stack.c @@ -1,4 +1,7 @@ #include "stack.h" +#include +#include +#include stack* stack_new() { stack* s = (stack*)malloc(sizeof(stack)); @@ -8,6 +11,11 @@ stack* stack_new() { return s; } +void exitunderflow() { + fprintf(stderr, "Error Stack Underflow"); + exit(1); +} + stackitem stack_pop(stack* s) { if (s->size > 0) { s->size = s->size - 1; @@ -15,6 +23,7 @@ stackitem stack_pop(stack* s) { return si; } else { // tried to pop empty stack + exitunderflow(); return 0; } } @@ -24,6 +33,7 @@ stackitem stack_peek(stack* s) { return s->start[s->size - 1]; } else { // tried to pop empty stack + exitunderflow(); return 0; } } @@ -31,7 +41,7 @@ stackitem stack_peek(stack* s) { void stack_push(stack *s, stackitem si) { // fprintf(stderr, "pushing %d", si); if (s->size >= s->maxsize) { - fprintf(stderr, "Error Stack Overflow"); + fprintf(stderr, "Error: Stack Overflow"); exit(1); } else { s->start[s->size] = si; @@ -39,21 +49,39 @@ void stack_push(stack *s, stackitem si) { } } -int stack_depth(stack *s) { +int stack_depth(stack* s) { return s->size; } -void stack_printall(stack *s) { - printf("<%d>", s->size); - for (int i = 0; i < s->size; i++) { - printf(" %d", s->start[i]); +/** + * Appends string representing whole stack to the string buffer passed in + */ +void stack_tostringappend(stack* s, int sbmaxlen, char* sb) { + int i = strlen(sb); + if (i >= sbmaxlen) { + fprintf(stderr, "Error: Output would overflow buffer if printed"); + exit(0); } - printf("\n"); + sprintf(&(sb[i]), "<%d>", s->size); + i = strlen(sb); + if (i >= sbmaxlen) { + fprintf(stderr, "Error: Output would overflow Buffer if printed"); + exit(0); + } + for (int j = 0; j < s->size; j++) { + sprintf(&(sb[i]), " %d", s->start[j]); + i = strlen(sb); + if (i >= sbmaxlen) { + fprintf(stderr, "Error: Output would overflow Buffer if printed"); + exit(0); + } + } + sprintf(&(sb[i]), "\n"); } -void stack_roll(stack *s) { +void stack_roll(stack* s) { int posfromtop = stack_pop(s); // top is 0, bottom is s->size - 1 - const int maxindex = s->size - 1; + int maxindex = s->size - 1; int i = maxindex - posfromtop; if (i >= 0) { int newtop = s->start[i]; @@ -62,19 +90,19 @@ void stack_roll(stack *s) { } s->start[i] = newtop; } else { - // no item found - stack_push(s, 0); + // tried to pop empty stack + exitunderflow(); } } void stack_pick(stack *s) { int posfromtop = stack_pop(s); // top is 0, bottom is s->size - 1 - const int maxindex = s->size - 1; + int maxindex = s->size - 1; if (s->size > posfromtop) { stack_push(s, s->start[maxindex - posfromtop]); } else { - // no item found - stack_push(s, 0); + // tried to pop empty stack + exitunderflow(); } } diff --git a/stack.h b/stack.h index 3bc308c..3769fd5 100644 --- a/stack.h +++ b/stack.h @@ -23,7 +23,7 @@ void stack_push(stack *s, stackitem si); int stack_depth(stack *s); -void stack_printall(stack *s); +void stack_tostringappend(stack* s, int sbmaxlen, char* sb); void stack_roll(stack *s); diff --git a/tests/lxiny-examples/stack-manipulation.forth b/tests/lxiny-examples/stack-manipulation.forth index 1192bb9..0d1924c 100644 --- a/tests/lxiny-examples/stack-manipulation.forth +++ b/tests/lxiny-examples/stack-manipulation.forth @@ -1,6 +1,6 @@ INPUT 3 dup .s clearstack -2 5 swap .s clearstack +2 5 swap .s clearstack 6 4 5 rot .s clearstack 4 0 drop .s clearstack 1 2 3 nip .s clearstack -- cgit v1.2.3