aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordan <[email protected]>2023-05-26 14:59:16 -0400
committerdan <[email protected]>2023-05-26 14:59:16 -0400
commit2b7ea0857da80e1353ce0a72239093f108fdc1e9 (patch)
treebdcfe9a653c94d0385cea58156225149f92dc3ad
parent4e26b8c0a1b7fc843741105d57da863997e7284b (diff)
downloadforth-2b7ea0857da80e1353ce0a72239093f108fdc1e9.tar.gz
forth-2b7ea0857da80e1353ce0a72239093f108fdc1e9.tar.bz2
forth-2b7ea0857da80e1353ce0a72239093f108fdc1e9.zip
refactor: if and : moved to optable too
-rw-r--r--forth.c53
-rw-r--r--makefile2
-rw-r--r--optable.c61
-rw-r--r--optable.h10
4 files changed, 74 insertions, 52 deletions
diff --git a/forth.c b/forth.c
index 0b4a99f..a9407ef 100644
--- a/forth.c
+++ b/forth.c
@@ -26,60 +26,43 @@ char isnumber(char *text) {
void eval(stack* s, int len, char* line);
-void exec(stack *s, char *word) {
+void exec(stack *s, char *word, int len, char* line, int* i) {
wordop* op = getop(word);
if (op) {
- if (op->isscript) {
+ if (op->optype == script) {
eval(s, op->scriptlen, op->script);
- } else {
+ } else if (op->optype == builtin) {
op->op(s);
+ } else if (op->optype == directive) {
+ op->directive(s, len, line, i);
}
- return;
- }
- if (isnumber(word)) {
+ } else if (isnumber(word)) {
push(s, atoi(word));
- return;
}
}
+bool notdelim(char c) {
+ return c != ' ' && c != '\n' && c != '\t' && c != '\0';
+}
+
void eval(stack* s, int len, char* line) {
- char word[WORD_LEN_LIMIT];
+ char word[WORD_LEN_LIMIT];
int wordi = 0;
for (int i = 0; i < len; i++) {
- // end of input is \n, char after end of input is \0
- if (line[i] == '\0') {
- return;
- }
- if (line[i] != ' ' &&
- line[i] != '\n' && wordi < WORD_LEN_LIMIT - 1) {
- if (line[i] == ':') {
- i = defineop(i, line);
- wordi = 0;
- } else {
- word[wordi++] = line[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';
- if (!strcmp(word, "if")) {
- stackitem predicate = pop(s);
- if (!predicate) {
- while (len > i && !(
- line[i-3] == 't' &&
- line[i-2] == 'h' &&
- line[i-1] == 'e' &&
- line[i] == 'n'
- )) {
- i++;
- }
- }
- } else {
- exec(s, word);
- }
+ exec(s, word, len, line, &i);
}
// start new word
wordi = 0;
}
+ // end of input string
+ if (line[i] == '\0') {
+ return;
+ }
}
}
diff --git a/makefile b/makefile
index db42381..db37b0e 100644
--- a/makefile
+++ b/makefile
@@ -1,5 +1,5 @@
build:
- gcc forth.c optable.c stack.c -o forth
+ clang forth.c optable.c stack.c -o ./forth -Wall
run:
./forth
run-rlwrap:
diff --git a/optable.c b/optable.c
index d74e2e9..71ef581 100644
--- a/optable.c
+++ b/optable.c
@@ -1,4 +1,5 @@
#include "optable.h"
+#include <stdio.h>
#include <string.h>
static void not(stack *s);
@@ -15,22 +16,31 @@ static void dup(stack *s);
static void popout(stack *s);
static void peekout(stack *s);
+static void ifdirective(stack *s, int len, char* line, int* i);
+static void defineopdirective(stack *s, 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
static wordop optable[OPTABLE_MAX_SIZE] = {
- {".", false, popout},
- {"peek", false, peekout},
- {"+", false, add},
- {"-", false, sub},
- {"*", false, mult},
- {"/", false, s_div},
- {"dup", false, dup},
- {"not", false, not},
- {"=", false, eq},
- {"swap", false, swap},
- {"drop", false, drop},
- {"over", false, over},
- {"rot", false, rot},
+ {".", builtin, {popout}},
+ {"peek", builtin, {peekout}},
+ {"+", builtin, {add}},
+ {"-", builtin, {sub}},
+ {"*", builtin, {mult}},
+ {"/", builtin, {s_div}},
+ {"dup", builtin, {dup}},
+ {"not", builtin, {not}},
+ {"=", builtin, {eq}},
+ {"swap", builtin, {swap}},
+ {"drop", builtin, {drop}},
+ {"over", builtin, {over}},
+ {"rot", builtin, {rot}},
+ {"if", directive, {ifdirective}},
+ {":", directive, {defineopdirective}},
};
-static int optablelen = 13;
+static int optablelen = 15;
+#pragma clang diagnostic pop
int defineop(int starti, char *input) {
// name by which the function will be called
@@ -66,7 +76,7 @@ int defineop(int starti, char *input) {
}
// add op to end of table, and increment size
optable[optablelen].word = opcode;
- optable[optablelen].isscript = true;
+ optable[optablelen].optype = script;
optable[optablelen].script = funcscript;
optable[optablelen].scriptlen = funcscripti;
optablelen++;
@@ -162,3 +172,24 @@ static void peekout(stack *s) {
push(s, x);
printf("%d\n", x);
}
+
+
+/* Directives */
+
+static void ifdirective(stack *s, int len, char* line, int* i) {
+ stackitem predicate = pop(s);
+ if (!predicate) {
+ while (len > *i && !(
+ line[*i-3] == 't' &&
+ line[*i-2] == 'h' &&
+ line[*i-1] == 'e' &&
+ line[*i] == 'n'
+ )) {
+ (*i)++;
+ }
+ }
+}
+
+static void defineopdirective(stack *s, int len, char* line, int* i) {
+ *i = defineop(*i, line);
+}
diff --git a/optable.h b/optable.h
index d85ff3d..ebf9a06 100644
--- a/optable.h
+++ b/optable.h
@@ -10,11 +10,19 @@
#define WORD_LEN_LIMIT 255
typedef void (*stackop)(stack *);
+typedef void (*directiveop)(stack *, int len, char* line, int* i);
+
+typedef enum {
+ directive = 0,
+ builtin = 1,
+ script = 2,
+} optype;
typedef struct {
char* word;
- bool isscript;
+ optype optype;
union {
+ directiveop directive;
stackop op;
struct {
char* script;