diff options
| -rw-r--r-- | forth.c | 12 | ||||
| -rw-r--r-- | optable.c | 87 | ||||
| -rw-r--r-- | optable.h | 15 | ||||
| -rwxr-xr-x | runtests.sh | 7 | ||||
| -rw-r--r-- | stack.c | 3 | 
5 files changed, 122 insertions, 2 deletions
| @@ -40,6 +40,14 @@ void exec(stack *s, char *word, int len, char* line, int* i) {              case directive:                  op->directive(s, len, line, i);                  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); +                    } +                }          }      } else if (isnumber(word)) {          stack_push(s, atoi(word)); @@ -67,8 +75,12 @@ void eval(stack* s, int len, char* line) {      }  } +  int main(int argc, char** argv) { +    optable_init(); +      stack* s = stack_new(); +      char *line = NULL;      size_t len = 0;      ssize_t read; @@ -1,5 +1,7 @@  #include "optable.h" +#include <stdbool.h>  #include <stdio.h> +#include <stdlib.h>  #include <string.h>  static void not(stack *s); @@ -11,6 +13,11 @@ static void eq(stack *s);  static void add(stack *s);  static void mult(stack *s);  static void s_div(stack *s); +static void mod(stack *s); +static void negate(stack *s); +static void s_abs(stack *s); +static void max(stack *s); +static void min(stack *s);  static void sub(stack *s);  static void dup(stack *s);  static void popout(stack *s); @@ -31,6 +38,11 @@ static wordop optable[OPTABLE_MAX_SIZE] = {      {"-", builtin, {sub}},      {"*", builtin, {mult}},      {"/", builtin, {s_div}}, +    {"negate", builtin, {negate}}, +    {"abs", builtin, {s_abs}}, +    {"mod", builtin, {mod}}, +    {"max", builtin, {max}}, +    {"min", builtin, {min}},      {"dup", builtin, {dup}},      {"not", builtin, {not}},      {"=", builtin, {eq}}, @@ -46,9 +58,47 @@ static wordop optable[OPTABLE_MAX_SIZE] = {      {"if", directive, {ifdirective}},      {":", directive, {defineop}},  }; -static int optablelen = 20; +static int optablelen = 25;  #pragma clang diagnostic pop +compileditem* compilewords(int len, char** script) { +    compileditem* oplist = malloc(sizeof(compileditem) * len); +    for (int i = 0; i < len; i++) { +        wordop* wordop = getop(script[i]); +        if (wordop) { +            oplist[i].isliteral = false; +            oplist[i].stackop = wordop->op; +        } else { +            oplist[i].isliteral = true; +            oplist[i].literal = atoi(script[i]); +        } +    } +    return oplist; +} + +void optable_init() { + +    optable[optablelen].word = "nip"; +    optable[optablelen].optype = compiled; +    int oplistlen = 2; +    optable[optablelen].oplistlen = oplistlen; +    char* ws[] = {"swap", "drop"}; +    compileditem* oplist = compilewords(2, ws); +    optable[optablelen].oplist = oplist; +    optablelen++; + + +    optable[optablelen].word = "incr"; +    optable[optablelen].optype = compiled; +    oplistlen = 2; +    optable[optablelen].oplistlen = oplistlen; +    char* ws2[] = {"1", "+"}; +    oplist = compilewords(2, ws2); +    optable[optablelen].oplist = oplist; +    optablelen++; + +} +  wordop* getop(char *word) {      for (int i = 0; i < optablelen; i++) {          if (!strcmp(optable[i].word, word)) { @@ -117,6 +167,12 @@ static void s_div(stack *s) {      stack_push(s, y / x);  } +static void mod(stack *s) { +    int x = stack_pop(s); +    int y = stack_pop(s); +    stack_push(s, y % x); +} +  static void sub(stack *s) {      int x = stack_pop(s);      int y = stack_pop(s); @@ -147,6 +203,35 @@ static void depth(stack *s) {      stack_push(s, stack_depth(s));  } +static void max(stack *s) { +    int x = stack_pop(s); +    int y = stack_pop(s); +    if (x > y) { +        stack_push(s, x); +    } else { +        stack_push(s, y); +    } +} + +static void min(stack *s) { +    int x = stack_pop(s); +    int y = stack_pop(s); +    if (x < y) { +        stack_push(s, x); +    } else { +        stack_push(s, y); +    } +} + +static void negate(stack *s) { +    stack_push(s, 0 - stack_pop(s)); +} + +static void s_abs(stack *s) { +    int x = stack_pop(s); +    stack_push(s, x < 0 ? 0 - x : x); +} +  /* Directives */  static void ifdirective(stack *s, int len, char* line, int* starti) { @@ -12,10 +12,19 @@  typedef void (*stackop)(stack *);  typedef void (*directiveop)(stack *, int len, char* line, int* i); +typedef struct { +    bool isliteral; +    union { +        stackop stackop; +        stackitem literal; +    }; +} compileditem; +  typedef enum {      directive = 0,      builtin = 1,      script = 2, +    compiled = 3,  } optype;  typedef struct { @@ -28,6 +37,10 @@ typedef struct {              char* script;              int scriptlen;          }; +        struct { +            compileditem* oplist; +            int oplistlen; +        };      };  } wordop; @@ -37,4 +50,6 @@ typedef struct {   */  wordop* getop(char *word); +void optable_init(); +  #endif //OPTABLE_H diff --git a/runtests.sh b/runtests.sh index ae77797..b93a45a 100755 --- a/runtests.sh +++ b/runtests.sh @@ -4,6 +4,11 @@ if [ -z "$FORTH_CMD" ] ; then      FORTH_CMD="./forth"  fi +dir='./tests' +if [ "$#" -gt 0 ] ; then +    dir="$1" +fi +  n=0  failed=0 @@ -27,7 +32,7 @@ runtest () {      fi  } -for f in ./tests/*; do +for f in $dir/*.forth; do      n="$(expr "$n" + 1)"      runtest "$f"  done @@ -61,6 +61,9 @@ void stack_roll(stack *s) {              s->start[i] = s->start[i+1];          }          s->start[i] = newtop; +    } else { +        // no item found +        stack_push(s, 0);      }  } | 
