misc/kforth: Add system status, work on vocab, better write_num.
- Now system structure includes a status variable and an associated function for writing the status out. - Adding more words to the builtin dictionary. - write_num round 3. - Include option to not print the stack each iteration.
This commit is contained in:
parent
3b284b7c08
commit
6a49675314
7
Makefile
7
Makefile
|
@ -1,7 +1,9 @@
|
||||||
CXXSTD := c++14
|
CXXSTD := c++14
|
||||||
CXXFLAGS := -std=$(CXXSTD) -Wall -Werror -g -O0
|
CXXFLAGS := -std=$(CXXSTD) -Wall -Werror -Os -static
|
||||||
|
LDFLAGS := -static
|
||||||
OBJS := linux/io.o \
|
OBJS := linux/io.o \
|
||||||
io.o \
|
io.o \
|
||||||
|
system.o \
|
||||||
parser.o \
|
parser.o \
|
||||||
word.o \
|
word.o \
|
||||||
dict.o \
|
dict.o \
|
||||||
|
@ -11,7 +13,8 @@ TARGET := kforth
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
$(TARGET): $(OBJS)
|
$(TARGET): $(OBJS)
|
||||||
$(CXX) $(CFLAGS) -o $@ $(OBJS)
|
$(CXX) $(CXXFLAGS) -o $@ $(OBJS)
|
||||||
|
strip $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJS) $(TARGET)
|
rm -f $(OBJS) $(TARGET)
|
||||||
|
|
1
defs.h
1
defs.h
|
@ -5,6 +5,7 @@
|
||||||
#include "linux/defs.h"
|
#include "linux/defs.h"
|
||||||
#else
|
#else
|
||||||
typedef int KF_INT;
|
typedef int KF_INT;
|
||||||
|
typedef long KF_LONG;
|
||||||
constexpr uint8_t STACK_SIZE = 16;
|
constexpr uint8_t STACK_SIZE = 16;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
9
dict.h
9
dict.h
|
@ -6,14 +6,9 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "word.h"
|
#include "word.h"
|
||||||
|
|
||||||
typedef enum _LOOKUP_ : uint8_t {
|
|
||||||
LOOKUP_OK = 0, // Lookup executed properly.
|
|
||||||
LOOKUP_NOTFOUND = 1, // The token isn't in the dictionary.
|
|
||||||
LOOKUP_FAILED = 2 // The word failed to execute.
|
|
||||||
} LOOKUP;
|
|
||||||
|
|
||||||
void init_dict(System *);
|
void init_dict(System *);
|
||||||
LOOKUP lookup(struct Token *, System *);
|
void reset_system(System *);
|
||||||
|
bool lookup(struct Token *, System *);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
Write You a Forth, 0x05
|
Write You a Forth, 0x05
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
:date: 2018-02-24 12:23
|
:date: 2018-02-27 08:06
|
||||||
:tags: wyaf, forth
|
:tags: wyaf, forth
|
||||||
|
|
||||||
NB: Today's update was pretty large, so I don't show all of the code; this is
|
NB: Today's update was pretty large, so I don't show all of the code; this is
|
||||||
|
|
42
io.cc
42
io.cc
|
@ -8,21 +8,12 @@ static constexpr size_t nbuflen = 11;
|
||||||
void
|
void
|
||||||
write_num(IO *interface, KF_INT n)
|
write_num(IO *interface, KF_INT n)
|
||||||
{
|
{
|
||||||
|
|
||||||
// TODO(kyle): make the size of the buffer depend on the size of
|
|
||||||
// KF_INT.
|
|
||||||
char buf[nbuflen];
|
char buf[nbuflen];
|
||||||
uint8_t i = nbuflen;
|
uint8_t i = nbuflen - 1;
|
||||||
memset(buf, 0, i);
|
memset(buf, 0, nbuflen);
|
||||||
bool neg = n < 0;
|
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
interface->wrch('-');
|
interface->wrch('-');
|
||||||
n = ~n;
|
|
||||||
if (n == 0) {
|
|
||||||
neg = false;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (n == 0) {
|
else if (n == 0) {
|
||||||
interface->wrch('0');
|
interface->wrch('0');
|
||||||
|
@ -30,13 +21,28 @@ write_num(IO *interface, KF_INT n)
|
||||||
}
|
}
|
||||||
|
|
||||||
while (n != 0) {
|
while (n != 0) {
|
||||||
char ch = (n % 10) + '0';
|
char x = n % 10;
|
||||||
if (neg && (i == nbuflen)) ch++;
|
x = x < 0 ? -x : x;
|
||||||
buf[i-1] = ch;
|
x += '0';
|
||||||
i--;
|
buf[i--] = x;
|
||||||
n /= 10;
|
n /= 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t buflen = nbuflen - i % nbuflen;
|
interface->wrbuf(buf+i, nbuflen - i);
|
||||||
interface->wrbuf(buf+i, buflen);
|
}
|
||||||
}
|
|
||||||
|
void
|
||||||
|
write_dstack(IO *interface, Stack<KF_INT> dstack)
|
||||||
|
{
|
||||||
|
KF_INT tmp;
|
||||||
|
interface->wrch('<');
|
||||||
|
for (size_t i = 0; i < dstack.size(); i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
interface->wrch(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
dstack.get(i, tmp);
|
||||||
|
write_num(interface, tmp);
|
||||||
|
}
|
||||||
|
interface->wrch('>');
|
||||||
|
}
|
||||||
|
|
4
io.h
4
io.h
|
@ -2,6 +2,7 @@
|
||||||
#define __KF_IO_H__
|
#define __KF_IO_H__
|
||||||
|
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
|
#include "stack.h"
|
||||||
|
|
||||||
class IO {
|
class IO {
|
||||||
public:
|
public:
|
||||||
|
@ -19,9 +20,12 @@ public:
|
||||||
// Line I/O
|
// Line I/O
|
||||||
virtual bool rdln(char *buf, size_t len, size_t *readlen) = 0;
|
virtual bool rdln(char *buf, size_t len, size_t *readlen) = 0;
|
||||||
virtual void wrln(char *buf, size_t len) = 0;
|
virtual void wrln(char *buf, size_t len) = 0;
|
||||||
|
|
||||||
|
virtual void newline(void) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void write_num(IO *, KF_INT);
|
void write_num(IO *, KF_INT);
|
||||||
|
void write_dstack(IO *, Stack<KF_INT>);
|
||||||
|
|
||||||
|
|
||||||
#endif // __KF_IO_H__
|
#endif // __KF_IO_H__
|
59
kforth.cc
59
kforth.cc
|
@ -10,25 +10,10 @@
|
||||||
#include "linux.h"
|
#include "linux.h"
|
||||||
#endif // __linux__
|
#endif // __linux__
|
||||||
|
|
||||||
static char ok[] = "ok.\n";
|
|
||||||
static System sys;
|
static System sys;
|
||||||
|
#ifndef TRACE_STACK
|
||||||
|
#define TRACE_STACK false
|
||||||
static void
|
#endif
|
||||||
write_dstack()
|
|
||||||
{
|
|
||||||
KF_INT tmp;
|
|
||||||
sys.interface->wrch('<');
|
|
||||||
for (size_t i = 0; i < sys.dstack.size(); i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
sys.interface->wrch(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
sys.dstack.get(i, tmp);
|
|
||||||
write_num(sys.interface, tmp);
|
|
||||||
}
|
|
||||||
sys.interface->wrch('>');
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parser(const char *buf, const size_t buflen)
|
parser(const char *buf, const size_t buflen)
|
||||||
|
@ -36,8 +21,6 @@ parser(const char *buf, const size_t buflen)
|
||||||
static size_t offset = 0;
|
static size_t offset = 0;
|
||||||
static struct Token token;
|
static struct Token token;
|
||||||
static PARSE_RESULT result = PARSE_FAIL;
|
static PARSE_RESULT result = PARSE_FAIL;
|
||||||
static LOOKUP lresult = LOOKUP_FAILED;
|
|
||||||
static bool stop = false;
|
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
|
@ -46,34 +29,17 @@ parser(const char *buf, const size_t buflen)
|
||||||
token.length = 0;
|
token.length = 0;
|
||||||
|
|
||||||
while ((result = parse_next(buf, buflen, &offset, &token)) == PARSE_OK) {
|
while ((result = parse_next(buf, buflen, &offset, &token)) == PARSE_OK) {
|
||||||
lresult = lookup(&token, &sys);
|
if (!lookup(&token, &sys)) {
|
||||||
switch (lresult) {
|
|
||||||
case LOOKUP_OK:
|
|
||||||
continue;
|
|
||||||
case LOOKUP_NOTFOUND:
|
|
||||||
sys.interface->wrln((char *)"word not found", 15);
|
|
||||||
stop = true;
|
|
||||||
break;
|
|
||||||
case LOOKUP_FAILED:
|
|
||||||
sys.interface->wrln((char *)"execution failed", 17);
|
|
||||||
stop = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
sys.interface->wrln((char *)"*** the world is broken ***", 27);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stop) {
|
|
||||||
stop = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
system_write_status(&sys);
|
||||||
|
sys.interface->newline();
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case PARSE_OK:
|
case PARSE_OK:
|
||||||
return false;
|
return false;
|
||||||
case PARSE_EOB:
|
case PARSE_EOB:
|
||||||
sys.interface->wrbuf(ok, 4);
|
|
||||||
return true;
|
return true;
|
||||||
case PARSE_LEN:
|
case PARSE_LEN:
|
||||||
sys.interface->wrln((char *)"parse error: token too long", 27);
|
sys.interface->wrln((char *)"parse error: token too long", 27);
|
||||||
|
@ -94,8 +60,10 @@ interpreter()
|
||||||
static char linebuf[81];
|
static char linebuf[81];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
write_dstack();
|
if (TRACE_STACK) {
|
||||||
sys.interface->wrch('\n');
|
write_dstack(sys.interface, sys.dstack);
|
||||||
|
sys.interface->newline();
|
||||||
|
}
|
||||||
sys.interface->wrch('?');
|
sys.interface->wrch('?');
|
||||||
sys.interface->wrch(' ');
|
sys.interface->wrch(' ');
|
||||||
buflen = sys.interface->rdbuf(linebuf, 80, true, '\n');
|
buflen = sys.interface->rdbuf(linebuf, 80, true, '\n');
|
||||||
|
@ -103,18 +71,19 @@ interpreter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char banner[] = "kforth interpreter\n";
|
static char banner[] = "kforth interpreter";
|
||||||
const size_t bannerlen = 19;
|
const size_t bannerlen = 18;
|
||||||
|
|
||||||
int
|
int
|
||||||
main(void)
|
main(void)
|
||||||
{
|
{
|
||||||
|
reset_system(&sys);
|
||||||
init_dict(&sys);
|
init_dict(&sys);
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
Console interface;
|
Console interface;
|
||||||
sys.interface = &interface;
|
sys.interface = &interface;
|
||||||
#endif
|
#endif
|
||||||
sys.interface->wrbuf(banner, bannerlen);
|
sys.interface->wrln(banner, bannerlen);
|
||||||
interpreter();
|
interpreter();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -5,6 +5,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef int32_t KF_INT;
|
typedef int32_t KF_INT;
|
||||||
|
typedef int64_t KF_LONG;
|
||||||
|
|
||||||
constexpr uint8_t STACK_SIZE = 128;
|
constexpr uint8_t STACK_SIZE = 128;
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -17,6 +17,8 @@ public:
|
||||||
// Line I/O
|
// Line I/O
|
||||||
bool rdln(char *buf, size_t len, size_t *readlen);
|
bool rdln(char *buf, size_t len, size_t *readlen);
|
||||||
void wrln(char *buf, size_t len);
|
void wrln(char *buf, size_t len);
|
||||||
|
|
||||||
|
void newline(void) { this->wrch('\n'); };
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void
|
static inline void
|
||||||
reset(struct Token *t)
|
reset(struct Token *t)
|
||||||
{
|
{
|
||||||
t->token = nullptr;
|
t->token = nullptr;
|
||||||
|
@ -48,9 +48,7 @@ parse_next(const char *buf, const size_t length, size_t *offset,
|
||||||
{
|
{
|
||||||
size_t cursor = *offset;
|
size_t cursor = *offset;
|
||||||
|
|
||||||
// Clear the token.
|
|
||||||
reset(token);
|
reset(token);
|
||||||
|
|
||||||
if (cursor == length) {
|
if (cursor == length) {
|
||||||
return PARSE_EOB;
|
return PARSE_EOB;
|
||||||
}
|
}
|
||||||
|
|
18
stack.h
18
stack.h
|
@ -9,6 +9,7 @@ public:
|
||||||
bool push(T val);
|
bool push(T val);
|
||||||
bool pop(T *val);
|
bool pop(T *val);
|
||||||
bool get(size_t, T &);
|
bool get(size_t, T &);
|
||||||
|
bool remove(size_t, T *);
|
||||||
size_t size(void) { return this->arrlen; }
|
size_t size(void) { return this->arrlen; }
|
||||||
void clear(void) { this->arrlen = 0; }
|
void clear(void) { this->arrlen = 0; }
|
||||||
private:
|
private:
|
||||||
|
@ -56,4 +57,21 @@ Stack<T>::get(size_t i, T &val)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove returns false on invalid bounds
|
||||||
|
template <typename T>
|
||||||
|
bool
|
||||||
|
Stack<T>::remove(size_t i, T *val)
|
||||||
|
{
|
||||||
|
if (i > this->arrlen) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*val = this->arr[i];
|
||||||
|
for (; i < (arrlen - 1); i++) {
|
||||||
|
this->arr[i] = this->arr[i+1];
|
||||||
|
}
|
||||||
|
arrlen--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // __KF_STACK_H__
|
#endif // __KF_STACK_H__
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include "defs.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
constexpr static char STATE_STR_OK[] = "ok";
|
||||||
|
constexpr static char STATE_STR_STACK_OVERFLOW[] = "stack overflow";
|
||||||
|
constexpr static char STATE_STR_STACK_UNDERFLOW[] = "stack underflow";
|
||||||
|
constexpr static char STATE_STR_EXECUTION_FAILURE[] = "execution failure";
|
||||||
|
constexpr static char STATE_STR_UNKNOWN_WORD[] = "unknown word";
|
||||||
|
constexpr static char STATE_STR_UNKNOWN_STATE[] = "undefined state";
|
||||||
|
constexpr static char STATE_STR_ERROR_CODE[] = " (error code ";
|
||||||
|
|
||||||
|
void
|
||||||
|
system_clear_error(System *sys)
|
||||||
|
{
|
||||||
|
sys->status = STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
system_write_status(System *sys)
|
||||||
|
{
|
||||||
|
char *buf = nullptr;
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
if (sys->interface == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sys->status) {
|
||||||
|
case STATUS_OK:
|
||||||
|
buf = (char *)(STATE_STR_OK);
|
||||||
|
len = sizeof STATE_STR_OK;
|
||||||
|
break;
|
||||||
|
case STATUS_STACK_OVERFLOW:
|
||||||
|
buf = (char *)(STATE_STR_STACK_OVERFLOW);
|
||||||
|
len = sizeof STATE_STR_STACK_OVERFLOW;
|
||||||
|
break;
|
||||||
|
case STATUS_STACK_UNDERFLOW:
|
||||||
|
buf = (char *)(STATE_STR_STACK_UNDERFLOW);
|
||||||
|
len = sizeof STATE_STR_STACK_UNDERFLOW;
|
||||||
|
break;
|
||||||
|
case STATUS_EXECUTION_FAILURE:
|
||||||
|
buf = (char *)(STATE_STR_EXECUTION_FAILURE);
|
||||||
|
len = sizeof STATE_STR_EXECUTION_FAILURE;
|
||||||
|
break;
|
||||||
|
case STATUS_UNKNOWN_WORD:
|
||||||
|
buf = (char *)(STATE_STR_UNKNOWN_WORD);
|
||||||
|
len = sizeof STATE_STR_UNKNOWN_WORD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
buf = (char *)(STATE_STR_UNKNOWN_STATE);
|
||||||
|
len = sizeof STATE_STR_UNKNOWN_STATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys->interface->wrbuf(buf, len);
|
||||||
|
if (sys->status != STATUS_OK) {
|
||||||
|
sys->interface->wrbuf((char *)STATE_STR_ERROR_CODE, sizeof STATE_STR_ERROR_CODE);
|
||||||
|
write_num(sys->interface, (KF_INT)sys->status);
|
||||||
|
sys->interface->wrch(')');
|
||||||
|
}
|
||||||
|
sys->interface->wrch('.');
|
||||||
|
}
|
15
system.h
15
system.h
|
@ -5,11 +5,24 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "stack.h"
|
#include "stack.h"
|
||||||
|
|
||||||
|
typedef enum _SYS_STATUS : uint8_t {
|
||||||
|
STATUS_OK = 0,
|
||||||
|
STATUS_STACK_OVERFLOW = 1,
|
||||||
|
STATUS_STACK_UNDERFLOW = 2,
|
||||||
|
STATUS_EXECUTION_FAILURE = 3,
|
||||||
|
STATUS_UNKNOWN_WORD = 4
|
||||||
|
} SYS_STATUS;
|
||||||
|
|
||||||
|
class Word;
|
||||||
|
|
||||||
typedef struct _System {
|
typedef struct _System {
|
||||||
Stack<KF_INT> dstack;
|
Stack<KF_INT> dstack;
|
||||||
IO *interface;
|
IO *interface;
|
||||||
struct Word *dict;
|
Word *dict;
|
||||||
|
SYS_STATUS status;
|
||||||
} System;
|
} System;
|
||||||
|
|
||||||
|
void system_clear_error(System *sys);
|
||||||
|
void system_write_status(System *sys);
|
||||||
|
|
||||||
#endif // __KF_CORE_H__
|
#endif // __KF_CORE_H__
|
Loading…
Reference in New Issue