/* Built-in Constants
*****************************************************************************/
/** The argument stack */
-long ArgStack[ARG_STACK_SIZE];
+val_t ArgStack[ARG_STACK_SIZE];
/** Pointer to current position on the stack */
-long* ArgStackPtr = ArgStack-1;
+val_t* ArgStackPtr = ArgStack-1;
/** Pointer to current instruction being executed */
-long* CodePtr = 0;
+val_t* CodePtr = 0;
/** A state variable used to flag when the interpreter reads a line of input */
-long Line_Read = 0;
+val_t Line_Read = 0;
/* Built-in Constants
*****************************************************************************/
-void docolon(long* code) {
+void docolon(val_t* code) {
word_t* word;
/* We may have previously been executing a word so we should save off our
* previous position */
- long* prev_code = CodePtr;
+ val_t* prev_code = CodePtr;
/* Set the next instruction to execute */
CodePtr = code;
/* And loop through until we get the bytecode instruction of 0 (NEXT) */
/* Built-in Constants
*****************************************************************************/
defconst("VERSION", version, 0, 0, 1);
-defconst("EXECDEF", execdef, 0, &version, (long)&docolon);
-defconst("WORDSZ", wordsz, 0, &execdef, sizeof(long));
+defconst("EXECDEF", execdef, 0, &version, (val_t)&docolon);
+defconst("WORDSZ", wordsz, 0, &execdef, sizeof(val_t));
/* Built-in Variables
*****************************************************************************/
/* Return the word */
ArgStackPtr++;
- *(ArgStackPtr) = (long)&buffer;
+ *(ArgStackPtr) = (val_t)&buffer;
}
defcode("findw", find_word, 0, &get_word){
}
curr = curr->link;
}
- *(ArgStackPtr) = (long)curr;
+ *(ArgStackPtr) = (val_t)curr;
}
/* Branching and Literal Words
}
defcode("br", branch, 0, &literal){
- CodePtr = (long*)(((long)CodePtr) + *(CodePtr));
+ CodePtr = (val_t*)(((val_t)CodePtr) + *(CodePtr));
}
defcode("0br", zbranch, 0, &branch){
if (*ArgStackPtr == 0)
{
- CodePtr = (long*)(((long)CodePtr) + *(CodePtr));
+ CodePtr = (val_t*)(((val_t)CodePtr) + *(CodePtr));
}
else
{
/* Initialize the name, codeword, and bytecode */
word->name = name;
word->codeword = &docolon;
- word->code = (long*)malloc(sizeof(long));
- word->code[0] = (long)&ret;
+ word->code = (val_t*)malloc(sizeof(val_t));
+ word->code[0] = (val_t)&ret;
/* Update Latest and Return the new word */
- latest_val = (long)word;
- here_val = (long)word->code;
- *(ArgStackPtr) = (long)word;
+ latest_val = (val_t)word;
+ here_val = (val_t)word->code;
+ *(ArgStackPtr) = (val_t)word;
}
defcode(",", comma, 0, &create){
word_t* word = (word_t*)latest_val;
/* Put the next instruction in place of the terminating 'ret' that "here"
* points too */
- *((long*)here_val) = *(ArgStackPtr);
+ *((val_t*)here_val) = *(ArgStackPtr);
ArgStackPtr--;
/* Resize the code section and relocate if necessary */
word->flags.codesize++;
- word->code = (long*)realloc(word->code, word->flags.codesize * sizeof(long));
+ word->code = (val_t*)realloc(word->code, word->flags.codesize * sizeof(val_t));
/* Update "here" and terminate the code section */
- here_val = (long)(&word->code[word->flags.codesize-1]);
- *((long*)here_val) = (long)&ret;
+ here_val = (val_t)(&word->code[word->flags.codesize-1]);
+ *((val_t*)here_val) = (val_t)&ret;
}
defcode("hidden", hidden, 1, &comma){
defcode("parsenum", parse_num, 0, &exec_word){
char* end;
- long num = strtol((const char *)*(ArgStackPtr), &end, 10);
+ val_t num = strtol((const char *)*(ArgStackPtr), &end, 10);
if(end != (char *)*(ArgStackPtr))
{
*(ArgStackPtr) = num;
/* else parse it as a number */
else
{
- *(ArgStackPtr) = (long)curr_word;
+ *(ArgStackPtr) = (val_t)curr_word;
EXEC(parse_num);
if (state_val == 1)
{
ArgStackPtr++;
- *(ArgStackPtr) = (long)&literal;
+ *(ArgStackPtr) = (val_t)&literal;
EXEC(comma);
EXEC(comma);
}
EXEC(interpret);
if(Line_Read)
{
- long stacksz = ArgStackPtr - ArgStack + 1;
+ val_t stacksz = ArgStackPtr - ArgStack + 1;
if (stacksz > 5)
printf("( ... ");
else
}
defcode("swap", swap, 0, &drop){
- long temp = *(ArgStackPtr);
+ val_t temp = *(ArgStackPtr);
*(ArgStackPtr) = *(ArgStackPtr-1);
*(ArgStackPtr-1) = temp;
}
}
defcode("rot", rot, 0, &over){
- long temp = *(ArgStackPtr);
+ val_t temp = *(ArgStackPtr);
*(ArgStackPtr) = *(ArgStackPtr-1);
*(ArgStackPtr-1) = *(ArgStackPtr-2);
*(ArgStackPtr-2) = temp;
}
defcode("-rot", nrot, 0, &rot){
- long temp = *(ArgStackPtr-2);
+ val_t temp = *(ArgStackPtr-2);
*(ArgStackPtr-2) = *(ArgStackPtr-1);
*(ArgStackPtr-1) = *(ArgStackPtr);
*(ArgStackPtr) = temp;
/* Memory Manipulation Words
*****************************************************************************/
defcode("!", store, 0, &bnot){
- *((long*)*(ArgStackPtr)) = *(ArgStackPtr-1);
+ *((val_t*)*(ArgStackPtr)) = *(ArgStackPtr-1);
ArgStackPtr -= 2;
}
defcode("@", fetch, 0, &store){
- *(ArgStackPtr) = *((long*)*(ArgStackPtr));
+ *(ArgStackPtr) = *((val_t*)*(ArgStackPtr));
}
defcode("+!", addstore, 0, &fetch){
- *((long*)*(ArgStackPtr)) += *(ArgStackPtr-1);
+ *((val_t*)*(ArgStackPtr)) += *(ArgStackPtr-1);
ArgStackPtr -= 2;
}
defcode("-!", substore, 0, &addstore){
- *((long*)*(ArgStackPtr)) -= *(ArgStackPtr-1);
+ *((val_t*)*(ArgStackPtr)) -= *(ArgStackPtr-1);
ArgStackPtr -= 2;
}
// : IF IMMEDIATE
// ' 0BRANCH , \ compile 0BRANCH
ArgStackPtr++;
- *(ArgStackPtr) = (long)&zbranch;
+ *(ArgStackPtr) = (val_t)&zbranch;
EXEC(comma);
// HERE @ \ save location of the offset on the stack
ArgStackPtr++;
EXEC(sub);
// SWAP ! \ store the offset in the back-filled location
EXEC(swap);
- *((long*)*ArgStackPtr) = *(ArgStackPtr-1);
+ *((val_t*)*ArgStackPtr) = *(ArgStackPtr-1);
ArgStackPtr -= 2;
// ;
}
// : ELSE IMMEDIATE
// ' BRANCH , \ definite branch to just over the false-part
ArgStackPtr++;
- *(ArgStackPtr) = (long)&branch;
+ *(ArgStackPtr) = (val_t)&branch;
EXEC(comma);
// HERE @ \ save location of the offset on the stack
ArgStackPtr++;
EXEC(sub);
// SWAP !
EXEC(swap);
- *((long*)*ArgStackPtr) = *(ArgStackPtr-1);
+ *((val_t*)*ArgStackPtr) = *(ArgStackPtr-1);
ArgStackPtr -= 2;
// ;
}
*****************************************************************************/
defcode("printw", printw, 0, &_else){
word_t* word = (word_t*)*(ArgStackPtr);
- long* bytecode = word->code;
+ val_t* bytecode = word->code;
ArgStackPtr--;
printf("Name: %s\n", word->name);
puts("Bytecode:");
while(bytecode)
{
- if (*bytecode == (long)&literal)
+ if (*bytecode == (val_t)&literal)
{
bytecode++;
printf("\tlit %ld\n", *bytecode);
}
- else if (*bytecode == (long)&zbranch)
+ else if (*bytecode == (val_t)&zbranch)
{
bytecode++;
printf("\t0br %ld\n", *bytecode);
printf("\t%s\n", ((word_t*) *bytecode)->name);
}
- if (*bytecode == (long)&ret)
+ if (*bytecode == (val_t)&ret)
{
bytecode = 0;
break;
}
else
{
- printf("CodeFn: 0x%lX\n",(long)word->codeword);
+ printf("CodeFn: 0x%lX\n",(val_t)word->codeword);
printf("Bytecode: (native)\n");
}
}
*****************************************************************************/
int main(int argc, char** argv)
{
- latest_val = (long)&printdefw;
+ CT_ASSERT(sizeof(val_t) == sizeof(val_t*));
+ latest_val = (val_t)&printdefw;
EXEC(quit);
return 0;
}
#ifndef SLVM_H
#define SLVM_H
-//#if defined(_16BIT_)
-//#elif defined(_32BIT_)
-//#elif defined(_64BIT_)
-//#else
-// #error "Invalid architecture"
-//#endif
+#include <stdint.h>
+
+/* Choose a width for val_t that matches the pointer size of the target
+ * architecture. Defaults to simply a long but can be overridden for specific
+ * cases */
+#if defined(_16BIT_)
+ typedef int16_t val_t;
+#elif defined(_32BIT_)
+ typedef int32_t val_t;
+#elif defined(_64BIT_)
+ typedef int64_t val_t;
+#else
+ /* hope for the best? */
+ typedef long val_t;
+#endif
+
+#define CODE_SZ_BITS ((sizeof(val_t) * 8) - 8u)
/**
This type represents a pointer to a function handler for executing a word.
@param code This is a pointer to the next bytecode instruction to execute.
For built-in words this pointer is 0.
*/
-typedef void (*codeword_t)(long* code);
+typedef void (*codeword_t)(val_t* code);
/**
This structure contains all of the relevant attributes of a word definition
struct word_t const* link;
/** A collection of flags describing attributes of the word. */
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 */
+ val_t f_hidden : 1; /*< Flag if this word should be hidden from the interpreter */
+ val_t f_immed : 1; /*< flag if this word should be executed at compile time */
+ val_t padding : 6; /*< Pads the flags to 8-bits */
+ val_t codesize : CODE_SZ_BITS; /*< The length of the bytecode section of the word */
} flags;
/** Pointer to the null terminated string that holds the name of the word. */
char const* name;
/**
* A pointer to the list of instructions that make up this word. For words
* defined in C this will be 0u (NULL). */
- long* code;
+ val_t* code;
} word_t;
/** Execute a built-in word directly */
/**
* Define a built-in word that executes native code */
#define defcode(name_str,c_name,immed,prev) \
- static void c_name##_code(long* code); \
+ static void c_name##_code(val_t* code); \
static word_t const c_name = { \
prev, \
{ 0, immed, 0, 0 }, \
&c_name##_code, \
0 \
}; \
- static void c_name##_code(long* inst_ptr) \
+ static void c_name##_code(val_t* inst_ptr) \
/**
* Define a built-in word representing a variable with the provided initial value */
#define defvar(name_str,c_name,immed,prev,initial) \
- static long c_name##_val = initial; \
+ static val_t c_name##_val = initial; \
defcode(name_str,c_name,immed,prev) { \
ArgStackPtr++; \
- *(ArgStackPtr) = (long)&(c_name##_val); \
+ *(ArgStackPtr) = (val_t)&(c_name##_val); \
}
/**
* Define a built-in word representing a constant with the provided value */
#define defconst(name_str,c_name,immed,prev,value) \
- static long const c_name##_val = value; \
+ static val_t const c_name##_val = value; \
defcode(name_str,c_name,immed,prev) { \
ArgStackPtr++; \
*(ArgStackPtr) = c_name##_val; \
}
+/**
+ * A little C macro hack that allows for some compile time assertions. When the
+ * expression evaluates to false (0) at compile time, the expanded switch
+ * statement will contain two case statements for the value 0 which is a compile
+ * error. Thus the build will break alerting the user that something went
+ * horribly wrong. */
+#define CT_ASSERT(expr) \
+ switch(1){ case(0):break; case(expr):break; default: break; }
+
/**
* This is the "inner" interpreter. This function is responsible for running
* the threaded code that make up colon defintions.
*
* @param code This is a pointer to the next instruction to be executed.
* */
-void docolon(long* code);
+void docolon(val_t* code);
#endif /* SLVM_H */