Added primitive functions [WIP]

This commit is contained in:
Fabio Scotto di Santolo
2025-12-01 19:38:12 +01:00
parent c85b1987e0
commit 95b5d3b97b
2 changed files with 132 additions and 23 deletions

View File

@@ -1 +1 @@
5 10 20 + print 5 10 + dup * print

View File

@@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <assert.h>
#define TFOBJ_TYPE_INT 0 #define TFOBJ_TYPE_INT 0
#define TFOBJ_TYPE_STR 1 #define TFOBJ_TYPE_STR 1
@@ -10,6 +11,7 @@
#define TFOBJ_TYPE_SYMBOL 4 #define TFOBJ_TYPE_SYMBOL 4
/* ############################# Data Structures ########################################## */ /* ############################# Data Structures ########################################## */
typedef struct tfobj { typedef struct tfobj {
int refcount; int refcount;
int type; // TFOBJ_TYPE_* int type; // TFOBJ_TYPE_*
@@ -18,6 +20,7 @@ typedef struct tfobj {
struct { struct {
char *ptr; char *ptr;
size_t len; size_t len;
int quoted;
} str; } str;
struct { struct {
struct tfobj **ele; struct tfobj **ele;
@@ -31,8 +34,24 @@ typedef struct tfparser {
char *p; // Next token to parse. char *p; // Next token to parse.
} tfparser; } tfparser;
/* Function table entry: each of this entry represents a symbol name
* associated with a function implementation.
*/
struct FunctionTableEntry {
tfobj *name;
void (*callback) (tfctx *ctx, tfobj *name);
tfobj *user_list;
};
struct FunctionTable {
struct FunctionTableEntry **func_table;
size_t func_count;
};
/* Our execution context. */
typedef struct tfctx { typedef struct tfctx {
tfobj *stack; tfobj *stack;
struct FunctionTable functable;
} tfctx; } tfctx;
/* ############################# Allocations wrappers ################################### */ /* ############################# Allocations wrappers ################################### */
@@ -47,6 +66,16 @@ void *xmalloc(size_t size)
return ptr; return ptr;
} }
void *xrealloc(void *oldptr, size_t size)
{
void *ptr = realloc(oldptr, size);
if (ptr == NULL) {
fprintf(stderr, "Out of memory allocating %zu bytes", size);
exit(1);
}
return ptr;
}
/* ######################### Object related functions ################################### /* ######################### Object related functions ###################################
* The following functions allocate Toy Forth objects of different types. * The following functions allocate Toy Forth objects of different types.
*/ */
@@ -91,6 +120,64 @@ tfobj *createSymbolObject(char *s, size_t len)
return obj; return obj;
} }
/* Free an object and all the other nested objects. */
void freeObject(tfobj *obj) {
switch (obj->type) {
case TFOBJ_TYPE_LIST:
for (size_t j = 0; j < obj->list.len; j++) {
tfobj *ele = obj->list.ele[j];
release(ele);
}
break;
case TFOBJ_TYPE_SYMBOL:
case TFOBJ_TYPE_STR:
free(obj->str.ptr);
break;
}
free(obj);
}
void retain(tfobj *obj)
{
obj->refcount++;
}
void release(tfobj *obj)
{
assert(obj->refcount > 0);
obj->refcount--;
if (obj->refcount == 0)
freeObject(obj);
}
void printObject(tfobj *obj) {
switch (obj->type) {
case TFOBJ_TYPE_INT:
printf("%d", obj->i);
break;
case TFOBJ_TYPE_LIST:
printf("[");
for (size_t j = 0; j < obj->list.len; j++) {
tfobj *o = obj->list.ele[j];
printObject(o);
if (j != o->list.len-1)
printf(" ");
}
printf("]");
break;
case TFOBJ_TYPE_STR:
printf("\"%s\"", obj->str.ptr);
break;
case TFOBJ_TYPE_SYMBOL:
printf("%s", obj->str.ptr);
break;
default:
printf("?");
break;
}
}
/* ############################ List Object ############################################ */ /* ############################ List Object ############################################ */
tfobj *createListObject(void) tfobj *createListObject(void)
@@ -106,7 +193,7 @@ tfobj *createListObject(void)
* element added to the list, if needed. */ * element added to the list, if needed. */
void listPush(tfobj *l, tfobj *ele) void listPush(tfobj *l, tfobj *ele)
{ {
l->list.ele = realloc(l->list.ele, sizeof(tfobj*) * (l->list.len+1)); l->list.ele = xrealloc(l->list.ele, sizeof(tfobj*) * (l->list.len+1));
l->list.ele[l->list.len] = ele; l->list.ele[l->list.len] = ele;
l->list.len++; l->list.len++;
} }
@@ -182,7 +269,7 @@ tfobj *compile(char *prg)
// Check if the current token produced a parsing error. // Check if the current token produced a parsing error.
if (obj == NULL) { if (obj == NULL) {
// FIXME: release parsed here. release(parsed);
printf("Syntax error near: %32s ...\n", token_start); printf("Syntax error near: %32s ...\n", token_start);
return NULL; return NULL;
} else { } else {
@@ -193,28 +280,42 @@ tfobj *compile(char *prg)
return parsed; return parsed;
} }
/* ############################ Execute the program ##################################### */ /* ############################# Execution and context ################################## */
void printObject(tfobj *obj) { tfctx *createContext(void)
switch (obj->type) { {
case TFOBJ_TYPE_INT: tfctx *ctx = xmalloc(sizeof(*ctx));
printf("%d", obj->i); ctx->stack = createListObject();
break; ctx->functable.func_table = NULL;
case TFOBJ_TYPE_LIST: ctx->functable.func_count = 0;
printf("["); registerFunction(ctx, "+", basicMathFunctions);
for (size_t j = 0; j < obj->list.len; j++) { return ctx;
tfobj *o = obj->list.ele[j]; }
printObject(o);
printf(" "); /* 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.
*/
int callSymbol(tfctx *ctx, tfobj *word)
{
return 0;
}
/* Execute the Toy Forth program stored into the list 'prg'. */
void exec(tfctx *ctx, tfobj *prg) {
assert(prg->type == TFOBJ_TYPE_LIST);
for (size_t j = 0; j < prg->list.len; j++) {
tfobj *word = prg->list.ele[j];
switch (word->type) {
case TFOBJ_TYPE_SYMBOL:
callSymbol(ctx, word);
break;
default:
listPush(ctx->stack, word);
retain(word);
break;
} }
printf("]");
break;
case TFOBJ_TYPE_SYMBOL:
printf("'%s", obj->str.ptr);
break;
default:
printf("?");
break;
} }
} }
@@ -246,6 +347,14 @@ int main(int argc, char **argv)
tfobj *prg = compile(prgtext); tfobj *prg = compile(prgtext);
printObject(prg); printObject(prg);
printf("\n");
tfctx *ctx = createContext();
exec(ctx, prg);
printf("Stack content at end: ");
printObject(ctx->stack);
printf("\n");
return 0; return 0;
} }