many fixes using prelimtest

master
Ondřej Hruška 3 years ago
parent 883cc7faf1
commit 5da44313c5
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 1
      CMakeLists.txt
  2. 2
      include/fh_config.h
  3. 1
      include/fh_error.h
  4. 2
      include/fh_globals.h
  5. 1
      include/fh_mem.h
  6. 21
      include/fh_parse.h
  7. 10
      include/fh_runtime.h
  8. 2
      src/fh_builtins_arith.c
  9. 34
      src/fh_builtins_mem.c
  10. 91
      src/fh_builtins_meta.c
  11. 18
      src/fh_builtins_system.c
  12. 1
      src/fh_error.c
  13. 14
      src/fh_mem.c
  14. 143
      src/fh_parse.c
  15. 124
      src/fh_runtime.c
  16. 12
      src/main.c

@ -18,6 +18,7 @@ add_executable(forth
src/fh_mem.c
src/fh_error.c
src/fh_see.c
src/fh_parse.c
)
target_include_directories(forth PRIVATE include)

@ -13,7 +13,7 @@
#define HEAP_SIZE (1024*1024)
#define MAXLINE 65535
#define PAD_OFFSET 340 // why? copied from somewhere
#define WORDBUF_SIZE 128
#define WORDBUF_SIZE 256
#define INPUT_BUFFER_SIZE 256
#define CELL 4

@ -27,6 +27,7 @@ enum fh_error {
FH_ERR_ILLEGAL_STORE,
FH_ERR_DIV_BY_ZERO,
FH_ERR_SYNTAX,
FH_ERR_NOT_APPLICABLE,
FH_ERR_MAX,
};

@ -15,6 +15,8 @@ struct fh_global_s {
bool verbose;
/** Interactive mode (i.e. not started with a file argument) */
bool interactive;
/** Echo read lines in non-interactive mode */
bool echo;
};
extern struct fh_global_s fh_globals;

