diff --git a/program.tf b/program.tf index 5607a69..1026987 100644 --- a/program.tf +++ b/program.tf @@ -1 +1 @@ -5 10 20 + print +5 10 + dup * print diff --git a/toyforth.c b/toyforth.c index 70801c9..0cd4230 100644 --- a/toyforth.c +++ b/toyforth.c @@ -2,6 +2,7 @@ #include #include #include +#include #define TFOBJ_TYPE_INT 0 #define TFOBJ_TYPE_STR 1 @@ -10,6 +11,7 @@ #define TFOBJ_TYPE_SYMBOL 4 /* ############################# Data Structures ########################################## */ + typedef struct tfobj { int refcount; int type; // TFOBJ_TYPE_* @@ -18,6 +20,7 @@ typedef struct tfobj { struct { char *ptr; size_t len; + int quoted; } str; struct { struct tfobj **ele; @@ -31,8 +34,24 @@ typedef struct tfparser { char *p; // Next token to parse. } 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 { tfobj *stack; + struct FunctionTable functable; } tfctx; /* ############################# Allocations wrappers ################################### */ @@ -47,6 +66,16 @@ void *xmalloc(size_t size) 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 ################################### * The following functions allocate Toy Forth objects of different types. */ @@ -91,6 +120,64 @@ tfobj *createSymbolObject(char *s, size_t len) 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 ############################################ */ tfobj *createListObject(void) @@ -106,7 +193,7 @@ tfobj *createListObject(void) * element added to the list, if needed. */ 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.len++; } @@ -182,7 +269,7 @@ tfobj *compile(char *prg) // Check if the current token produced a parsing error. if (obj == NULL) { - // FIXME: release parsed here. + release(parsed); printf("Syntax error near: %32s ...\n", token_start); return NULL; } else { @@ -193,28 +280,42 @@ tfobj *compile(char *prg) return parsed; } -/* ############################ Execute the program ##################################### */ +/* ############################# Execution and context ################################## */ -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); - printf(" "); +tfctx *createContext(void) +{ + tfctx *ctx = xmalloc(sizeof(*ctx)); + ctx->stack = createListObject(); + ctx->functable.func_table = NULL; + ctx->functable.func_count = 0; + registerFunction(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. + */ +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); printObject(prg); + printf("\n"); + + tfctx *ctx = createContext(); + exec(ctx, prg); + + printf("Stack content at end: "); + printObject(ctx->stack); + printf("\n"); return 0; }