#include #include #include #include #define TFOBJ_TYPE_INT 0 #define TFOBJ_TYPE_STR 1 #define TFOBJ_TYPE_BOOL 2 #define TFOBJ_TYPE_LIST 3 #define TFOBJ_TYPE_SYMBOL 4 /* ############################# Data Structures ########################################## */ typedef struct tfobj { int refcount; int type; // TFOBJ_TYPE_* union { int i; struct { char *ptr; size_t len; } str; struct { struct tfobj **ele; size_t len; } list; }; } tfobj; typedef struct tfparser { char *prg; // The program to compile into a list. char *p; // Next token to parse. } tfparser; typedef struct tfctx { tfobj *stack; } tfctx; /* ############################# Allocations wrappers ################################### */ void *xmalloc(size_t size) { void *ptr = malloc(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. */ /*Allocate and initialize a new Toy Forth object. */ tfobj *createObject(int type) { tfobj *o = xmalloc(sizeof(tfobj)); o->type = type; o->refcount = 1; return o; } tfobj *createStringObject(char *s, size_t len) { tfobj *obj = createObject(TFOBJ_TYPE_STR); obj->str.ptr = s; obj->str.len = len; return obj; } tfobj *createIntObject(int i) { tfobj *obj = createObject(TFOBJ_TYPE_INT); obj->i = i; return obj; } tfobj *createBoolObject(int b) { tfobj *obj = createObject(TFOBJ_TYPE_BOOL); obj->i = b; return obj; } tfobj *createSymbolObject(char *s, size_t len) { tfobj *obj = createStringObject(s, len); obj->type = TFOBJ_TYPE_SYMBOL; return obj; } /* ############################ List Object ############################################ */ tfobj *createListObject(void) { tfobj *obj = createObject(TFOBJ_TYPE_LIST); obj->list.ele = NULL; obj->list.len = 0; return obj; } /* Add the new element at the end of the 'list'. * It is up to the caller to increment the reference count of the * 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[l->list.len] = ele; l->list.len++; } /* ####################### Turn program into toy forth list ############################ */ void parseSpaces(tfparser *parser) { while (isspace(parser->p[0])) parser->p++; } #define MAX_NUM_LEN 128 tfobj *parseNumber(tfparser *parser) { char buf[MAX_NUM_LEN]; char *start = parser->p; char *end; if (parser->p[0] == '-') parser->p++; while (parser->p[0] && isdigit(parser->p[0])) parser->p++; end = parser->p; int numLen = end - start; if (numLen >= MAX_NUM_LEN) return NULL; memcpy(buf, start, numLen); buf[numLen] = 0; tfobj *obj = createIntObject(atoi(buf)); return obj; } tfobj *compile(char *prg) { tfparser parser; parser.prg = prg; parser.p = prg; tfobj *parsed = createListObject(); while (parser.p) { tfobj *obj; char *token_start = parser.p; parseSpaces(&parser); if (parser.p[0] == 0) break; // End of program reached. if (isdigit(parser.p[0]) || parser.p[0] == '-') { obj = parseNumber(&parser); } else { obj = NULL; } // Check if the current token produced a parsing error. if (obj == NULL) { // FIXME: release parsed here. printf("Syntax error near: %32s ...\n", token_start); return NULL; } else { listPush(parsed, obj); } } return parsed; } /* ############################ Execute the program ##################################### */ void exec(tfobj *obj) { // TODO: unimplmented function for (size_t j = 0; j < obj->list.len; j++) { tfobj *o = obj->list.ele[j]; switch (o->type) { case TFOBJ_TYPE_INT: printf("%d", o->i); break; default: printf("?"); break; } printf(" "); } printf("\n"); } /* ############################### Main ################################################# */ int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } // Read the program in memory, for later parsing. FILE *fp = fopen(argv[1], "r"); if (fp == NULL) { perror("Opening Toy Forth program"); return 1; } fseek(fp, 0, SEEK_END); long file_size = ftell(fp); char *prgtext = xmalloc(file_size+1); fseek(fp, 0, SEEK_SET); fread(prgtext, file_size, 1, fp); prgtext[file_size] = 0; fclose(fp); //printf("Program text: \"%s\"\n", prgtext); tfobj *prg = compile(prgtext); exec(prg); return 0; }