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 | |
parent | 558b0646c5580454dd35a6bdee07bcc711db134e (diff) | |
download | forth-ac8a2fd77f7661b60cf2b272090ece67f65951db.tar.gz forth-ac8a2fd77f7661b60cf2b272090ece67f65951db.tar.bz2 forth-ac8a2fd77f7661b60cf2b272090ece67f65951db.zip |
refactor: always output via buffer
-rw-r--r-- | drhstrings.c | 15 | ||||
-rw-r--r-- | drhstrings.h | 8 | ||||
-rw-r--r-- | forth.c | 101 | ||||
-rw-r--r-- | forthmachine.c | 66 | ||||
-rw-r--r-- | forthmachine.h (renamed from optable.h) | 21 | ||||
-rw-r--r-- | forthmachine_optable.c (renamed from optable.c) | 171 | ||||
-rw-r--r-- | makefile | 2 | ||||
-rw-r--r-- | stack.c | 56 | ||||
-rw-r--r-- | stack.h | 2 | ||||
-rw-r--r-- | tests/lxiny-examples/stack-manipulation.forth | 2 |
10 files changed, 260 insertions, 184 deletions
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 <string.h> +#include <stdbool.h> + +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 <stdbool.h> + +bool isnumber(char *text); +bool notdelim(char c); + +#endif @@ -5,108 +5,21 @@ #include <unistd.h> #include <stdbool.h> -#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 <string.h> +#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/optable.h b/forthmachine.h index 811da9f..8854eac 100644 --- a/optable.h +++ b/forthmachine.h @@ -1,9 +1,9 @@ +#ifndef OPTABLE_H +#define OPTABLE_H #include <stdio.h> #include <stdbool.h> #include "stack.h" -#ifndef OPTABLE_H -#define OPTABLE_H #define OPTABLE_MAX_SIZE 1024 #define DEFINED_FUNC_MAX_LENGTH 1024 @@ -11,9 +11,11 @@ typedef struct optable optable; typedef struct wordop wordop; +typedef struct forthmachine forthmachine; + -typedef void (*stackop)(stack *); -typedef void (*directiveop)(stack *, int len, char* line, int* i, optable* optable); +typedef void (*stackop)(forthmachine* fm); +typedef void (*directiveop)(forthmachine* fm, int len, char* line, int* i); extern char* outputbuffer; extern int outputline; @@ -63,4 +65,15 @@ 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/optable.c b/forthmachine_optable.c index de2aab0..9ac925c 100644 --- a/optable.c +++ b/forthmachine_optable.c @@ -1,32 +1,38 @@ -#include "optable.h" +#include "forthmachine.h" #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> - -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); +#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" @@ -50,17 +56,15 @@ const static wordop inittable[] = { {"drop", builtin, {drop}}, {"over", builtin, {over}}, {"rot", builtin, {rot}}, - {"pick", builtin, {stack_pick}}, - {"roll", builtin, {stack_roll}}, + {"pick", builtin, {pick}}, + {"roll", builtin, {roll}}, {"then", builtin, {donothing}}, {"depth", builtin, {depth}}, - {".s", builtin, {stack_printall}}, - {"clearstack", builtin, {stack_clear}}, + {".s", builtin, {printall}}, + {"clearstack", builtin, {clearstack}}, {"if", directive, {ifdirective}}, {":", directive, {defineop}}, }; - -//static int optable->len = 26; #pragma clang diagnostic pop compileditem* optable_compilewords(optable* ot, int len, char** script) { @@ -126,16 +130,19 @@ wordop* optable_getop(optable* optable, char *word) { /* Implementations of builtin functions */ -static void not(stack *s) { +static void not(forthmachine* fm) { + stack* s = fm->s; int x = stack_pop(s); stack_push(s, !x); } -static void drop(stack *s) { +static void drop(forthmachine* fm) { + stack* s = fm->s; stack_pop(s); } -static void over(stack *s) { +static void over(forthmachine* fm) { + stack* s = fm->s; int x = stack_pop(s); int y = stack_pop(s); stack_push(s, y); @@ -143,7 +150,8 @@ static void over(stack *s) { stack_push(s, y); } -static void rot(stack *s) { +static void rot(forthmachine* fm) { + stack* s = fm->s; int x = stack_pop(s); int y = stack_pop(s); int z = stack_pop(s); @@ -152,93 +160,97 @@ static void rot(stack *s) { stack_push(s, z); } -static void swap(stack *s) { +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(stack *s) { +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(stack *s) { +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(stack *s) { +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(stack *s) { +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(stack *s) { +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(stack *s) { +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(stack *s) { +static void dup(forthmachine* fm) { + stack* s = fm->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) { +static void forthmachine_output(forthmachine* fm, stackitem v) { +if (fm->outputbuffer) { char x[WORD_LEN_LIMIT]; - sprintf(x, "%d\n", stack_pop(s)); - strcat(outputbuffer, x); - outputline++; + sprintf(x, "%d\n", v); + strcat(fm->outputbuffer, x); // TODO: fix: UNSAFE! } else { - printf("%d\n", stack_pop(s)); + printf("%d\n", v); +} } + +static void popout(forthmachine* fm) { + stack* s = fm->s; + forthmachine_output(fm, stack_pop(s)); } -static void peekout(stack *s) { +static void peekout(forthmachine* fm) { + stack* s = fm->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); -} + forthmachine_output(fm, x); } -static void donothing(stack *s) { +static void donothing(forthmachine* fm) { // Do nothing at all (i.e. discard token) } -static void depth(stack *s) { +static void depth(forthmachine* fm) { + stack* s = fm->s; stack_push(s, stack_depth(s)); } -static void max(stack *s) { +static void max(forthmachine* fm) { + stack* s = fm->s; int x = stack_pop(s); int y = stack_pop(s); if (x > y) { @@ -248,7 +260,8 @@ static void max(stack *s) { } } -static void min(stack *s) { +static void min(forthmachine* fm) { + stack* s = fm->s; int x = stack_pop(s); int y = stack_pop(s); if (x < y) { @@ -258,18 +271,35 @@ static void min(stack *s) { } } -static void negate(stack *s) { +static void negate(forthmachine* fm) { + stack* s = fm->s; stack_push(s, 0 - stack_pop(s)); } -static void s_abs(stack *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(stack *s, int len, char* line, int* starti, optable* ot_IDNORED) { +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) { @@ -294,7 +324,8 @@ static void ifdirective(stack *s, int len, char* line, int* starti, optable* ot_ * returns new position of input index * */ -static void defineop(stack* s_IGNORED, int len_IGNORED, char *input, int* starti, optable* optable) { +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 @@ -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 @@ -1,4 +1,7 @@ #include "stack.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> 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(); } } @@ -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 |