misc/kforth: Restart the world.
This commit is contained in:
parent
a1149654d4
commit
7a2ed45857
29
Makefile
29
Makefile
|
@ -1,23 +1,28 @@
|
|||
CXXSTD := c++14
|
||||
CXXFLAGS := -std=$(CXXSTD) -Wall -Werror -O0 -g
|
||||
PLATFORM ?= default
|
||||
CSTD := c99
|
||||
CFLAGS ?= -std=$(CSTD) -Wall -Werror -O0 -g -DPLATFORM_$(PLATFORM)
|
||||
LDFLAGS := -static
|
||||
OBJS := linux/io.o \
|
||||
io.o \
|
||||
system.o \
|
||||
parser.o \
|
||||
OBJS := stack.o \
|
||||
eval.o \
|
||||
word.o \
|
||||
dict.o \
|
||||
kforth.o
|
||||
TARGET := kforth
|
||||
kf.o
|
||||
TARGET := kf-$(PLATFORM)
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(TARGET)
|
||||
clean-objs:
|
||||
rm -f $(OBJS)
|
||||
|
||||
clean: clean-objs
|
||||
rm -f kf-pc kf-default
|
||||
|
||||
install: $(TARGET)
|
||||
cp $(TARGET) ~/bin
|
||||
chmod 0755 ~/bin/$(TARGET)
|
||||
|
||||
cross:
|
||||
make PLATFORM=default clean-objs all
|
||||
make PLATFORM=pc clean-objs all
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
#ifndef __KF_PLATFORM_DEFAULT_H__
|
||||
#define __KF_PLATFORM_DEFAULT_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef __KF_DEFAULT_DEFS_H__
|
||||
#define __KF_DEFAULT_DEFS_H__
|
||||
|
||||
typedef int KF_INT;
|
||||
typedef uintptr_t KF_ADDR;
|
||||
|
||||
constexpr static size_t STACK_SIZE = 48 / sizeof(KF_INT);
|
||||
constexpr static size_t DICT_SIZE = 4096;
|
||||
constexpr static size_t ARENA_SIZE = 256;
|
||||
static const size_t DSTACK_SIZE = 12;
|
||||
static const size_t RSTACK_SIZE = 12;
|
||||
static const size_t DICT_SIZE = 4096;
|
||||
|
||||
#endif /* __KF_DEFAULT_DEFS_H__ */
|
||||
|
||||
#endif // __KF_PLATFORM_DEFAULT_H__
|
7
defs.h
7
defs.h
|
@ -1,12 +1,15 @@
|
|||
#ifndef __KF_DEFS_H__
|
||||
#define __KF_DEFS_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if PLATFORM == PC
|
||||
#ifdef PLATFORM_pc
|
||||
#include "pc/defs.h"
|
||||
#else
|
||||
#include "default/defs.h"
|
||||
#endif
|
||||
|
||||
|
||||
#endif __KF_DEFS_H__
|
||||
#endif /* __KF_DEFS_H__ */
|
||||
|
|
|
@ -16,3 +16,17 @@ Some design choices that didn't really work out:
|
|||
+ my linked list approach to the dictionary
|
||||
+ my class-based approach to words
|
||||
|
||||
I get the distinct feeling that I could (maybe should) be doing this in C99, so
|
||||
I think I'll switch to that.
|
||||
|
||||
The new design
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
I'll need to provide a few initial pieces:
|
||||
|
||||
1. eval.c
|
||||
2. stack.c
|
||||
3. the platform parts
|
||||
|
||||
I'll skip the parser at first and hand hack some things, then try to
|
||||
port over my I/O layer from before.
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
#include "defs.h"
|
||||
#include "eval.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
cwexec(uintptr_t entry)
|
||||
{
|
||||
uintptr_t target = 0;
|
||||
uintptr_t codeword = 0;
|
||||
|
||||
memcpy(&codeword, (void *)entry, sizeof(uintptr_t));
|
||||
memcpy(&target, (void *)(entry + sizeof(uintptr_t)), sizeof(uintptr_t));
|
||||
((void(*)(uintptr_t))codeword)(target);
|
||||
}
|
||||
|
||||
void
|
||||
nexec(uintptr_t target)
|
||||
{
|
||||
((void(*)(void))target)();
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef __KF_EVAL_H__
|
||||
#define __KF_EVAL_H__
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
/*
|
||||
* cwexec is the codeword executor. It assumes that the uintptr_t
|
||||
* passed into it points to the correct executor (e.g. nexec),
|
||||
* which is called with the next address.
|
||||
*/
|
||||
void cwexec(uintptr_t);
|
||||
|
||||
|
||||
/*
|
||||
* nexec is the native executor.
|
||||
*
|
||||
* It should take a uintptr_t containing the address of a code block
|
||||
* and will execute the function starting there. The function should
|
||||
* half the signature void(*target)(void) - a function returning
|
||||
* nothing and taking no arguments.
|
||||
*/
|
||||
void nexec(uintptr_t);
|
||||
|
||||
static const uintptr_t nexec_p = (uintptr_t)&nexec;
|
||||
|
||||
|
||||
#endif /* __KF_EVAL_H__ */
|
|
@ -0,0 +1,28 @@
|
|||
#include "defs.h"
|
||||
#include "eval.h"
|
||||
#include "stack.h"
|
||||
#include "word.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
hello(void)
|
||||
{
|
||||
printf("hello, world\n");
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
dstack_push(2);
|
||||
dstack_push(3);
|
||||
|
||||
uint8_t arena[128] = {0};
|
||||
uintptr_t arena_p = (uintptr_t)arena;
|
||||
store_native(arena, hello);
|
||||
|
||||
cwexec(arena_p);
|
||||
|
||||
printf("finished\n");
|
||||
}
|
15
pc/defs.h
15
pc/defs.h
|
@ -1,14 +1,11 @@
|
|||
#ifndef __KF_PLATFORM_PC_H__
|
||||
#define __KF_PLATFORM_PC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef __KF_PC_DEFS_H__
|
||||
#define __KF_PC_DEFS_H__
|
||||
|
||||
typedef int32_t KF_INT;
|
||||
typedef uintptr_t KF_ADDR;
|
||||
|
||||
constexpr static size_t STACK_SIZE = 65535;
|
||||
constexpr static size_t DICT_SIZE = 65535;
|
||||
constexpr static size_t ARENA_SIZE = 65535;
|
||||
static const size_t DSTACK_SIZE = 65535;
|
||||
static const size_t RSTACK_SIZE = 65535;
|
||||
static const size_t DICT_SIZE = 65535;
|
||||
|
||||
|
||||
#endif // __KF_PLATFORM_PC_H__
|
||||
#endif /* __KF_PC_DEFS_H__ */
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
#include "defs.h"
|
||||
#include "stack.h"
|
||||
|
||||
static KF_INT dstack[DSTACK_SIZE] = {0};
|
||||
static size_t dstack_len = 0;
|
||||
|
||||
bool
|
||||
dstack_pop(KF_INT *a)
|
||||
{
|
||||
if (dstack_len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*a = dstack[--dstack_len];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
dstack_push(KF_INT a)
|
||||
{
|
||||
if (dstack_len == DSTACK_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dstack[dstack_len++] = a;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
dstack_get(size_t i, KF_INT *a)
|
||||
{
|
||||
if (i >= dstack_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*a = dstack[dstack_len - i - 1];
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
dstack_size()
|
||||
{
|
||||
return dstack_len;
|
||||
}
|
||||
|
||||
void
|
||||
dstack_clear()
|
||||
{
|
||||
dstack_len = 0;
|
||||
}
|
||||
|
||||
static KF_ADDR rstack[RSTACK_SIZE] = {0};
|
||||
static size_t rstack_len = 0;
|
||||
|
||||
bool
|
||||
rstack_pop(KF_ADDR *a)
|
||||
{
|
||||
if (rstack_len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*a = rstack[--rstack_len];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
rstack_push(KF_ADDR a)
|
||||
{
|
||||
if (rstack_len == DSTACK_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rstack[rstack_len++] = a;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
rstack_get(size_t i, KF_ADDR *a)
|
||||
{
|
||||
if (i >= rstack_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*a = rstack[rstack_len - i - 1];
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
rstack_size()
|
||||
{
|
||||
return rstack_len;
|
||||
}
|
||||
|
||||
void
|
||||
rstack_clear()
|
||||
{
|
||||
rstack_len = 0;
|
||||
}
|
17
stack.h
17
stack.h
|
@ -1,9 +1,18 @@
|
|||
#ifndef __KF_STACK_H__
|
||||
#define __KF_STACK_H__
|
||||
|
||||
/* data stack interaction */
|
||||
bool dstack_pop(KF_INT *);
|
||||
bool dstack_push(KF_INT);
|
||||
bool dstack_get(size_t, KF_INT *);
|
||||
size_t dstack_size(void);
|
||||
void dstack_clear(void);
|
||||
|
||||
/* return stack interaction */
|
||||
bool rstack_pop(KF_ADDR *);
|
||||
bool rstack_push(KF_ADDR);
|
||||
bool rstack_get(size_t, KF_ADDR *);
|
||||
size_t rstack_size(void);
|
||||
void rstack_clear(void);
|
||||
|
||||
static
|
||||
|
||||
|
||||
#endif // __KF_STACK_H__
|
||||
#endif /* __KF_STACK_H__ */
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
#include "defs.h"
|
||||
#include "eval.h"
|
||||
#include "word.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
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))
|
||||
{
|
||||
store_native(dict+last, name, len, target);
|
||||
}
|
||||
|
||||
bool
|
||||
execute(const char *name, const uint8_t len)
|
||||
{
|
||||
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);
|
||||
cwexec(dict + body + offset);
|
||||
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));
|
||||
|
||||
/* write the header */
|
||||
entry[0] = len;
|
||||
entry[1] = 0; // flags aren't used yet
|
||||
memcpy(entry+2, name, len);
|
||||
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));
|
||||
}
|
||||
|
||||
bool
|
||||
match_word(uint8_t *entry, const char *name, const uint8_t len)
|
||||
{
|
||||
if (entry[0] != len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(entry+2, name, len) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
word_link(uint8_t *entry)
|
||||
{
|
||||
size_t link;
|
||||
|
||||
if (entry[0] == 0) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(&link, entry+2+entry[0], sizeof(link));
|
||||
return link;
|
||||
}
|
||||
|
||||
size_t
|
||||
word_body(uint8_t *entry)
|
||||
{
|
||||
return 2 + entry[0] + sizeof(size_t);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef __KF_WORD_H__
|
||||
#define __KF_WORD_H__
|
||||
|
||||
/*
|
||||
* Every word in the dictionary starts with a header:
|
||||
* uint8_t length;
|
||||
* uint8_t flags;
|
||||
* char *name;
|
||||
* uintptr_t next;
|
||||
*
|
||||
* The body looks like the following:
|
||||
* uintptr_t codeword;
|
||||
* uintptr_t body[];
|
||||
*
|
||||
* The codeword is the interpreter for the body. This is defined in
|
||||
* eval.c. Note that a native (or builtin function) has only a single
|
||||
* body element.
|
||||
*
|
||||
* The body of a native word points to a function that's compiled in already.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* store_native writes a new dictionary entry for a native-compiled
|
||||
* function.
|
||||
*/
|
||||
void store_native(uint8_t *, const char *, const uint8_t, void(*)(void));
|
||||
|
||||
/*
|
||||
* match_word returns true if the current dictionary entry matches the
|
||||
* token being searched for.
|
||||
*/
|
||||
bool match_word(uint8_t *, const char *, const uint8_t);
|
||||
|
||||
/*
|
||||
* word_link returns the offset to the next word.
|
||||
*/
|
||||
size_t word_link(uint8_t *);
|
||||
|
||||
size_t word_body(uint8_t *);
|
||||
|
||||
#endif /* __KF_WORD_H__ */
|
Loading…
Reference in New Issue