diff options
| -rw-r--r-- | drhstrings.c | 15 | ||||
| -rw-r--r-- | drhstrings.h | 8 | ||||
| -rw-r--r-- | forth.c | 101 | ||||
| -rw-r--r-- | forthmachine.c | 66 | ||||
| -rw-r--r-- | forthmachine.h (renamed from optable.h) | 21 | ||||
| -rw-r--r-- | forthmachine_optable.c (renamed from optable.c) | 171 | ||||
| -rw-r--r-- | makefile | 2 | ||||
| -rw-r--r-- | stack.c | 56 | ||||
| -rw-r--r-- | stack.h | 2 | ||||
| -rw-r--r-- | tests/lxiny-examples/stack-manipulation.forth | 2 | 
10 files changed, 260 insertions, 184 deletions
| diff --git a/drhstrings.c b/drhstrings.c new file mode 100644 index 0000000..7585149 --- /dev/null +++ b/drhstrings.c @@ -0,0 +1,15 @@ +#include <string.h> +#include <stdbool.h> + +bool isnumber(char* text) { +    for(int j = strlen(text); j > 0; j--) { +        if(text[j] < '0' && text[j] > '9') { +            return false; +        } +    } +    return true; +} + +bool notdelim(char c) { +    return c != ' ' && c != '\n' && c != '\t' && c != '\0'; +} diff --git a/drhstrings.h b/drhstrings.h new file mode 100644 index 0000000..03fa40c --- /dev/null +++ b/drhstrings.h @@ -0,0 +1,8 @@ +#ifndef DRHSTRINGS_H +#define DRHSTRINGS_H +#include <stdbool.h> + +bool isnumber(char *text); +bool notdelim(char c); + +#endif @@ -5,108 +5,21 @@  #include <unistd.h>  #include <stdbool.h> -#ifndef STACK_H  #include "stack.h" -#endif -#ifndef OPTABLE_H -#include "optable.h" -#endif - -bool isnumber(char *text) { -    for(int j = strlen(text); j > 0; j--) { -        if(text[j] < '0' && text[j] > '9') { -            return false; -        } -    } -    return true; -} - -bool notdelim(char c) { -    return c != ' ' && c != '\n' && c != '\t' && c != '\0'; -} - -typedef struct { -    optable* ot; -    stack* s; -} forthmachine; - -forthmachine* forthmachine_new() { -    forthmachine* fm = malloc(sizeof(forthmachine)); -    fm->ot = optable_new(); -    fm->s = stack_new(); -    return fm; -} - -void eval(forthmachine* fm, int len, char* line); - -void op_exec(wordop* op, forthmachine* fm, char *word, int len, char* line, int* i) { -    switch (op->optype) { -        case script: -            eval(fm, op->scriptlen, op->script); -            break; -        case builtin: -            op->op(fm->s); -            break; -        case directive: -            op->directive(fm->s, len, line, i, fm->ot); -            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); -                } -            } -    } -} - -void exec(forthmachine* fm, char *word, int len, char* line, int* i) { -    wordop* op = optable_getop(fm->ot, word); -    if (op) { -        op_exec(op, fm, word, len, line, i); -    } else if (isnumber(word)) { -        stack_push(fm->s, atoi(word)); -    } -} - -void eval(forthmachine* fm, int len, char* line) { -    char word[WORD_LEN_LIMIT]; -    int wordi = 0; -    for (int i = 0; i < len; 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'; -                exec(fm, word, len, line, &i); -            } -            // start new word -            wordi = 0; -        } -        // end of input string -        if (line[i] == '\0') { -            return; -        } -    } -} +#include "forthmachine.h"  int initialised = false;  forthmachine* fm;  int lastline = 0; -  char* buffer_eval(int len, char* line) {      if (!initialised) {          fm = forthmachine_new();          initialised = true; -        outputline = 0; -        outputbuffer = malloc(sizeof(char) * 1024);      } -    strcpy(outputbuffer, ""); -    eval(fm, len, line); -    if (outputline) { -        outputline = 0; -        return outputbuffer; +    strcpy(fm->outputbuffer, ""); +    forthmachine_eval(fm, len, line); +    if (fm->outputbuffer && strlen(fm->outputbuffer)) { +        return fm->outputbuffer;      } else {          return "";      } @@ -118,7 +31,9 @@ void stdin_eval() {      size_t len = 0;      ssize_t read;      while ((read = getline(&line, &len, stdin)) != -1) { -        eval(fm, len, line); +        forthmachine_eval(fm, len, line); +        printf("%s", fm->outputbuffer); +        strcpy(fm->outputbuffer, "");      }  } diff --git a/forthmachine.c b/forthmachine.c new file mode 100644 index 0000000..91c77ff --- /dev/null +++ b/forthmachine.c @@ -0,0 +1,66 @@ +#include "forthmachine.h" +#include <string.h> +#include "drhstrings.h" +/****/ + +forthmachine* forthmachine_new() { +    forthmachine* fm = (forthmachine*)malloc(sizeof(forthmachine)); +    fm->ot = optable_new(); +    fm->s = stack_new(); +    fm->outputbuffer = (char*)malloc(sizeof(char) * MAX_OUTPUT_BUFFER_SIZE); +    strcpy(fm->outputbuffer, ""); +    return fm; +} + +static void op_exec(wordop* op, forthmachine* fm, char *word, int len, char* line, int* i) { +    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); +                } +            } +            break; +    } +} + +static void forthmachine_exec(forthmachine* fm, char *word, int len, char* line, int* i) { +    wordop* op = optable_getop(fm->ot, word); +    if (op) { +        op_exec(op, fm, word, len, line, i); +    } else if (isnumber(word)) { +        stack_push(fm->s, atoi(word)); +    } +} + +void forthmachine_eval(forthmachine* fm, int len, char* line) { +    char word[WORD_LEN_LIMIT]; +    int wordi = 0; +    for (int i = 0; i < len; 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'; +                forthmachine_exec(fm, word, len, line, &i); +            } +            // start new word +            wordi = 0; +        } +        // end of input string +        if (line[i] == '\0') { +            return; +        } +    } +} diff --git a/optable.h b/forthmachine.h index 811da9f..8854eac 100644 --- a/optable.h +++ b/forthmachine.h @@ -1,9 +1,9 @@ +#ifndef OPTABLE_H +#define OPTABLE_H  #include <stdio.h>  #include <stdbool.h>  #include "stack.h" -#ifndef OPTABLE_H -#define OPTABLE_H  #define OPTABLE_MAX_SIZE 1024  #define DEFINED_FUNC_MAX_LENGTH 1024 @@ -11,9 +11,11 @@  typedef struct optable optable;  typedef struct wordop wordop; +typedef struct forthmachine forthmachine; + -typedef void (*stackop)(stack *); -typedef void (*directiveop)(stack *, int len, char* line, int* i, optable* optable); +typedef void (*stackop)(forthmachine* fm); +typedef void (*directiveop)(forthmachine* fm, int len, char* line, int* i);  extern char* outputbuffer;  extern int outputline; @@ -63,4 +65,15 @@ wordop* optable_getop(optable* optable, char *word);  optable* optable_new(); +struct forthmachine { +    optable* ot; +    stack* s; +    char* outputbuffer; +}; + +#define MAX_OUTPUT_BUFFER_SIZE 1024 + +forthmachine* forthmachine_new(); +void forthmachine_eval(forthmachine* fm, int len, char* line); +  #endif //OPTABLE_H diff --git a/optable.c b/forthmachine_optable.c index de2aab0..9ac925c 100644 --- a/optable.c +++ b/forthmachine_optable.c @@ -1,32 +1,38 @@ -#include "optable.h" +#include "forthmachine.h"  #include <stdbool.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> - -static void not(stack *s); -static void drop(stack *s); -static void over(stack *s); -static void rot(stack *s); -static void swap(stack *s); -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); -static void peekout(stack *s); -static void donothing(stack *s); -static void depth(stack *s); - -static void ifdirective(stack *s, int len, char* line, int* i, optable* ot); -static void defineop(stack *s, int len, char* line, int* i, optable* ot); +#include "drhstrings.h" + +static void not(forthmachine* fm); +static void drop(forthmachine* fm); +static void over(forthmachine* fm); +static void rot(forthmachine* fm); +static void swap(forthmachine* fm); +static void eq(forthmachine* fm); +static void add(forthmachine* fm); +static void mult(forthmachine* fm); +static void s_div(forthmachine* fm); +static void mod(forthmachine* fm); +static void negate(forthmachine* fm); +static void s_abs(forthmachine* fm); +static void max(forthmachine* fm); +static void min(forthmachine* fm); +static void sub(forthmachine* fm); +static void dup(forthmachine* fm); +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" @@ -50,17 +56,15 @@ const static wordop inittable[] = {      {"drop", builtin, {drop}},      {"over", builtin, {over}},      {"rot", builtin, {rot}}, -    {"pick", builtin, {stack_pick}}, -    {"roll", builtin, {stack_roll}}, +    {"pick", builtin, {pick}}, +    {"roll", builtin, {roll}},      {"then", builtin, {donothing}},      {"depth", builtin, {depth}}, -    {".s", builtin, {stack_printall}}, -    {"clearstack", builtin, {stack_clear}}, +    {".s", builtin, {printall}}, +    {"clearstack", builtin, {clearstack}},      {"if", directive, {ifdirective}},      {":", directive, {defineop}},  }; - -//static int optable->len = 26;  #pragma clang diagnostic pop  compileditem* optable_compilewords(optable* ot, int len, char** script) { @@ -126,16 +130,19 @@ wordop* optable_getop(optable* optable, char *word) {  /* Implementations of builtin functions */ -static void not(stack *s) { +static void not(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      stack_push(s, !x);  } -static void drop(stack *s) { +static void drop(forthmachine* fm) { +    stack* s = fm->s;      stack_pop(s);  } -static void over(stack *s) { +static void over(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      stack_push(s, y); @@ -143,7 +150,8 @@ static void over(stack *s) {      stack_push(s, y);  } -static void rot(stack *s) { +static void rot(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      int z = stack_pop(s); @@ -152,93 +160,97 @@ static void rot(stack *s) {      stack_push(s, z);  } -static void swap(stack *s) { +static void swap(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      stack_push(s, x);      stack_push(s, y);  } -static void eq(stack *s) { +static void eq(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      stack_push(s, x == y);  } -static void add(stack *s) { +static void add(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      stack_push(s, x + y);  } -static void mult(stack *s) { +static void mult(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      stack_push(s, x * y);  } -static void s_div(stack *s) { +static void s_div(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      stack_push(s, y / x);  } -static void mod(stack *s) { +static void mod(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      stack_push(s, y % x);  } -static void sub(stack *s) { +static void sub(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      stack_push(s, y - x);  } -static void dup(stack *s) { +static void dup(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      stack_push(s, x);      stack_push(s, x);  } -//#ifdef __EMSCRIPTEN__ -int outputline = 0; -char* outputbuffer; -//#endif -static void popout(stack *s) { -if (outputbuffer) { +static void forthmachine_output(forthmachine* fm, stackitem v) { +if (fm->outputbuffer) {      char x[WORD_LEN_LIMIT]; -    sprintf(x, "%d\n", stack_pop(s)); -    strcat(outputbuffer, x); -    outputline++; +    sprintf(x, "%d\n", v); +    strcat(fm->outputbuffer, x); // TODO: fix: UNSAFE!  } else { -    printf("%d\n", stack_pop(s)); +    printf("%d\n", v); +}  } + +static void popout(forthmachine* fm) { +    stack* s = fm->s; +    forthmachine_output(fm, stack_pop(s));  } -static void peekout(stack *s) { +static void peekout(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      stack_push(s, x); -if (outputbuffer) { -    char y[WORD_LEN_LIMIT]; -    sprintf(y, "%d\n", x); -    strcat(outputbuffer, y); -    outputline++; -} else { -    printf("%d\n", x); -} +    forthmachine_output(fm, x);  } -static void donothing(stack *s) { +static void donothing(forthmachine* fm) {      // Do nothing at all (i.e. discard token)  } -static void depth(stack *s) { +static void depth(forthmachine* fm) { +    stack* s = fm->s;      stack_push(s, stack_depth(s));  } -static void max(stack *s) { +static void max(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      if (x > y) { @@ -248,7 +260,8 @@ static void max(stack *s) {      }  } -static void min(stack *s) { +static void min(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      int y = stack_pop(s);      if (x < y) { @@ -258,18 +271,35 @@ static void min(stack *s) {      }  } -static void negate(stack *s) { +static void negate(forthmachine* fm) { +    stack* s = fm->s;      stack_push(s, 0 - stack_pop(s));  } -static void s_abs(stack *s) { +static void s_abs(forthmachine* fm) { +    stack* s = fm->s;      int x = stack_pop(s);      stack_push(s, x < 0 ? 0 - x : x);  } +static void printall(forthmachine* fm) { +    stack_tostringappend(fm->s, MAX_OUTPUT_BUFFER_SIZE, fm->outputbuffer); +} + +static void pick(forthmachine* fm) { +    stack_pick(fm->s); +} +static void roll(forthmachine* fm) { +    stack_roll(fm->s); +} +static void clearstack(forthmachine* fm) { +    stack_clear(fm->s); +} +  /* Directives */ -static void ifdirective(stack *s, int len, char* line, int* starti, optable* ot_IDNORED) { +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) { @@ -294,7 +324,8 @@ static void ifdirective(stack *s, int len, char* line, int* starti, optable* ot_   * returns new position of input index   *   */ -static void defineop(stack* s_IGNORED, int len_IGNORED, char *input, int* starti, optable* optable) { +static void defineop(forthmachine* fm, int len_IGNORED, char *input, int* starti) { +    optable* optable = fm->ot;      // value easier to deal with (than pointer)      int i = *starti;      // name by which the function will be called @@ -1,4 +1,4 @@ -srcfiles := forth.c optable.c stack.c +srcfiles := drhstrings.c forthmachine.c forthmachine_optable.c forth.c stack.c  nativeexe := ./forth @@ -1,4 +1,7 @@  #include "stack.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h>  stack* stack_new() {      stack* s = (stack*)malloc(sizeof(stack)); @@ -8,6 +11,11 @@ stack* stack_new() {      return s;  } +void exitunderflow() { +    fprintf(stderr, "Error Stack Underflow"); +    exit(1); +} +  stackitem stack_pop(stack* s) {      if (s->size > 0) {          s->size = s->size - 1; @@ -15,6 +23,7 @@ stackitem stack_pop(stack* s) {          return si;      } else {          // tried to pop empty stack +        exitunderflow();          return 0;      }  } @@ -24,6 +33,7 @@ stackitem stack_peek(stack* s) {          return s->start[s->size - 1];      } else {          // tried to pop empty stack +        exitunderflow();          return 0;      }  } @@ -31,7 +41,7 @@ stackitem stack_peek(stack* s) {  void stack_push(stack *s, stackitem si) {  //        fprintf(stderr, "pushing %d", si);      if (s->size >= s->maxsize) { -        fprintf(stderr, "Error Stack Overflow"); +        fprintf(stderr, "Error: Stack Overflow");          exit(1);      } else {          s->start[s->size] = si; @@ -39,21 +49,39 @@ void stack_push(stack *s, stackitem si) {      }  } -int stack_depth(stack *s) { +int stack_depth(stack* s) {      return s->size;  } -void stack_printall(stack *s) { -    printf("<%d>", s->size); -    for (int i = 0; i < s->size; i++) { -        printf(" %d", s->start[i]); +/** + * Appends string representing whole stack to the string buffer passed in + */ +void stack_tostringappend(stack* s, int sbmaxlen, char* sb) { +    int i = strlen(sb); +    if (i >= sbmaxlen) { +        fprintf(stderr, "Error: Output would overflow buffer if printed"); +        exit(0);       } -    printf("\n"); +    sprintf(&(sb[i]), "<%d>", s->size); +    i = strlen(sb); +    if (i >= sbmaxlen) { +        fprintf(stderr, "Error: Output would overflow Buffer if printed"); +        exit(0);  +    } +    for (int j = 0; j < s->size; j++) { +        sprintf(&(sb[i]), " %d", s->start[j]); +        i = strlen(sb); +        if (i >= sbmaxlen) { +            fprintf(stderr, "Error: Output would overflow Buffer if printed"); +            exit(0);  +        } +    } +    sprintf(&(sb[i]), "\n");  } -void stack_roll(stack *s) { +void stack_roll(stack* s) {      int posfromtop = stack_pop(s); // top is 0, bottom is s->size - 1 -    const int maxindex = s->size - 1; +    int maxindex = s->size - 1;      int i = maxindex - posfromtop;      if (i >= 0) {          int newtop = s->start[i]; @@ -62,19 +90,19 @@ void stack_roll(stack *s) {          }          s->start[i] = newtop;      } else { -        // no item found -        stack_push(s, 0); +        // tried to pop empty stack +        exitunderflow();      }  }  void stack_pick(stack *s) {      int posfromtop = stack_pop(s); // top is 0, bottom is s->size - 1 -    const int maxindex = s->size - 1; +    int maxindex = s->size - 1;      if (s->size > posfromtop) {          stack_push(s, s->start[maxindex - posfromtop]);      } else { -        // no item found -        stack_push(s, 0); +        // tried to pop empty stack +        exitunderflow();      }  } @@ -23,7 +23,7 @@ void stack_push(stack *s, stackitem si);  int stack_depth(stack *s); -void stack_printall(stack *s); +void stack_tostringappend(stack* s, int sbmaxlen, char* sb);  void stack_roll(stack *s); diff --git a/tests/lxiny-examples/stack-manipulation.forth b/tests/lxiny-examples/stack-manipulation.forth index 1192bb9..0d1924c 100644 --- a/tests/lxiny-examples/stack-manipulation.forth +++ b/tests/lxiny-examples/stack-manipulation.forth @@ -1,6 +1,6 @@  INPUT  3 dup .s clearstack -2 5 swap  .s clearstack +2 5 swap .s clearstack  6 4 5 rot .s clearstack  4 0 drop .s clearstack  1 2 3 nip .s clearstack | 
