aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordan <[email protected]>2023-05-30 17:10:55 -0400
committerdan <[email protected]>2023-05-30 17:10:55 -0400
commit66d61a5546e5e0173f92e941ab489a1c6474473e (patch)
tree17ccb05b23b3c86bae385ec2f49f6a7fc424ff76
parent0ba0482710f0a3300c0743a2a986e117972e6ec8 (diff)
downloadforth-66d61a5546e5e0173f92e941ab489a1c6474473e.tar.gz
forth-66d61a5546e5e0173f92e941ab489a1c6474473e.tar.bz2
forth-66d61a5546e5e0173f92e941ab489a1c6474473e.zip
feat: JIT-compiled ops are in an array
-rw-r--r--forth.c78
-rw-r--r--optable.c80
-rw-r--r--optable.h14
-rwxr-xr-xruntests.sh2
4 files changed, 113 insertions, 61 deletions
diff --git a/forth.c b/forth.c
index 9370eb5..9f4e34f 100644
--- a/forth.c
+++ b/forth.c
@@ -27,28 +27,32 @@ bool notdelim(char c) {
void eval(optable* ot, stack* s, int len, char* line);
+void op_exec(wordop* op, optable* ot, stack *s, char *word, int len, char* line, int* i) {
+ switch (op->optype) {
+ case script:
+ eval(ot, s, op->scriptlen, op->script);
+ break;
+ case builtin:
+ op->op(s);
+ break;
+ case directive:
+ op->directive(s, len, line, i, ot);
+ break;
+ case compiled:
+ for (int j = 0; j < op->oplistlen; j++) {
+ if (op->oplist[j].isliteral) {
+ stack_push(s, op->oplist[j].literal);
+ } else {
+ op_exec(op->oplist[j].wordop, ot, s, word, len, line, i);
+ }
+ }
+ }
+}
+
void exec(optable* ot, stack *s, char *word, int len, char* line, int* i) {
wordop* op = optable_getop(ot, word);
if (op) {
- switch (op->optype) {
- case script:
- eval(ot, s, op->scriptlen, op->script);
- break;
- case builtin:
- op->op(s);
- break;
- case directive:
- op->directive(s, len, line, i, ot);
- break;
- case compiled:
- for (int i = 0; i < op->oplistlen; i++) {
- if (op->oplist[i].isliteral) {
- stack_push(s, op->oplist[i].literal);
- } else {
- (op->oplist[i].stackop)(s);
- }
- }
- }
+ op_exec(op, ot, s, word, len, line, i);
} else if (isnumber(word)) {
stack_push(s, atoi(word));
}
@@ -76,11 +80,11 @@ void eval(optable* ot, stack* s, int len, char* line) {
}
-int main(int argc, char** argv) {
- optable* ot = optable_init();
+#ifndef __EMSCRIPTEN__
+int main(int argc, char** argv) {
+ optable* ot = optable_new();
stack* s = stack_new();
-
char *line = NULL;
size_t len = 0;
ssize_t read;
@@ -88,3 +92,33 @@ int main(int argc, char** argv) {
eval(ot, s, len, line);
}
}
+
+#else
+
+#include <emscripten/emscripten.h>
+int initialised = false;
+optable* ot;
+stack* s;
+int lastline = 0;
+
+#define EXTERN
+
+EXTERN EMSCRIPTEN_KEEPALIVE char* extern_eval(int len, char* line) {
+ if (!initialised) {
+ ot = optable_new();
+ s = stack_new();
+ initialised = true;
+ outputline = malloc(sizeof(int));
+ *outputline = 0;
+ // outputtobuffer = true;
+ }
+ eval(ot, s, len, line);
+ if (*outputline != lastline) {
+ lastline = *outputline;
+ return outputbuffer;
+ } else {
+ return "";
+ }
+
+}
+#endif
diff --git a/optable.c b/optable.c
index 9ce3085..efd01e3 100644
--- a/optable.c
+++ b/optable.c
@@ -63,13 +63,13 @@ const static wordop inittable[] = {
//static int optable->len = 26;
#pragma clang diagnostic pop
-compileditem* compilewords(optable* ot, int len, char** script) {
+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].stackop = wordop->op;
+ oplist[i].wordop = wordop;
} else {
oplist[i].isliteral = true;
oplist[i].literal = atoi(script[i]);
@@ -78,39 +78,40 @@ compileditem* compilewords(optable* ot, int len, char** script) {
return oplist;
}
-optable* optable_init() {
- 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);
-
- ot->optable[ot->len].word = "nip";
+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;
- int oplistlen = 2;
- ot->optable[ot->len].oplistlen = oplistlen;
- char* ws[] = {"swap", "drop"};
- compileditem* oplist = compilewords(ot, 2, ws);
+ ot->optable[ot->len].oplistlen = len;
+ compileditem* oplist = optable_compilewords(ot, len, words);
ot->optable[ot->len].oplist = oplist;
ot->len++;
+}
- ot->optable[ot->len].word = "tuck";
- ot->optable[ot->len].optype = compiled;
- oplistlen = 3;
- ot->optable[ot->len].oplistlen = oplistlen;
- char* ws2[] = {"dup", "rot", "rot"};
- oplist = compilewords(ot, oplistlen, ws2);
- 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);
- ot->optable[ot->len].word = "incr";
- ot->optable[ot->len].optype = compiled;
- oplistlen = 2;
- ot->optable[ot->len].oplistlen = oplistlen;
- char* ws3[] = {"1", "+"};
- oplist = compilewords(ot, 2, ws3);
- ot->optable[ot->len].oplist = oplist;
- ot->len++;
+ 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;
}
@@ -200,14 +201,25 @@ static void dup(stack *s) {
stack_push(s, x);
}
+
static void popout(stack *s) {
- printf("%d\n", stack_pop(s));
+#ifdef __EMSCRIPTEN__
+ sprintf(outputbuffer, "%d\n", stack_pop(s));
+ (*outputline)++;
+#else
+ printf("%d\n", stack_pop(s));
+#endif
}
static void peekout(stack *s) {
int x = stack_pop(s);
stack_push(s, x);
- printf("%d\n", x);
+#ifdef __EMSCRIPTEN__
+ sprintf(outputbuffer, "%d\n", x);
+ (*outputline)++;
+#else
+ printf("%d\n", x);
+#endif
}
static void donothing(stack *s) {
@@ -278,11 +290,11 @@ static void defineop(stack* s_IGNORED, int len_IGNORED, char *input, int* starti
// 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);
+ 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);
+ char* funcscript = malloc(sizeof(char) * DEFINED_FUNC_MAX_LENGTH);
int funcscripti = 0;
// skip ' ' and ':'
diff --git a/optable.h b/optable.h
index b378a9f..9675678 100644
--- a/optable.h
+++ b/optable.h
@@ -10,14 +10,20 @@
#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);
+#ifdef __EMSCRIPTEN__
+extern char outputbuffer[1024];
+extern int* outputline;
+#endif
+
typedef struct {
bool isliteral;
union {
- stackop stackop;
+ wordop* wordop;
stackitem literal;
};
} compileditem;
@@ -29,7 +35,7 @@ typedef enum {
compiled = 3,
} optype;
-typedef struct {
+struct wordop {
char* word;
optype optype;
union {
@@ -44,7 +50,7 @@ typedef struct {
int oplistlen;
};
};
-} wordop;
+};
struct optable {
int len;
@@ -57,6 +63,6 @@ struct optable {
*/
wordop* optable_getop(optable* optable, char *word);
-optable* optable_init();
+optable* optable_new();
#endif //OPTABLE_H
diff --git a/runtests.sh b/runtests.sh
index 766850d..3900871 100755
--- a/runtests.sh
+++ b/runtests.sh
@@ -24,7 +24,7 @@ runtest () {
if [ "1" -eq "$?" ] ; then
echo "Test $n failed: $file" >&2
- echo "Diff: (expected vs actual)" >&2
+ echo "Diff: (actual vs expected)" >&2
echo "$diff"
exitcode=1
failed="$(expr "$failed" + 1)"