diff options
| -rw-r--r-- | forth.c | 53 | ||||
| -rw-r--r-- | makefile | 2 | ||||
| -rw-r--r-- | optable.c | 61 | ||||
| -rw-r--r-- | optable.h | 10 | 
4 files changed, 74 insertions, 52 deletions
| @@ -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; +            }          }  } @@ -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: @@ -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); +} @@ -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; | 
