Added basic functionality for interpreter platform functions
This commit is contained in:
140
toyforth.c
140
toyforth.c
@@ -37,14 +37,15 @@ typedef struct tfparser {
|
||||
/* Function table entry: each of this entry represents a symbol name
|
||||
* associated with a function implementation.
|
||||
*/
|
||||
struct FunctionTableEntry {
|
||||
struct tfctx;
|
||||
typedef struct FunctionTableEntry {
|
||||
tfobj *name;
|
||||
void (*callback) (tfctx *ctx, tfobj *name);
|
||||
tfobj *user_list;
|
||||
};
|
||||
void (*callback) (struct tfctx *ctx, tfobj *name);
|
||||
tfobj *user_func;
|
||||
} tffuncentry;
|
||||
|
||||
struct FunctionTable {
|
||||
struct FunctionTableEntry **func_table;
|
||||
tffuncentry **func_table;
|
||||
size_t func_count;
|
||||
};
|
||||
|
||||
@@ -54,6 +55,11 @@ typedef struct tfctx {
|
||||
struct FunctionTable functable;
|
||||
} tfctx;
|
||||
|
||||
/* ############################# Function Prototypes #################################### */
|
||||
|
||||
void retain(tfobj *o);
|
||||
void release(tfobj *o);
|
||||
|
||||
/* ############################# Allocations wrappers ################################### */
|
||||
|
||||
void *xmalloc(size_t size)
|
||||
@@ -89,16 +95,6 @@ tfobj *createObject(int type)
|
||||
return o;
|
||||
}
|
||||
|
||||
tfobj *createStringObject(char *s, size_t len)
|
||||
{
|
||||
tfobj *obj = createObject(TFOBJ_TYPE_STR);
|
||||
obj->str.ptr = xmalloc(len+1);
|
||||
obj->str.len = len;
|
||||
memcpy(obj->str.ptr, s, len);
|
||||
obj->str.ptr[len] = 0;
|
||||
return obj;
|
||||
}
|
||||
|
||||
tfobj *createIntObject(int i)
|
||||
{
|
||||
tfobj *obj = createObject(TFOBJ_TYPE_INT);
|
||||
@@ -113,13 +109,6 @@ tfobj *createBoolObject(int b)
|
||||
return obj;
|
||||
}
|
||||
|
||||
tfobj *createSymbolObject(char *s, size_t len)
|
||||
{
|
||||
tfobj *obj = createStringObject(s, len);
|
||||
obj->type = TFOBJ_TYPE_SYMBOL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* Free an object and all the other nested objects. */
|
||||
void freeObject(tfobj *obj) {
|
||||
switch (obj->type) {
|
||||
@@ -178,7 +167,43 @@ void printObject(tfobj *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ############################ List Object ############################################ */
|
||||
/* ############################ String Object ########################################## */
|
||||
|
||||
tfobj *createStringObject(char *s, size_t len)
|
||||
{
|
||||
tfobj *obj = createObject(TFOBJ_TYPE_STR);
|
||||
obj->str.ptr = xmalloc(len+1);
|
||||
obj->str.len = len;
|
||||
memcpy(obj->str.ptr, s, len);
|
||||
obj->str.ptr[len] = 0;
|
||||
return obj;
|
||||
}
|
||||
|
||||
tfobj *createSymbolObject(char *s, size_t len)
|
||||
{
|
||||
tfobj *obj = createStringObject(s, len);
|
||||
obj->type = TFOBJ_TYPE_SYMBOL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/* Compare the two string objects 'a' and 'b', returns 0 if they are
|
||||
* the same, '1' if a > b , '-1' if a < b.
|
||||
* The comparison is performed using memcmp(). */
|
||||
int compareStringObject(tfobj *a, tfobj *b)
|
||||
{
|
||||
size_t minlen = a->str.len < b->str.len ? a->str.len : b->str.len;
|
||||
int cmp = memcmp(a->str.ptr, b->str.ptr, minlen);
|
||||
if (cmp == 0) {
|
||||
if (a->str.len == b->str.len) return 0;
|
||||
else if (a->str.len > b->str.len) return 1;
|
||||
else return -1;
|
||||
} else {
|
||||
if (cmp < 0) return -1;
|
||||
else return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ############################ List Object ############################################ */
|
||||
|
||||
tfobj *createListObject(void)
|
||||
{
|
||||
@@ -280,25 +305,88 @@ tfobj *compile(char *prg)
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/* ############################# Basic Standard Library ################################# */
|
||||
|
||||
void basicMathFunctions(tfctx *ctx, tfobj *name)
|
||||
{
|
||||
// TODO unimplemeted function
|
||||
/* if (ctxCheckStackMinLen(ctx, 2)) return; */
|
||||
/* tfobj *b = ctxStackPop(ctx, TFOBJ_TYPE_INT); */
|
||||
/* tfobj *a = ctxStackPop(ctx, TFOBJ_TYPE_INT); */
|
||||
/* if (a == NULL || b == NULL) return; */
|
||||
|
||||
/* int result = a->i + b->i; */
|
||||
/* ctxStackPush(ctx, createIntObject(result)); */
|
||||
}
|
||||
|
||||
/* ############################# Execution and context ################################## */
|
||||
|
||||
tffuncentry *getFunctionByName(tfctx *ctx, tfobj *name)
|
||||
{
|
||||
for (size_t j = 0; j < ctx->functable.func_count; j++) {
|
||||
tffuncentry *fe = ctx->functable.func_table[j];
|
||||
if (compareStringObject(fe->name, name) == 0)
|
||||
return fe;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Push a new function entry in the context. It's up to the caller
|
||||
* to set either the C callback or the list representing the user
|
||||
* defined function */
|
||||
tffuncentry *registerFunction(tfctx *ctx, tfobj *name)
|
||||
{
|
||||
ctx->functable.func_table = xrealloc(ctx->functable.func_table,
|
||||
sizeof(tffuncentry*) * ctx->functable.func_count + 1);
|
||||
tffuncentry *fe = xmalloc(sizeof(tffuncentry));
|
||||
ctx->functable.func_table[ctx->functable.func_count] = fe;
|
||||
ctx->functable.func_count++;
|
||||
fe->name = name;
|
||||
retain(name);
|
||||
fe->callback = NULL;
|
||||
fe->user_func = NULL;
|
||||
return fe;
|
||||
}
|
||||
|
||||
/* Register a new function with the given name in the function table
|
||||
* of the context. The function can't fail since if a function with the
|
||||
* same name already exist, it gets replaced by the new one. */
|
||||
void registerCFunction(tfctx *ctx, char *name, void (*callback)(tfctx *ctx, tfobj *name))
|
||||
{
|
||||
tffuncentry *fe;
|
||||
tfobj *oname = createStringObject(name, strlen(name));
|
||||
fe = getFunctionByName(ctx, oname);
|
||||
if (fe) {
|
||||
if (fe->user_func) {
|
||||
release(fe->user_func);
|
||||
fe->user_func = NULL;
|
||||
}
|
||||
fe->callback = callback;
|
||||
} else {
|
||||
fe = registerFunction(ctx, oname);
|
||||
fe->callback = callback;
|
||||
}
|
||||
release(oname);
|
||||
}
|
||||
|
||||
tfctx *createContext(void)
|
||||
{
|
||||
tfctx *ctx = xmalloc(sizeof(*ctx));
|
||||
ctx->stack = createListObject();
|
||||
ctx->functable.func_table = NULL;
|
||||
ctx->functable.func_count = 0;
|
||||
registerFunction(ctx, "+", basicMathFunctions);
|
||||
registerCFunction(ctx, "+", basicMathFunctions);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/* Try to resolve and call the function associated with the symbol
|
||||
* name 'word'. Return 0 if the symbol was actually bound to some
|
||||
* function, return 1 otherwise.
|
||||
* function and was executed, return 1 otherwise (on error).
|
||||
*/
|
||||
int callSymbol(tfctx *ctx, tfobj *word)
|
||||
{
|
||||
|
||||
tffuncentry *fe = getFunctionByName(ctx, word);
|
||||
if (fe == NULL) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user