@ -29,6 +29,7 @@ enum fh_error fh_heap_reserve(
void fh_heap_write(struct fh_thread_s *fh, uint32_t addr, const void *src, uint32_t len);
enum fh_error fh_heap_put(struct fh_thread_s *fh, const void *src, uint32_t len);
void fh_heap_copy(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint32_t len);
void fh_heap_copyptr(struct fh_thread_s *fh, uint32_t addr, char * source, uint32_t len);
enum fh_error fh_put_instr(struct fh_thread_s *fh, enum fb_instruction_kind kind, uint32_t data);

@ -0,0 +1,21 @@
/**
* Parsing
*
* Created on 2021/11/17.
*/
#ifndef FORTH_FH_PARSE_H
#define FORTH_FH_PARSE_H
typedef bool (*chartest_t)(char c, void* param);
void fh_input_consume_matching(struct fh_thread_s *fh, chartest_t test, void* param);
void fh_input_consume_spaces(struct fh_thread_s *fh);
enum fh_error fh_input_read_delimited(struct fh_thread_s *fh, char **out, size_t *len, chartest_t test, void* param);
enum fh_error fh_input_read_word(struct fh_thread_s *fh, char **out, size_t *len);
enum fh_error fh_input_read_quotedstring(struct fh_thread_s *fh, bool escaped, char *outbuf, size_t capacity, size_t *out_len);
#endif //FORTH_FH_PARSE_H

@ -197,19 +197,17 @@ struct fh_thread_s {
#define INPUTBUF_ADDR (HEAP_END + WORDBUF_SIZE)
enum fh_error fh_loop_nest(struct fh_thread_s *fh, uint32_t indexvalue);
enum fh_error fh_loop_unnest(struct fh_thread_s *fh);
enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh);
void fh_setstate(struct fh_thread_s *fh, enum fh_state state, enum fh_substate substate);
void fh_setsubstate(struct fh_thread_s *fh, enum fh_substate substate);
enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w);
enum fh_error fh_input_read_quotedstring(struct fh_thread_s *fh, bool escaped, char *outbuf, size_t capacity, size_t *out_len);
enum fh_error fh_input_read_word(struct fh_thread_s *fh, char **out, size_t *len);
void fh_input_consume_spaces(struct fh_thread_s *fh);
enum fh_error fh_postpone_word(
struct fh_thread_s *fh,
const char *name,
@ -226,9 +224,11 @@ enum fh_error fh_see_word(
/* if the return address is this, we should drop back to interactive mode */
// SFR and magic addresses are "negative"
#define MAGICADDR_INTERACTIVE 0xFFFFFFFFULL
#define MAGICADDR_EXEC_INTERACTIVE 0xFFFFFFFFULL
#define MAGICADDR_BASE 0xFFFFBA5EULL
#define MAGICADDR_HERE 0xFFFF4E7EULL
#define MAGICADDR_INPTR 0xFFFFF111ULL
#define MAGICADDR_UNRESOLVED 0xFFFFFBADULL
/** Get a value rounded up to multiple of word size */

@ -90,7 +90,7 @@ static enum fh_error w_zero_less(struct fh_thread_s *fh, const struct fh_word_s
enum fh_error rv;
uint32_t a = 0;
TRY(ds_pop(fh, &a));
TRY(ds_push(fh, TOBOOL(a < 0)));
TRY(ds_push(fh, TOBOOL((int32_t)a < 0)));
return FH_OK;
}

@ -39,7 +39,7 @@ static enum fh_error w_plus_store(struct fh_thread_s *fh, const struct fh_word_s
uint32_t val = 0;
TRY(fh_fetch(fh, addr, &val));
uint32_t val2 = 0;
TRY(ds_pop(fh, &val));
TRY(ds_pop(fh, &val2));
TRY(fh_store(fh, addr, val2 + val));
return FH_OK;
@ -96,7 +96,7 @@ static enum fh_error w_allot(struct fh_thread_s *fh, const struct fh_word_s *w)
TRY(fh_heap_reserve(fh, ci, NULL));
} else {
LOG("Deallot %d", count);
fh->here = WORDALIGNED((uint32_t) (int32_t)fh->here + count);
fh->here = WORDALIGNED((uint32_t) (int32_t) fh->here + count);
}
return FH_OK;
}
@ -148,21 +148,21 @@ static enum fh_error w_here(struct fh_thread_s *fh, const struct fh_word_s *w)
}
const struct name_and_handler fh_builtins_mem[] = {
{"chars", wp_mul, 0, 1},
{"char+", wp_add, 0, 1},
{"cells", wp_mul, 0, CELL},
{"cell+", wp_add, 0, CELL},
{"@", w_fetch, 0, 0},
{"!", w_store, 0, 0},
{"+!", w_plus_store, 0, 0},
{"2!", w_two_store, 0, 0},
{"2@", w_two_fetch, 0, 0},
{"aligned", w_aligned, 0, 0},
{"allot", w_allot, 0, 0},
{"align", w_align, 0, 0},
{",", w_comma, 0, 0},
{"here", w_here, 0, 0},
{"pad", w_pad, 0, 0},
{"chars", wp_mul, 0, 1},
{"char+", wp_add, 0, 1},
{"cells", wp_mul, 0, CELL},
{"cell+", wp_add, 0, CELL},
{"@", w_fetch, 0, 0},
{"!", w_store, 0, 0},
{"+!", w_plus_store, 0, 0},
{"2!", w_two_store, 0, 0},
{"2@", w_two_fetch, 0, 0},
{"aligned", w_aligned, 0, 0},
{"allot", w_allot, 0, 0},
{"align", w_align, 0, 0},
{",", w_comma, 0, 0},
{"here", w_here, 0, 0},
{"pad", w_pad, 0, 0},
{ /* end marker */ }
};

