diff options
-rw-r--r-- | forthmachine.c | 36 | ||||
-rw-r--r-- | forthmachine.h | 24 | ||||
-rw-r--r-- | forthmachine_optable.c | 93 | ||||
-rw-r--r-- | stack.c | 5 | ||||
-rw-r--r-- | stack.h | 2 | ||||
-rw-r--r-- | tests/simple-if2.forth | 3 |
6 files changed, 98 insertions, 65 deletions
diff --git a/forthmachine.c b/forthmachine.c index 91c77ff..3820dde 100644 --- a/forthmachine.c +++ b/forthmachine.c @@ -1,6 +1,8 @@ #include "forthmachine.h" +#include <stdio.h> #include <string.h> #include "drhstrings.h" +#include "stack.h" /****/ forthmachine* forthmachine_new() { @@ -12,23 +14,29 @@ forthmachine* forthmachine_new() { return fm; } -static void op_exec(wordop* op, forthmachine* fm, char *word, int len, char* line, int* i) { +static void op_exec(wordop* op, forthmachine* fm) { 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); + switch (op->oplist[j].type) { + case compileditem_literal: + stack_push(fm->s, op->oplist[j].literal); + break; + case compileditem_stackop: + op_exec(op->oplist[j].wordop, fm); + break; + case compileditem_ifcontrol: + { + stackitem si = stack_pop(fm->s); + int jumpto = op->oplist[j].jumpto; + if (!si && jumpto != -1) { + j = jumpto - 1; + } + break; + } } } break; @@ -36,9 +44,13 @@ static void op_exec(wordop* op, forthmachine* fm, char *word, int len, char* lin } static void forthmachine_exec(forthmachine* fm, char *word, int len, char* line, int* i) { + if (0 == strcmp(word, ":")) { + defineop(fm, line, i); + return; + } wordop* op = optable_getop(fm->ot, word); if (op) { - op_exec(op, fm, word, len, line, i); + op_exec(op, fm); } else if (isnumber(word)) { stack_push(fm->s, atoi(word)); } diff --git a/forthmachine.h b/forthmachine.h index 8854eac..50eb4d8 100644 --- a/forthmachine.h +++ b/forthmachine.h @@ -20,32 +20,34 @@ typedef void (*directiveop)(forthmachine* fm, int len, char* line, int* i); extern char* outputbuffer; extern int outputline; +typedef enum { + compileditem_stackop = 0, + compileditem_literal = 1, + compileditem_ifcontrol = 2, +} compileditem_type; + typedef struct { - bool isliteral; + compileditem_type type; union { wordop* wordop; stackitem literal; + struct { + int jumpto; + }; }; } compileditem; typedef enum { - directive = 0, - builtin = 1, - script = 2, - compiled = 3, + builtin = 0, + compiled = 1, } optype; struct wordop { char* word; optype optype; union { - directiveop directive; stackop op; struct { - char* script; - int scriptlen; - }; - struct { compileditem* oplist; int oplistlen; }; @@ -63,6 +65,8 @@ struct optable { */ wordop* optable_getop(optable* optable, char *word); +void defineop(forthmachine* fm, char *input, int* starti); + optable* optable_new(); struct forthmachine { diff --git a/forthmachine_optable.c b/forthmachine_optable.c index 2bfecfc..47ad009 100644 --- a/forthmachine_optable.c +++ b/forthmachine_optable.c @@ -25,18 +25,11 @@ 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}}, @@ -62,20 +55,18 @@ const static wordop inittable[] = { {"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) { + +static 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].type = compileditem_stackop; oplist[i].wordop = wordop; } else { - oplist[i].isliteral = true; + oplist[i].type = compileditem_literal; oplist[i].literal = atoi(script[i]); } } @@ -294,24 +285,6 @@ static void clearstack(forthmachine* fm) { /* 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. @@ -320,7 +293,7 @@ static void ifdirective(forthmachine* fm, int len, char* line, int* starti) { * returns new position of input index * */ -static void defineop(forthmachine* fm, int len_IGNORED, char *input, int* starti) { +void defineop(forthmachine* fm, char *input, int* starti) { optable* optable = fm->ot; // value easier to deal with (than pointer) int i = *starti; @@ -328,10 +301,7 @@ static void defineop(forthmachine* fm, int len_IGNORED, char *input, int* starti 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++; @@ -343,11 +313,50 @@ static void defineop(forthmachine* fm, int len_IGNORED, char *input, int* starti } opcode[opcodei] = '\0'; + + // code to be evaluated when function is called + + compileditem* oplist = malloc(sizeof(compileditem) * DEFINED_FUNC_MAX_LENGTH); + int opsi = 0; + // get code - while (input[i] != ';' && funcscripti < DEFINED_FUNC_MAX_LENGTH) { - funcscript[funcscripti++] = input[i++]; + int wordi = 0; + char wordbuf[WORD_LEN_LIMIT]; + stack* ifcounter = stack_new(); + while (input[i] != ';' && opsi < DEFINED_FUNC_MAX_LENGTH) { + char c = input[i++]; + if (notdelim(c) && wordi < WORD_LEN_LIMIT) { + wordbuf[wordi++] = c; + } else if (wordi > 0) { + wordbuf[wordi] = '\0'; + if (0 == strcmp(wordbuf, "if")) { + oplist[opsi].type = compileditem_ifcontrol; + oplist[opsi].jumpto = -1; + stack_push(ifcounter, opsi); + opsi++; + } else if (0 == strcmp(wordbuf, "then")) { + int ifopi = stack_pop(ifcounter); + oplist[ifopi].jumpto = opsi; + } else if (0 == strcmp(wordbuf, opcode)) { + oplist[opsi].type = compileditem_stackop; + oplist[opsi].wordop = &optable->optable[optable->len]; + opsi++; + } + else { + wordop* wordop = optable_getop(optable, wordbuf); + if (wordop) { + oplist[opsi].type = compileditem_stackop; + oplist[opsi].wordop = wordop; + } else { + oplist[opsi].type = compileditem_literal; + oplist[opsi].literal = atoi(wordbuf); + } + opsi++; + } + wordi = 0; + } } - funcscript[funcscripti] = '\0'; + stack_free(ifcounter); // optable->optable bounds check if (optable->len >= OPTABLE_MAX_SIZE) { @@ -357,9 +366,9 @@ static void defineop(forthmachine* fm, int len_IGNORED, char *input, int* starti } // 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->optable[optable->len].optype = compiled; + optable->optable[optable->len].oplist = oplist; + optable->optable[optable->len].oplistlen = opsi; optable->len++; // move read position forwards @@ -11,6 +11,11 @@ stack* stack_new() { return s; } +void stack_free(stack* s) { + free(s->start); + free(s); +} + void exitunderflow() { fprintf(stderr, "Error Stack Underflow"); exit(1); @@ -15,6 +15,8 @@ typedef struct { stack* stack_new(); +void stack_free(stack* s); + stackitem stack_pop(stack* s); stackitem stack_peek(stack* s); diff --git a/tests/simple-if2.forth b/tests/simple-if2.forth index 92bbc6b..67a72ac 100644 --- a/tests/simple-if2.forth +++ b/tests/simple-if2.forth @@ -1,4 +1,5 @@ INPUT -0 if 5 . then 8 . +: f 0 if 5 . then 8 . ; +f OUTPUT 8 |