]> git.mdlowis.com Git - proto/sclpl.git/commitdiff
Clean-up, restructuring, and debugging of control word implementations
authorMichael D. Lowis <mike@mdlowis.com>
Mon, 21 Apr 2014 01:56:08 +0000 (21:56 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Mon, 21 Apr 2014 01:56:08 +0000 (21:56 -0400)
source/slvm/main.c

index 5e545c7af0bc55bad71c665b9810f48dd7d13e62..8e776a3a6686abe4645ad0952d63dff7a409fcc6 100644 (file)
@@ -1,3 +1,6 @@
+#include <stdint.h>
+#include <stdlib.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -22,7 +25,12 @@ typedef struct word_t {
     /** Pointer to the next most recently defined word in the dictionary. */
     struct word_t const* link;
     /** A collection of flags describing attributes of the word. */
-    long flags;
+    struct {
+        long f_hidden : 1;  /*< Flag if this word should be hidden from the interpreter */
+        long f_immed  : 1;  /*< flag if this word should be executed at compile time */
+        long padding  : 6;  /*< Pads the flags to 8-bits */
+        long codesize : 24; /*< The lenght of the bytecode section of the word */
+    } flags;
     /** Pointer to the null terminated string that holds the name of the word. */
     char const* name;
     /**
@@ -63,7 +71,7 @@ static void docolon(long* code) {
     long* prev_code = CodePtr;
     /* Set the next instruction to execute */
     CodePtr = code;
-    /* And loop through until we get the bytecode instructionof 0 (NEXT) */
+    /* And loop through until we get the bytecode instruction of 0 (NEXT) */
     while(*CodePtr)
     {
         /* Execute the byte code instruction */
@@ -82,81 +90,78 @@ static void check_stack(void)
     if(ArgStackPtr < (ArgStack-1))
     {
         puts("Stack Underflow!");
-        exit(1);
+        //exit(1);
     }
 
     if(ArgStackPtr > (ArgStack+30))
     {
         puts("Stack Overflow!");
-        exit(1);
+        //exit(1);
     }
 }
 
 /**
  * Define a built-in word that executes native code */
-#define defcode(name_str,c_name,flags,prev)      \
+#define defcode(name_str,c_name,immed,hide,prev) \
     static void c_name##_code(long* code);       \
-    static char const c_name##_str[];            \
     static word_t const c_name = {               \
         prev,                                    \
-        flags,                                   \
-        c_name##_str,                            \
+        { immed, hide, 0, 0 },                   \
+        name_str,                                \
         &c_name##_code,                          \
         0                                        \
     };                                           \
-    static char const c_name##_str[] = name_str; \
     static void c_name##_code(long* inst_ptr)    \
 
 /**
  * Define a built-in word representing a variable with the provided initial value */
-#define defvar(name_str,c_name,flags,prev,initial) \
+#define defvar(name_str,c_name,immed,hide,prev,initial) \
     static long c_name##_val = initial;            \
-    defcode(name_str,c_name,flags,prev) {          \
+    defcode(name_str,c_name,immed,hide,prev) {          \
         ArgStackPtr++;                             \
         *(ArgStackPtr) = (long)&(c_name##_val);    \
     }
 
 /**
  * Define a built-in word representing a constant with the provided value */
-#define defconst(name_str,c_name,flags,prev,value) \
+#define defconst(name_str,c_name,immed,hide,prev,value) \
     static long const c_name##_val = value;        \
-    defcode(name_str,c_name,flags,prev) {          \
+    defcode(name_str,c_name,immed,hide,prev) {          \
         ArgStackPtr++;                             \
         *(ArgStackPtr) = c_name##_val;             \
     }
 
 /* Built-in Constants
  *****************************************************************************/
-defconst("VERSION",  version,  0, 0,        1);
-defconst("EXECDEF",  execdef,  0, &version, (long)&docolon);
-defconst("F_IMMED",  f_immed,  0, &execdef, 0x01);
-defconst("F_HIDDEN", f_hidden, 0, &f_immed, 0x02);
+defconst("VERSION",  version,  0, 0, 0,        1);
+defconst("EXECDEF",  execdef,  0, 0, &version, (long)&docolon);
+defconst("WORDSZ",   wordsz,   0, 0, &execdef, sizeof(long));
 
 /* Built-in Variables
  *****************************************************************************/
-defvar("state",  state,  0, &f_hidden, 0);
-defvar("here",   here,   0, &state,    0);
-defvar("latest", latest, 0, &here,     0);
+defvar("state",  state,  0, 0, &wordsz, 0);
+defvar("here",   here,   0, 0, &state,  0);
+defvar("latest", latest, 0, 0, &here,   0);
 
 /* Input Words
  *****************************************************************************/
-defcode("getc", get_char, 0, &latest){
+defcode("getc", get_char, 0, 0, &latest){
     ArgStackPtr++;
     *(ArgStackPtr) = getc(stdin);
 }
 
-defcode("ws?", is_ws, 0, &get_char){
+defcode("ws?", is_ws, 0, 0, &get_char){
     char ch = *(ArgStackPtr);
     *(ArgStackPtr) = ((ch == ' ')  || (ch == '\t') ||
                       (ch == '\r') || (ch == '\n'));
 
-    /* Note: total hack to get the prompt to reappear when the user hits
+    /* TODO: total hack to get the prompt to reappear when the user hits
      * enter */
     if(ch == '\n')
         Line_Read = 1;
 }
 
-defcode("getw", get_word, 0, &is_ws){
+defcode("getw", get_word, 0, 0, &is_ws){
     static char buffer[32];
     int i = 0;
     int wschar = 0;
@@ -189,12 +194,12 @@ defcode("getw", get_word, 0, &is_ws){
     *(ArgStackPtr) = (long)&buffer;
 }
 
-defcode("findw", find_word, 0, &get_word){
+defcode("findw", find_word, 0, 0, &get_word){
     word_t const* curr = (word_t const*)latest_val;
     char* name = (char*)*(ArgStackPtr);
     while(curr)
     {
-        if (!(curr->flags & 0x02) && (0 == strcmp(curr->name,name)))
+        if (!(curr->flags.f_hidden) && (0 == strcmp(curr->name,name)))
         {
             break;
         }
@@ -205,18 +210,18 @@ defcode("findw", find_word, 0, &get_word){
 
 /* Branching and Literal Words
  *****************************************************************************/
-defcode("lit", literal, 0, &find_word){
+defcode("lit", literal, 0, 0, &find_word){
     CodePtr++;
     ArgStackPtr++;
     *(ArgStackPtr) = *CodePtr;
 }
 
-defcode("br", branch, 0, &literal){
+defcode("br", branch, 0, 0, &literal){
   CodePtr++;
   CodePtr += *(CodePtr);
 }
 
-defcode("0br", zbranch, 0, &branch){
+defcode("0br", zbranch, 0, 0, &branch){
     if (!(*ArgStackPtr))
     {
         CodePtr++;
@@ -226,15 +231,15 @@ defcode("0br", zbranch, 0, &branch){
 
 /* Compiler Words
  *****************************************************************************/
-defcode("[", lbrack, 0, &zbranch){
+defcode("[", lbrack, 0, 0, &zbranch){
     state_val = 0;
 }
 
-defcode("]", rbrack, 0x01, &lbrack){
+defcode("]", rbrack, 01, &lbrack){
     state_val = 1;
 }
 
-defcode("create", create, 0, &rbrack){
+defcode("create", create, 0, 0, &rbrack){
     /* Copy the name string */
     char* name = 0u;
     if (*(ArgStackPtr))
@@ -246,7 +251,9 @@ defcode("create", create, 0, &rbrack){
     /* Create the word entry */
     word_t* word   = (word_t*)malloc(sizeof(word_t));
     word->link     = (word_t*)latest_val;
-    word->flags    = f_hidden_val;
+    word->flags.f_immed  = 0;
+    word->flags.f_hidden = 1;
+    word->flags.codesize = 0;
     word->name     = name;
     word->codeword = &docolon;
     word->code     = (long*)malloc(sizeof(long));
@@ -257,7 +264,7 @@ defcode("create", create, 0, &rbrack){
     *(ArgStackPtr) = (long)word;
 }
 
-defcode(",", comma, 0, &create){
+defcode(",", comma, 0, 0, &create){
     /* Get the word we are currently compiling */
     word_t* word  = (word_t*)latest_val;
     /* Put the next instruction in place of the terminating NULL that "here"
@@ -272,40 +279,40 @@ defcode(",", comma, 0, &create){
     *((long*)here_val) = 0;
 }
 
-defcode("hidden", hidden, 1, &comma){
-    ((word_t*)*(ArgStackPtr))->flags ^= f_hidden_val;
+defcode("hidden", hidden, 0, 1, &comma){
+    ((word_t*)*(ArgStackPtr))->flags.f_hidden ^= 1;
 }
 
-defcode("immediate", immediate, 1, &hidden){
-    ((word_t*)*(ArgStackPtr))->flags ^= f_immed_val;
+defcode("immediate", immediate, 0, 1, &hidden){
+    ((word_t*)*(ArgStackPtr))->flags.f_immed ^= 1;
 }
 
-defcode(":", colon, 0, &immediate){
+defcode(":", colon, 0, 0, &immediate){
     EXEC(get_word);
     EXEC(create);
     EXEC(rbrack);
 }
 
-defcode(";", semicolon, 1, &colon){
+defcode(";", semicolon, 0, 1, &colon){
     EXEC(lbrack);
     EXEC(hidden);
     ArgStackPtr--;
 }
 
-defcode("'", tick, 1, &semicolon){
-    ArgStackPtr++;
-    *(ArgStackPtr) = *(CodePtr+1);
+defcode("'", tick, 0, 1, &semicolon){
+    EXEC(get_word);
+    EXEC(find_word);
 }
 
 /* Interpreter Words
  *****************************************************************************/
-defcode("execw", exec_word, 0, &tick){
+defcode("execw", exec_word, 0, 0, &tick){
     word_t* word = (word_t*)(*ArgStackPtr);
     ArgStackPtr--;
     EXEC( *(word) );
 }
 
-defcode("parsenum", parse_num, 0, &exec_word){
+defcode("parsenum", parse_num, 0, 0, &exec_word){
     char* end;
     long num = strtol((const char *)*(ArgStackPtr), &end, 10);
     if(end != (char *)*(ArgStackPtr))
@@ -314,12 +321,12 @@ defcode("parsenum", parse_num, 0, &exec_word){
     }
     else
     {
-        puts("Parse Error");
+        printf("%s ? \n", ((char*)*(ArgStackPtr)));
         ArgStackPtr--;
     }
 }
 
-defcode("interpret", interpret, 0, &parse_num){
+defcode("interpret", interpret, 0, 0, &parse_num){
     char* curr_word;
     /* Parse a word */
     EXEC(get_word);
@@ -331,7 +338,7 @@ defcode("interpret", interpret, 0, &parse_num){
     if (*ArgStackPtr)
     {
         /* If we are in immediate mode or the found word is marked immediate */
-        if((state_val == 0) || (((word_t*)*ArgStackPtr)->flags & f_immed_val))
+        if((state_val == 0) || (((word_t*)*ArgStackPtr)->flags.f_immed))
         {
             /* Execute the word */
             EXEC(exec_word);
@@ -361,7 +368,7 @@ defcode("interpret", interpret, 0, &parse_num){
     }
 }
 
-defcode("quit", quit, 0, &interpret){
+defcode("quit", quit, 0, 0, &interpret){
     int i;
     printf("=> ");
     Line_Read = 0;
@@ -390,198 +397,287 @@ defcode("quit", quit, 0, &interpret){
 
 /* Stack Manipulation Words
  *****************************************************************************/
-defcode("drop", drop, 0, &quit){
+defcode("drop", drop, 0, 0, &quit){
     ArgStackPtr--;
 }
 
-defcode("swap", swap, 0, &drop){
+defcode("swap", swap, 0, 0, &drop){
     long temp = *(ArgStackPtr);
     *(ArgStackPtr) = *(ArgStackPtr-1);
     *(ArgStackPtr-1) = temp;
 }
 
-defcode("dup", dup, 0, &swap){
+defcode("dup", dup, 0, 0, &swap){
     ArgStackPtr++;
     *(ArgStackPtr) = *(ArgStackPtr-1);
 }
 
-defcode("over", over, 0, &dup){
+defcode("over", over, 0, 0, &dup){
     ArgStackPtr++;
     *(ArgStackPtr) = *(ArgStackPtr-2);
 }
 
-defcode("rot", rot, 0, &over){
+defcode("rot", rot, 0, 0, &over){
     long temp = *(ArgStackPtr);
     *(ArgStackPtr) = *(ArgStackPtr-1);
     *(ArgStackPtr-1) = *(ArgStackPtr-2);
     *(ArgStackPtr-2) = temp;
 }
 
-defcode("-rot", nrot, 0, &rot){
+defcode("-rot", nrot, 0, 0, &rot){
     long temp = *(ArgStackPtr-2);
     *(ArgStackPtr-2) = *(ArgStackPtr-1);
     *(ArgStackPtr-1) = *(ArgStackPtr);
     *(ArgStackPtr) = temp;
 }
 
-defcode("2drop", twodrop, 0, &nrot){
-    ArgStackPtr -= 2;
-}
-
-defcode("2dup", twodup, 0, &twodrop){
-    ArgStackPtr += 2;
-    *(ArgStackPtr-1) = *(ArgStackPtr-3);
-    *(ArgStackPtr) = *(ArgStackPtr-2);
-}
-
-defcode("2swap", twoswap, 0, &twodup){
-}
-
-defcode("?dup", dup_if, 0, &twoswap){
-    if (*ArgStackPtr)
-    {
-        ArgStackPtr++;
-        *(ArgStackPtr) = *(ArgStackPtr-1);
-    }
-}
-
 /* Arithmetic Words
  *****************************************************************************/
-defcode("+", add, 0, &dup_if){
+defcode("+", add, 0, 0, &nrot){
     *(ArgStackPtr-1) += *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("-", sub, 0, &add){
+defcode("-", sub, 0, 0, &add){
     *(ArgStackPtr-1) -= *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("*", mul, 0, &sub){
+defcode("*", mul, 0, 0, &sub){
     *(ArgStackPtr-1) *= *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("/", divide, 0, &mul){
+defcode("/", divide, 0, 0, &mul){
     *(ArgStackPtr-1) /= *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("%", mod, 0, &divide){
+defcode("%", mod, 0, 0, &divide){
     *(ArgStackPtr-1) %= *(ArgStackPtr);
     ArgStackPtr--;
 }
 
 /* Boolean Conditional Words
  *****************************************************************************/
-defcode("=", equal, 0, &mod){
+defcode("=", equal, 0, 0, &mod){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) == *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("!=", notequal, 0, &equal){
+defcode("!=", notequal, 0, 0, &equal){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) != *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("<", lessthan, 0, &notequal){
+defcode("<", lessthan, 0, 0, &notequal){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) < *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode(">", greaterthan, 0, &lessthan){
+defcode(">", greaterthan, 0, 0, &lessthan){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) > *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("<=", lessthaneq, 0, &greaterthan){
+defcode("<=", lessthaneq, 0, 0, &greaterthan){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) <= *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode(">=", greaterthaneq, 0, &lessthaneq){
+defcode(">=", greaterthaneq, 0, 0, &lessthaneq){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) >= *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("and", and, 0, &greaterthaneq){
+defcode("and", and, 0, 0, &greaterthaneq){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) && *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("or", or, 0, &and){
+defcode("or", or, 0, 0, &and){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) || *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("not", not, 0, &or){
+defcode("not", not, 0, 0, &or){
     *(ArgStackPtr) = !(*(ArgStackPtr));
 }
 
 /* Bitwise Words
  *****************************************************************************/
-defcode("band", band, 0, &not){
+defcode("band", band, 0, 0, &not){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) & *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("bor", bor, 0, &band){
+defcode("bor", bor, 0, 0, &band){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) | *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("bxor", bxor, 0, &bor){
+defcode("bxor", bxor, 0, 0, &bor){
     *(ArgStackPtr-1) = *(ArgStackPtr-1) ^ *(ArgStackPtr);
     ArgStackPtr--;
 }
 
-defcode("bnot", bnot, 0, &bxor){
+defcode("bnot", bnot, 0, 0, &bxor){
     *(ArgStackPtr) = ~(*(ArgStackPtr));
 }
 
 /* Memory Manipulation Words
  *****************************************************************************/
-defcode("!", store, 0, &bnot){
+defcode("!", store, 0, 0, &bnot){
     *((long*)*(ArgStackPtr)) = *(ArgStackPtr-1);
     ArgStackPtr -= 2;
 }
 
-defcode("@", fetch, 0, &store){
+defcode("@", fetch, 0, 0, &store){
     *(ArgStackPtr) = *((long*)*(ArgStackPtr));
 }
 
-defcode("+!", addstore, 0, &fetch){
+defcode("+!", addstore, 0, 0, &fetch){
     *((long*)*(ArgStackPtr)) += *(ArgStackPtr-1);
     ArgStackPtr -= 2;
 }
 
-defcode("-!", substore, 0, &addstore){
+defcode("-!", substore, 0, 0, &addstore){
     *((long*)*(ArgStackPtr)) -= *(ArgStackPtr-1);
     ArgStackPtr -= 2;
 }
 
-defcode("b!", bytestore, 0, &substore){
+defcode("b!", bytestore, 0, 0, &substore){
     *((char*)*(ArgStackPtr)) = (char)*(ArgStackPtr-1);
     ArgStackPtr -= 2;
 }
 
-defcode("b@", bytefetch, 0, &bytestore){
+defcode("b@", bytefetch, 0, 0, &bytestore){
     *(ArgStackPtr) = *((char*)*(ArgStackPtr));
 }
 
-defcode("b@b!", bytecopy, 0, &bytefetch){
+defcode("b@b!", bytecopy, 0, 0, &bytefetch){
 }
 
-defcode("bmove", bytemove, 0, &bytecopy){
+defcode("bmove", bytemove, 0, 0, &bytecopy){
+}
+
+/* Control Flow Words
+ *****************************************************************************/
+defcode("if", _if, 1, 0, &bytemove){
+    // : IF IMMEDIATE
+    //         ' 0BRANCH ,     \ compile 0BRANCH
+    //         HERE @          \ save location of the offset on the stack
+    //         0 ,             \ compile a dummy offset
+    // ;
+}
+
+defcode("then", _then, 1, 0, &_if){
+    // : THEN IMMEDIATE
+    //         DUP
+    //         HERE @ SWAP -   \ calculate the offset from the address saved on the stack
+    //         SWAP !          \ store the offset in the back-filled location
+    // ;
+}
+
+defcode("else", _else, 1, 0, &_then){
+    // : ELSE IMMEDIATE
+    //         ' BRANCH ,      \ definite branch to just over the false-part
+    //         HERE @          \ save location of the offset on the stack
+    //         0 ,             \ compile a dummy offset
+    //         SWAP            \ now back-fill the original (IF) offset
+    //         DUP             \ same as for THEN word above
+    //         HERE @ SWAP -
+    //         SWAP !
+    // ;
+}
+
+/* Debugging Words
+ *****************************************************************************/
+defcode("printw", printw, 0, 0, &_else){
+    word_t* word = (word_t*)*(ArgStackPtr);
+    long* bytecode = word->code;
+    ArgStackPtr--;
+
+    printf("Name:     %s\n", word->name);
+    //printf("Flags:    0x%lX\n", word->flags);
+    if (word->codeword == &docolon)
+    {
+        puts("CodeFn:   docolon");
+        puts("Bytecode:");
+        while(*bytecode)
+        {
+            printf("\t%s\n", ((word_t*) *bytecode)->name);
+            bytecode++;
+        }
+        printf("\tret\n");
+    }
+    else
+    {
+        printf("CodeFn:   0x%lX\n",(long)word->codeword);
+        printf("Bytecode: (native)\n");
+    }
+}
+
+defcode("printallw", printallw, 0, 0, &printw){
+    const word_t* word = (word_t*)latest_val;
+    while(word)
+    {
+        puts(word->name);
+        word = word->link;
+    }
+}
+
+defcode("printdefw", printdefw, 0, 0, &printallw){
+    const word_t* word = (word_t*)latest_val;
+    while(word != &printdefw)
+    {
+        printf("%s\t%lu %lu",
+               word->name,
+               word->flags.f_immed,
+               word->flags.f_hidden);
+        word = word->link;
+    }
 }
 
 /* Main
  *****************************************************************************/
+static void run_tests(void);
+
 int main(int argc, char** argv)
 {
+    run_tests();
     ArgStackPtr = ArgStack - 1;
-    latest_val = (long)&bytemove;
+    latest_val = (long)&printdefw;
     EXEC(quit);
     return 0;
 }
 
+/* Unit Tests
+ *****************************************************************************/
+static char* Current_Test_Desc;
+
+#define TEST(desc) \
+    Current_Test_Desc = desc; \
+    test_setup(); \
+    for(int i=0; i == 0; i++)
+
+#define CHECK(expr) \
+    if (!(expr)) {  \
+        test_setup(); \
+        printf(__FILE__ ":%d:0:FAIL:%s\n\t" #expr "\n", __LINE__-1, Current_Test_Desc); \
+        continue;   \
+    }
+
+static void test_setup(void)
+{
+    ArgStackPtr = ArgStack - 1;
+    CodePtr = 0;
+    latest_val = (long)&printw;
+}
+
+static void run_tests(void) {
+    TEST("Expected 0 to be 1"){
+        CHECK(0 == 1);
+    }
+}
+