misc/kforth: Fix a bunch of bugs from part 0x08.

This commit is contained in:
Kyle Isom 2018-03-09 13:07:23 -08:00
parent 960587baa3
commit cf3a0f426c
4 changed files with 93 additions and 11 deletions

View File

@ -1,7 +1,7 @@
Write You a Forth, 0x08 Write You a Forth, 0x08
----------------------- -----------------------
:date: 2018-03-01 19:31 :date: 2018-03-05 21:42
:tags: wyaf, forth :tags: wyaf, forth
After reading some more in Threaded Interpreted Languages (TIL_ from now on), 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__ */ #endif /* __KF_WORD_H__ */
The codeword is the big changer here. I've put a native evaluator and 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__ #ifndef __KF_EVAL_H__
#define __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. ``nexec`` just casts its target to a void function and calls it.
::
void void
nexec(uintptr_t target) 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 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. case of native execution, this is a pointer to a function.
::
void void
cwexec(uintptr_t entry) 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:: up a word by name and execute it::
void 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); store_native(dict+last, name, len, target);
} }
@ -341,6 +345,41 @@ up a word by name and execute it::
} }
} }
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 void
store_native(uint8_t *entry, const char *name, const uint8_t len, void(*target)(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)); 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 bool
match_word(uint8_t *entry, const char *name, const uint8_t len) match_word(uint8_t *entry, const char *name, const uint8_t len)
{ {
@ -372,6 +414,10 @@ up a word by name and execute it::
return true; 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 size_t
word_link(uint8_t *entry) word_link(uint8_t *entry)
{ {
@ -390,3 +436,6 @@ up a word by name and execute it::
return 2 + entry[0] + sizeof(size_t); 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.

16
kf.c
View File

@ -4,6 +4,7 @@
#include "word.h" #include "word.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
void void
@ -18,11 +19,18 @@ main(void)
dstack_push(2); dstack_push(2);
dstack_push(3); dstack_push(3);
uint8_t arena[128] = {0}; append_native_word("hello", 5, hello);
uintptr_t arena_p = (uintptr_t)arena; uintptr_t hwb = 0;
store_native(arena, "hello", 5, hello);
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"); printf("finished\n");
} }

30
word.c
View File

@ -8,7 +8,7 @@ static uint8_t dict[DICT_SIZE] = {0};
static size_t last = 0; static size_t last = 0;
void 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); 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 void
store_native(uint8_t *entry, const char *name, const uint8_t len, void(*target)(void)) store_native(uint8_t *entry, const char *name, const uint8_t len, void(*target)(void))
{ {
uintptr_t target_p = (uintptr_t)target; 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 */ /* write the header */
entry[0] = len; 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)); memcpy(entry+2+len, &link, sizeof(link));
/* write the native executor codeword and the function pointer */ /* write the native executor codeword and the function pointer */
memcpy(entry, (uint8_t *)(&nexec_p), sizeof(uintptr_t)); memcpy(entry+offset, (uint8_t *)(&nexec_p), sizeof(uintptr_t));
memcpy(entry + sizeof(uintptr_t), (uint8_t *)(&target_p), sizeof(uintptr_t)); offset += sizeof(uintptr_t);
memcpy(entry+offset, (uint8_t *)(&target_p), sizeof(uintptr_t));
} }
bool bool

3
word.h
View File

@ -19,6 +19,9 @@
* The body of a native word points to a function that's compiled in already. * 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 * store_native writes a new dictionary entry for a native-compiled