aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordan <[email protected]>2023-06-02 16:22:29 -0400
committerdan <[email protected]>2023-06-02 16:22:29 -0400
commitac8a2fd77f7661b60cf2b272090ece67f65951db (patch)
treed45442d8bcf5c40febb85fc35d02c6c4f1d3684e
parent558b0646c5580454dd35a6bdee07bcc711db134e (diff)
downloadforth-ac8a2fd77f7661b60cf2b272090ece67f65951db.tar.gz
forth-ac8a2fd77f7661b60cf2b272090ece67f65951db.tar.bz2
forth-ac8a2fd77f7661b60cf2b272090ece67f65951db.zip
refactor: always output via buffer
-rw-r--r--drhstrings.c15
-rw-r--r--drhstrings.h8
-rw-r--r--forth.c101
-rw-r--r--forthmachine.c66
-rw-r--r--forthmachine.h (renamed from optable.h)21
-rw-r--r--forthmachine_optable.c (renamed from optable.c)171
-rw-r--r--makefile2
-rw-r--r--stack.c56
-rw-r--r--stack.h2
-rw-r--r--tests/lxiny-examples/stack-manipulation.forth2
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
diff --git a/forth.c b/forth.c
index b2c6552..e44d372 100644
--- a/forth.c
+++ b/forth.c
@@ -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
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/stack.c b/stack.c
index 0fe7235..8393a2a 100644
--- a/stack.c
+++ b/stack.c
@@ -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();
}
}
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