diff --git a/doc/part-0x08.rst b/doc/part-0x08.rst index 633175b..1f7c748 100644 --- a/doc/part-0x08.rst +++ b/doc/part-0x08.rst @@ -1,7 +1,7 @@ Write You a Forth, 0x08 ----------------------- -:date: 2018-03-01 19:31 +:date: 2018-03-05 21:42 :tags: wyaf, forth After reading some more in Threaded Interpreted Languages (TIL_ from now on), @@ -199,7 +199,7 @@ Reading TIL has given me some new ideas on how to implement words:: #endif /* __KF_WORD_H__ */ The codeword is the big changer here. I've put a native evaluator and -a codeword executor in the ``eval`` files: +a codeword executor in the ``eval`` files:: #ifndef __KF_EVAL_H__ #define __KF_EVAL_H__ @@ -238,6 +238,8 @@ The implementations of these are short:: ``nexec`` just casts its target to a void function and calls it. +:: + void nexec(uintptr_t target) { @@ -248,6 +250,8 @@ The implementations of these are short:: is the executor, and the next is the start of the code body. In the case of native execution, this is a pointer to a function. +:: + void cwexec(uintptr_t entry) { @@ -317,7 +321,7 @@ adds a new word to the dictionary, and the second attempts to look up a word by name and execute it:: void - append_word(const char *name, const uint8_t len, void(*target)(void)) + append_native_word(const char *name, const uint8_t len, void(*target)(void)) { store_native(dict+last, name, len, target); } @@ -340,7 +344,42 @@ up a word by name and execute it:: return true; } } + +Actually, now that I think about it, maybe I should also add in a function +to return a uintptr_t to the word, too. Should this point to the header or +to the body? My first instinct is to point to the header and have the caller +(me) use ``word_body`` to get the actual body. That being said, however, +we already have the useful information from the header (namely, the name and +length); the link is only useful for the search phase. Following this logic +means that ``lookup`` will return a pointer to the body. So say we all:: + bool + lookup(const char *name, const uint8_t len, uintptr_t *ptr) + { + size_t offset = 0; + size_t body = 0; + while (true) { + if (!match_word(dict+offset, name, len)) { + if ((offset = word_link(dict+offset)) == 0) { + return false; + } + continue; + } + + body = word_body(dict+offset); + *ptr = (uintptr_t)(dict + offset + body); + return true; + } + + } + +The rest of the functions in the header (all of which are publicly +visible) are made available for use later. Maybe (but let's be honest, +probably not) I'll go back later and make these functions private. + +The first such function stores a native (built-in) word. This is what +``append_native_word`` is built around:: + void store_native(uint8_t *entry, const char *name, const uint8_t len, void(*target)(void)) { @@ -358,6 +397,9 @@ up a word by name and execute it:: memcpy(entry + sizeof(uintptr_t), (uint8_t *)(&target_p), sizeof(uintptr_t)); } +The rest of the functions are utility functions. ``match_word`` is used +to... match words:: + bool match_word(uint8_t *entry, const char *name, const uint8_t len) { @@ -371,6 +413,10 @@ up a word by name and execute it:: return true; } + +Finally, ``word_link`` returns the offset to the next function (e.g. so +as to be able to do ``entry+offset``) and ``word_body`` returns the offset +to the body of the word:: size_t word_link(uint8_t *entry) @@ -390,3 +436,6 @@ up a word by name and execute it:: return 2 + entry[0] + sizeof(size_t); } + +That about wraps up this chunk of work. Next to maybe start porting builtins? I +also need to rewrite the parser and I/O layer. diff --git a/kf.c b/kf.c index dcc1cbc..4a58962 100644 --- a/kf.c +++ b/kf.c @@ -4,6 +4,7 @@ #include "word.h" #include +#include #include void @@ -18,11 +19,18 @@ main(void) dstack_push(2); dstack_push(3); - uint8_t arena[128] = {0}; - uintptr_t arena_p = (uintptr_t)arena; - store_native(arena, "hello", 5, hello); + append_native_word("hello", 5, hello); + uintptr_t hwb = 0; - cwexec(arena_p); + if (!lookup("hello", 5, &hwb)) { + fprintf(stderr, "failed to lookup 'hello'\n"); + exit(1); + } + printf("hello: 0x%lx\n", (unsigned long)hwb); + if (!execute("hello", 5)) { + fprintf(stderr, "failed to execute 'hello'\n"); + exit(1); + } printf("finished\n"); } diff --git a/word.c b/word.c index 8afd3f3..4f11732 100644 --- a/word.c +++ b/word.c @@ -8,7 +8,7 @@ static uint8_t dict[DICT_SIZE] = {0}; static size_t last = 0; void -append_word(const char *name, const uint8_t len, void(*target)(void)) +append_native_word(const char *name, const uint8_t len, void(*target)(void)) { store_native(dict+last, name, len, target); } @@ -32,11 +32,32 @@ execute(const char *name, const uint8_t len) } } +bool +lookup(const char *name, const uint8_t len, uintptr_t *ptr) +{ + size_t offset = 0; + size_t body = 0; + while (true) { + if (!match_word(dict+offset, name, len)) { + if ((offset = word_link(dict+offset)) == 0) { + return false; + } + continue; + } + + body = word_body(dict+offset); + *ptr = (uintptr_t)(dict + offset + body); + return true; + } + +} + void store_native(uint8_t *entry, const char *name, const uint8_t len, void(*target)(void)) { uintptr_t target_p = (uintptr_t)target; - size_t link = 2 + len + (2 * sizeof(uintptr_t)); + size_t offset = 2 + len + sizeof(size_t); + size_t link = offset + (2 * sizeof(uintptr_t)); /* write the header */ entry[0] = len; @@ -45,8 +66,9 @@ store_native(uint8_t *entry, const char *name, const uint8_t len, void(*target)( memcpy(entry+2+len, &link, sizeof(link)); /* write the native executor codeword and the function pointer */ - memcpy(entry, (uint8_t *)(&nexec_p), sizeof(uintptr_t)); - memcpy(entry + sizeof(uintptr_t), (uint8_t *)(&target_p), sizeof(uintptr_t)); + memcpy(entry+offset, (uint8_t *)(&nexec_p), sizeof(uintptr_t)); + offset += sizeof(uintptr_t); + memcpy(entry+offset, (uint8_t *)(&target_p), sizeof(uintptr_t)); } bool diff --git a/word.h b/word.h index fbc5c80..6d69733 100644 --- a/word.h +++ b/word.h @@ -19,6 +19,9 @@ * The body of a native word points to a function that's compiled in already. */ +void append_native_word(const char *, const uint8_t, void(*)(void)); +bool execute(const char *, const uint8_t); +bool lookup(const char *, const uint8_t, uintptr_t *); /* * store_native writes a new dictionary entry for a native-compiled