From 7461069855882fb1953fdcb8646802934d89e6f2 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Mon, 8 Dec 2025 00:31:13 +0100 Subject: [PATCH] Added basic functionality for interpreter platform functions --- toyforth.c | 140 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 114 insertions(+), 26 deletions(-) diff --git a/toyforth.c b/toyforth.c index 0cd4230..bde52c9 100644 --- a/toyforth.c +++ b/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; }