From ae385c33001047921262dbb9a8e95029e9a25965 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Sun, 20 Apr 2014 21:56:08 -0400 Subject: [PATCH] Clean-up, restructuring, and debugging of control word implementations --- source/slvm/main.c | 302 +++++++++++++++++++++++++++++---------------- 1 file changed, 199 insertions(+), 103 deletions(-) diff --git a/source/slvm/main.c b/source/slvm/main.c index 5e545c7..8e776a3 100644 --- a/source/slvm/main.c +++ b/source/slvm/main.c @@ -1,3 +1,6 @@ +#include +#include + #include #include #include @@ -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, 0, 1, &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, ÷){ +defcode("%", mod, 0, 0, ÷){ *(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, ¬equal){ +defcode("<", lessthan, 0, 0, ¬equal){ *(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, ¬){ +defcode("band", band, 0, 0, ¬){ *(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); + } +} + -- 2.55.0