aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--forthmachine.c36
-rw-r--r--forthmachine.h24
-rw-r--r--forthmachine_optable.c93
-rw-r--r--stack.c5
-rw-r--r--stack.h2
-rw-r--r--tests/simple-if2.forth3
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
diff --git a/stack.c b/stack.c
index 8393a2a..9242f2d 100644
--- a/stack.c
+++ b/stack.c
@@ -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);
diff --git a/stack.h b/stack.h
index 3769fd5..daedca7 100644
--- a/stack.h
+++ b/stack.h
@@ -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