@ -5,6 +5,7 @@
#include "fh_stack.h"
#include "fh_print.h"
#include "fh_builtins.h"
#include "fh_parse.h"
static enum fh_error w_colon(struct fh_thread_s *fh, const struct fh_word_s *w)
{
@ -179,6 +180,17 @@ static enum fh_error w_rightbracket(struct fh_thread_s *fh, const struct fh_word
return FH_OK;
}
static enum fh_error w_source(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, INPUTBUF_ADDR));
TRY(ds_push(fh, fh->inputlen));
// TRY(ds_push(fh, INPUTBUF_ADDR + fh->inputptr));
// TRY(ds_push(fh, fh->inputlen - fh->inputptr));
return FH_OK;
}
static enum fh_error w_literal(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
@ -251,7 +263,83 @@ static enum fh_error w_char(struct fh_thread_s *fh, const struct fh_word_s *w)
return FH_OK;
}
static enum fh_error w_depth(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, fh->data_stack_top));
return FH_OK;
}
static enum fh_error w_unused(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, HEAP_SIZE - fh->here));
return FH_OK;
}
static enum fh_error w_to_in(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, MAGICADDR_INPTR));
return FH_OK;
}
static bool chartest_equals_or_end(char c, void *param)
{
char cc = (char) *(uint32_t *) param;
return c == cc || c == 0;
}
static enum fh_error w_word(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
uint32_t ch;
TRY(ds_pop(fh, &ch));
if (ch > 0xFF) {
LOGE("Char out of ASCII bounds!");
return FH_ERR_NOT_APPLICABLE;
}
fh_input_consume_matching(fh, chartest_equals_or_end, &ch);
char *out;
size_t len;
fh_input_read_delimited(fh, &out, &len, chartest_equals_or_end, &ch);
if (len >= WORDBUF_SIZE) {
LOGE("WORD parsed string too long");
return FH_ERR_NAME_TOO_LONG;
}
fh_store_char(fh, WORDBUF_ADDR, (char) len);
fh_heap_copyptr(fh, WORDBUF_ADDR + 1, out, len);
TRY(ds_push(fh, WORDBUF_ADDR));
return FH_OK;
}
static enum fh_error w_count(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
uint32_t caddr;
TRY(ds_pop(fh, &caddr));
uint8_t len;
TRY(fh_fetch_char(fh, caddr, (char*)&len));
TRY(ds_push(fh, caddr + 1));
TRY(ds_push(fh, len));
return FH_OK;
}
const struct name_and_handler fh_builtins_meta[] = {
{"depth", w_depth, 0, 0},
{"unused", w_unused, 0, 0},
{">in", w_to_in, 0, 0},
{":", w_colon, 0, 0},
{";", w_semicolon, 1, 0},
{"forget", w_forget, 1, 0},
@ -261,6 +349,7 @@ const struct name_and_handler fh_builtins_meta[] = {
{"postpone", w_postpone, 1, 0},
{"[", w_leftbracket, 1, 0},
{"]", w_rightbracket, 1, 0},
{"source", w_source, 0, 0},
{"literal", w_literal, 1, 0},
{"char", w_char, 0, 0},
{"[char]", w_char, 1, 0},
@ -268,6 +357,8 @@ const struct name_and_handler fh_builtins_meta[] = {
{"variable", wp_variable, 1, 0},
{"value", wp_variable, 1, 1},
{"constant", wp_variable, 1, 2},
{"word", w_word, 0, 0},
{"count", w_count, 0, 0},
{ /* end marker */ }
};

@ -6,22 +6,6 @@
#include "fh_print.h"
#include "fh_builtins.h"
static enum fh_error w_depth(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, fh->data_stack_top));
return FH_OK;
}
static enum fh_error w_unused(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
enum fh_error rv;
TRY(ds_push(fh, HEAP_SIZE - fh->here));
return FH_OK;
}
// extension
static enum fh_error w_reset(struct fh_thread_s *fh, const struct fh_word_s *w)
{
@ -52,8 +36,6 @@ static enum fh_error w_debug(struct fh_thread_s *fh, const struct fh_word_s *w)
}
const struct name_and_handler fh_builtins_system[] = {
{"depth", w_depth, 0, 0},
{"unused", w_unused, 0, 0},
{"reset", w_reset, 1, 0},
{"bye", w_bye, 0, 0},
{"debug", w_debug, 0, 0},

@ -20,6 +20,7 @@ static const char *errornames[FH_ERR_MAX] = {
[FH_ERR_ILLEGAL_STORE] = "ILLEGAL_STORE",
[FH_ERR_DIV_BY_ZERO] = "DIV_BY_ZERO",
[FH_ERR_SYNTAX] = "SYNTAX_ERROR",
[FH_ERR_NOT_APPLICABLE] = "NOT_APPLICABLE",
};
/** Get error name from code, returns Unknown if not defined */

@ -39,6 +39,10 @@ enum fh_error fh_fetch(struct fh_thread_s *fh, uint32_t addr, uint32_t *dst)
*dst = fh->here;
break;
case MAGICADDR_INPTR:
*dst = fh->inputptr;
break;
default:
if (addr & 3) {
LOGE("Address 0x%08x is not aligned!", addr);
@ -78,6 +82,10 @@ enum fh_error fh_store(struct fh_thread_s *fh, uint32_t addr, uint32_t val)
LOGE("HERE is read-only!");
return FH_ERR_ILLEGAL_STORE;
case MAGICADDR_INPTR:
fh->inputptr = val;
break;
default:
if (addr & 3) {
LOGE("Address 0x%08x is not aligned!", addr);
@ -166,6 +174,12 @@ void fh_heap_copy(struct fh_thread_s *fh, uint32_t addr, uint32_t srcaddr, uint3
memcpy(&fh->heap[addr], &fh->heap[srcaddr], len);
}
/** Copy bytes from anywhere to heap. The region must have been previously allocated! */
void fh_heap_copyptr(struct fh_thread_s *fh, uint32_t addr, char * source, uint32_t len)
{
memcpy(&fh->heap[addr], source, len);
}
char *fh_str_at(struct fh_thread_s *fh, uint32_t addr) {
if (addr >= HEAP_SIZE) {

@ -0,0 +1,143 @@
#include <ctype.h>
#include <stdint.h>
#include <stddef.h>
#include "fh_print.h"
#include "fh_runtime.h"
#include "fh_error.h"
#include "fh_parse.h"
void fh_input_consume_matching(struct fh_thread_s *fh, chartest_t test, void* param) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
while (test(*rp, param)) {
rp++;
fh->inputptr++;
}
}
void fh_input_consume_spaces(struct fh_thread_s *fh) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
while (isspace(*rp)) {
rp++;
fh->inputptr++;
}
}
enum fh_error fh_input_read_delimited(struct fh_thread_s *fh, char **out, size_t *len, chartest_t test, void* param)
{
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
char *start = rp;
while (1) {
char c = *rp;
if (test(c, param)) {
if (rp == start) {
LOGE("Expected a word!");
return FH_ERR_SYNTAX;
}
*out = start;
*len = rp - start;
fh->inputptr++; // advance past the delimiter
return FH_OK;
}
rp++;
fh->inputptr++;
}
}
static bool chartest_space_or_end(char c, void *param)
{
(void)param;
return isspace(c) || c == 0;
}
enum fh_error fh_input_read_word(struct fh_thread_s *fh, char **out, size_t *len) {
return fh_input_read_delimited(fh, out, len, chartest_space_or_end, NULL);
}
enum fh_error fh_input_read_quotedstring(struct fh_thread_s *fh, bool escaped, char *outbuf, size_t capacity, size_t *out_len) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
bool next_escaped = false;
size_t remains = capacity;
size_t len = 0;
int hexdigits = 0;
uint32_t hex = 0;
while (len < capacity) {
char c = *rp;
if (c == 0) {
LOGE("Unterminated quoted string!");
return FH_ERR_SYNTAX;
}
if (hexdigits) {
hex <<= 4;
if (isdigit(c)) {
hex |= c - '0';
} else if (c>='a' && c<='f') {
hex |= c - 'a';
} else if (c>='A' && c<='F') {
hex |= c - 'A';
} else {
LOGE("Bad hex escape");
return FH_ERR_SYNTAX;
}
hexdigits--;
if (hexdigits == 0) {
c = (char) hex;
goto append;
}
}
if (!escaped || !next_escaped) {
if (c == '\"') {
*outbuf = 0;
*out_len = len;
// advance past the quote
fh->inputptr++;
return FH_OK;
}
if (c == '\\') {
next_escaped = true;
goto skip;
}
} else {
next_escaped = false;
switch (c) {
case 'a': c = 7; break;
case 'b': c = 8; break;
case 'e': c = 27; break;
case 'f': c = 12; break;
case 'l': c = 10; break;
case 'm':
case 'n':
if (remains < 2) goto full;
*outbuf++ = '\r';
*outbuf++ = '\n';
remains -= 2;
len += 2;
goto skip;
case 'q': c = '"'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
case 'z': c = 0; break; // XXX this will cause problems!
case 'x':
hex = 0;
hexdigits = 2;
goto skip;
default:;
// just append normally
}
}
append:
*outbuf++ = c;
len++;
skip:
rp++;
fh->inputptr++;
}
full:
LOGE("String too long!");
return FH_ERR_SYNTAX;
}

@ -28,122 +28,6 @@ static const char *substatenames[FH_SUBSTATE_MAX] = {
[FH_SUBSTATE_EXIT] = "EXIT",
};
void fh_input_consume_spaces(struct fh_thread_s *fh) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
while (isspace(*rp)) {
rp++;
fh->inputptr++;
}
}
enum fh_error fh_input_read_word(struct fh_thread_s *fh, char **out, size_t *len) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
char *start = rp;
while (1) {
char c = *rp;
if (isspace(c) || c == 0) {
if (rp == start) {
LOGE("Expected a word!");
return FH_ERR_SYNTAX;
}
*out = start;
*len = rp - start;
return FH_OK;
}
rp++;
fh->inputptr++;
}
}
enum fh_error fh_input_read_quotedstring(struct fh_thread_s *fh, bool escaped, char *outbuf, size_t capacity, size_t *out_len) {
char *rp = (char *) &fh->heap[INPUTBUF_ADDR + fh->inputptr];
bool next_escaped = false;
size_t remains = capacity;
size_t len = 0;
int hexdigits = 0;
uint32_t hex = 0;
while (len < capacity) {
char c = *rp;
if (c == 0) {
LOGE("Unterminated quoted string!");
return FH_ERR_SYNTAX;
}
if (hexdigits) {
hex <<= 4;
if (isdigit(c)) {
hex |= c - '0';
} else if (c>='a' && c<='f') {
hex |= c - 'a';
} else if (c>='A' && c<='F') {
hex |= c - 'A';
} else {
LOGE("Bad hex escape");
return FH_ERR_SYNTAX;
}
hexdigits--;
if (hexdigits == 0) {
c = (char) hex;
goto append;
}
}
if (!escaped || !next_escaped) {
if (c == '\"') {
*outbuf = 0;
*out_len = len;
// advance past the quote
fh->inputptr++;
return FH_OK;
}
if (c == '\\') {
next_escaped = true;
goto skip;
}
} else {
next_escaped = false;
switch (c) {
case 'a': c = 7; break;
case 'b': c = 8; break;
case 'e': c = 27; break;
case 'f': c = 12; break;
case 'l': c = 10; break;
case 'm':
case 'n':
if (remains < 2) goto full;
*outbuf++ = '\r';
*outbuf++ = '\n';
remains -= 2;
len += 2;
goto skip;
case 'q': c = '"'; break;
case 'r': c = '\r'; break;
case 't': c = '\t'; break;
case 'v': c = '\v'; break;
case 'z': c = 0; break; // XXX this will cause problems!
case 'x':
hex = 0;
hexdigits = 2;
goto skip;
default:;
// just append normally
}
}
append:
*outbuf++ = c;
len++;
skip:
rp++;
fh->inputptr++;
}
full:
LOGE("String too long!");
return FH_ERR_SYNTAX;
}
/** Add a word to the dictionary. */
enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh)
{
@ -250,7 +134,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0)
fh_setsubstate(fh, 0);
LOG("Exec: early return");
TRY(rs_pop(fh, &fh->execptr));
if (fh->execptr == MAGICADDR_INTERACTIVE) {
if (fh->execptr == MAGICADDR_EXEC_INTERACTIVE) {
goto end;
}
}
@ -373,7 +257,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0)
case FH_INSTR_ENDWORD:
LOG("Exec: word-end (RETURN)");
TRY(rs_pop(fh, &fh->execptr));
if (fh->execptr == MAGICADDR_INTERACTIVE) {
if (fh->execptr == MAGICADDR_EXEC_INTERACTIVE) {
goto end;
}
goto instr;
@ -395,7 +279,7 @@ enum fh_error fh_init(struct fh_thread_s *fh)
fh->dict_last = MAGICADDR_DICTFIRST;
TRY(register_builtin_words(fh));
fh->execptr = MAGICADDR_INTERACTIVE;
fh->execptr = MAGICADDR_EXEC_INTERACTIVE;
fh->base = 10;
return FH_OK;
}
@ -545,7 +429,7 @@ enum fh_error fh_process_line(struct fh_thread_s *fh, const char *linebuf, size_
char c;
if (!fh_globals.interactive) {
if (fh_globals.echo && !fh_globals.interactive) {
LOGI("%s", linebuf);
}

@ -12,6 +12,7 @@ int main(int argc, char *argv[])
{
fh_globals.verbose = false;
fh_globals.interactive = isatty(STDIN_FILENO);
fh_globals.echo = 0;
FILE *infile = stdin;
@ -26,6 +27,9 @@ int main(int argc, char *argv[])
case 'v':
fh_globals.verbose = 1;
break;
case 'e':
fh_globals.echo = 1;
break;
default:
LOGE("Unknown flag: %c", c);
return 1;
@ -70,7 +74,9 @@ int main(int argc, char *argv[])
rv = fh_process_line(&fh, linebuf, strlen(linebuf));
if (rv == FH_OK) {
FHPRINT_SVC(" ok\n");
if (fh_globals.interactive || fh_globals.echo) {
FHPRINT_SVC(" ok\n");
}
} else {
LOGE("ERROR %s on line %d", fherr_name(rv), linecnt);
if (!fh_globals.interactive) {
@ -83,7 +89,9 @@ int main(int argc, char *argv[])
fh.return_stack_top = 0;
}
FHPRINT("%s", prompt);
if (fh_globals.interactive) {
FHPRINT("%s", prompt);
}
}
// Show resource usage

Loading…
Cancel
Save