diff options
author | dan <[email protected]> | 2023-05-30 17:10:55 -0400 |
---|---|---|
committer | dan <[email protected]> | 2023-05-30 17:10:55 -0400 |
commit | 66d61a5546e5e0173f92e941ab489a1c6474473e (patch) | |
tree | 17ccb05b23b3c86bae385ec2f49f6a7fc424ff76 | |
parent | 0ba0482710f0a3300c0743a2a986e117972e6ec8 (diff) | |
download | forth-66d61a5546e5e0173f92e941ab489a1c6474473e.tar.gz forth-66d61a5546e5e0173f92e941ab489a1c6474473e.tar.bz2 forth-66d61a5546e5e0173f92e941ab489a1c6474473e.zip |
feat: JIT-compiled ops are in an array
-rw-r--r-- | forth.c | 78 | ||||
-rw-r--r-- | optable.c | 80 | ||||
-rw-r--r-- | optable.h | 14 | ||||
-rwxr-xr-x | runtests.sh | 2 |
4 files changed, 113 insertions, 61 deletions
@@ -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 @@ -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 ':' @@ -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)" |