refactor: make interpreter portable with static pools and I/O hooks
Co-authored-by: aider (openrouter/moonshotai/kimi-k2.6) <aider@aider.chat>
This commit is contained in:
@@ -7,7 +7,6 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
// Configuration (all hard limits removed)
|
// Configuration (all hard limits removed)
|
||||||
#define MAX_NAME_LEN 31
|
#define MAX_NAME_LEN 31
|
||||||
@@ -88,8 +87,11 @@ void inner_interpreter(void);
|
|||||||
void process_token(const char* token);
|
void process_token(const char* token);
|
||||||
void outer_interpreter(void);
|
void outer_interpreter(void);
|
||||||
|
|
||||||
// Ensure compile_buf has at least 'needed' free cells
|
// Ensure compile_buf has at least 'needed' free cells (returns 0 on overflow)
|
||||||
void ensure_compile_cap(int32_t needed);
|
int ensure_compile_cap(int32_t needed);
|
||||||
|
|
||||||
|
Word* forth_alloc_word(void);
|
||||||
|
Cell* forth_alloc_body(int32_t cells);
|
||||||
|
|
||||||
// Stack ops
|
// Stack ops
|
||||||
void do_dup(Word* w);
|
void do_dup(Word* w);
|
||||||
|
|||||||
+58
-53
@@ -1,34 +1,38 @@
|
|||||||
#include "forth.h"
|
#include "forth.h"
|
||||||
|
|
||||||
// Dynamic storage
|
// Static storage for bare-metal portability
|
||||||
int64_t *data_stack = NULL;
|
static int64_t data_stack_storage[FORTH_DATA_STACK_SIZE];
|
||||||
|
int64_t *data_stack = data_stack_storage;
|
||||||
int32_t data_sp = -1;
|
int32_t data_sp = -1;
|
||||||
int32_t data_cap = 0;
|
int32_t data_cap = FORTH_DATA_STACK_SIZE;
|
||||||
|
|
||||||
Cell *ret_stack = NULL;
|
static Cell ret_stack_storage[FORTH_RET_STACK_SIZE];
|
||||||
|
Cell *ret_stack = ret_stack_storage;
|
||||||
int32_t rp = -1;
|
int32_t rp = -1;
|
||||||
int32_t ret_cap = 0;
|
int32_t ret_cap = FORTH_RET_STACK_SIZE;
|
||||||
Cell* ip = NULL;
|
Cell* ip = NULL;
|
||||||
|
|
||||||
Word* dict_head = NULL;
|
Word* dict_head = NULL;
|
||||||
|
|
||||||
int state = 0;
|
static Cell compile_buf_storage[FORTH_COMPILE_BUF_SIZE];
|
||||||
Cell *compile_buf = NULL;
|
Cell *compile_buf = compile_buf_storage;
|
||||||
int32_t compile_idx = 0;
|
int32_t compile_idx = 0;
|
||||||
int32_t compile_cap = 0;
|
int32_t compile_cap = FORTH_COMPILE_BUF_SIZE;
|
||||||
char compiling_name[MAX_NAME_LEN + 1] = {0};
|
char compiling_name[MAX_NAME_LEN + 1] = {0};
|
||||||
|
|
||||||
char* input_buf = NULL;
|
char* input_buf = NULL;
|
||||||
size_t input_buf_cap = 0;
|
size_t input_buf_cap = 0;
|
||||||
char* input_ptr = NULL;
|
char* input_ptr = NULL;
|
||||||
|
|
||||||
int64_t *compile_stack = NULL;
|
static int64_t compile_stack_storage[FORTH_COMPILE_STACK_SIZE];
|
||||||
|
int64_t *compile_stack = compile_stack_storage;
|
||||||
int32_t compile_sp = -1;
|
int32_t compile_sp = -1;
|
||||||
int32_t compile_stack_cap = 0;
|
int32_t compile_stack_cap = FORTH_COMPILE_STACK_SIZE;
|
||||||
|
|
||||||
Cell *user_mem = NULL;
|
static Cell user_mem_storage[FORTH_USER_MEM_CELLS];
|
||||||
int64_t user_mem_size = 0;
|
Cell *user_mem = user_mem_storage;
|
||||||
Cell* here = NULL;
|
int64_t user_mem_size = FORTH_USER_MEM_CELLS;
|
||||||
|
Cell* here = user_mem_storage;
|
||||||
|
|
||||||
Word* w_exit = NULL;
|
Word* w_exit = NULL;
|
||||||
Word* w_docolon = NULL;
|
Word* w_docolon = NULL;
|
||||||
@@ -37,17 +41,35 @@ Word* w_branch = NULL;
|
|||||||
Word* w_zbranch = NULL;
|
Word* w_zbranch = NULL;
|
||||||
Word* w_dot_quote_inner = NULL;
|
Word* w_dot_quote_inner = NULL;
|
||||||
|
|
||||||
|
static Word word_pool[FORTH_MAX_WORDS];
|
||||||
|
static int32_t word_pool_used = 0;
|
||||||
|
|
||||||
|
static Cell word_body_storage[FORTH_MAX_WORD_BODY_CELLS];
|
||||||
|
static int32_t word_body_used = 0;
|
||||||
|
|
||||||
|
Word* forth_alloc_word(void) {
|
||||||
|
if (word_pool_used >= FORTH_MAX_WORDS) {
|
||||||
|
forth_printf("Dictionary full\n");
|
||||||
|
forth_panic();
|
||||||
|
}
|
||||||
|
return &word_pool[word_pool_used++];
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell* forth_alloc_body(int32_t cells) {
|
||||||
|
if (word_body_used + cells > FORTH_MAX_WORD_BODY_CELLS) {
|
||||||
|
forth_printf("Word body pool exhausted\n");
|
||||||
|
forth_panic();
|
||||||
|
}
|
||||||
|
Cell* p = &word_body_storage[word_body_used];
|
||||||
|
word_body_used += cells;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------- Data stack ----------
|
// ---------- Data stack ----------
|
||||||
void data_push(int64_t val) {
|
void data_push(int64_t val) {
|
||||||
if (data_sp + 1 >= data_cap) {
|
if (data_sp + 1 >= data_cap) {
|
||||||
int32_t new_cap = data_cap ? data_cap * 2 : 128;
|
forth_printf("Data stack overflow\n");
|
||||||
int64_t *tmp = realloc(data_stack, new_cap * sizeof(int64_t));
|
return;
|
||||||
if (!tmp) {
|
|
||||||
fprintf(stderr, "Out of memory\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
data_stack = tmp;
|
|
||||||
data_cap = new_cap;
|
|
||||||
}
|
}
|
||||||
data_stack[++data_sp] = val;
|
data_stack[++data_sp] = val;
|
||||||
}
|
}
|
||||||
@@ -61,69 +83,52 @@ int64_t data_pop(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------- Return stack (holds Cell values) ----------
|
// ---------- Return stack (holds Cell values) ----------
|
||||||
static void ensure_ret_stack(void) {
|
|
||||||
if (rp + 1 >= ret_cap) {
|
|
||||||
int32_t new_cap = ret_cap ? ret_cap * 2 : 128;
|
|
||||||
Cell *tmp = realloc(ret_stack, new_cap * sizeof(Cell));
|
|
||||||
if (!tmp) {
|
|
||||||
fprintf(stderr, "Out of memory\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
ret_stack = tmp;
|
|
||||||
ret_cap = new_cap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ret_push_ip(Cell* val) {
|
void ret_push_ip(Cell* val) {
|
||||||
ensure_ret_stack();
|
if (rp + 1 >= ret_cap) {
|
||||||
|
forth_printf("Return stack overflow\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
rp++;
|
rp++;
|
||||||
ret_stack[rp].ptr = val; // store pointer in the 'ptr' member
|
ret_stack[rp].ptr = val; // store pointer in the 'ptr' member
|
||||||
}
|
}
|
||||||
|
|
||||||
Cell* ret_pop_ip(void) {
|
Cell* ret_pop_ip(void) {
|
||||||
if (rp < 0) {
|
if (rp < 0) {
|
||||||
fprintf(stderr, "Return stack underflow\n");
|
forth_printf("Return stack underflow\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return ret_stack[rp--].ptr;
|
return ret_stack[rp--].ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ret_push_num(int64_t val) {
|
void ret_push_num(int64_t val) {
|
||||||
ensure_ret_stack();
|
if (rp + 1 >= ret_cap) {
|
||||||
|
forth_printf("Return stack overflow\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
rp++;
|
rp++;
|
||||||
ret_stack[rp].num = val;
|
ret_stack[rp].num = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t ret_pop_num(void) {
|
int64_t ret_pop_num(void) {
|
||||||
if (rp < 0) {
|
if (rp < 0) {
|
||||||
fprintf(stderr, "Return stack underflow (num)\n");
|
forth_printf("Return stack underflow (num)\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return ret_stack[rp--].num;
|
return ret_stack[rp--].num;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- Compile stack (indices) ----------
|
// ---------- Compile stack (indices) ----------
|
||||||
static void ensure_compile_stack(void) {
|
|
||||||
if (compile_sp + 1 >= compile_stack_cap) {
|
|
||||||
int32_t new_cap = compile_stack_cap ? compile_stack_cap * 2 : 64;
|
|
||||||
int64_t *tmp = realloc(compile_stack, new_cap * sizeof(int64_t));
|
|
||||||
if (!tmp) {
|
|
||||||
fprintf(stderr, "Out of memory\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
compile_stack = tmp;
|
|
||||||
compile_stack_cap = new_cap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void compile_push(int64_t idx) {
|
void compile_push(int64_t idx) {
|
||||||
ensure_compile_stack();
|
if (compile_sp + 1 >= compile_stack_cap) {
|
||||||
|
forth_printf("Compile stack overflow\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
compile_stack[++compile_sp] = idx;
|
compile_stack[++compile_sp] = idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t compile_pop(void) {
|
int64_t compile_pop(void) {
|
||||||
if (compile_sp < 0) {
|
if (compile_sp < 0) {
|
||||||
fprintf(stderr, "Compile stack underflow\n");
|
forth_printf("Compile stack underflow\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return compile_stack[compile_sp--];
|
return compile_stack[compile_sp--];
|
||||||
|
|||||||
+1
-5
@@ -1,11 +1,7 @@
|
|||||||
#include "forth.h"
|
#include "forth.h"
|
||||||
|
|
||||||
Word* add_primitive(const char* name, void (*code)(Word*), uint8_t flags) {
|
Word* add_primitive(const char* name, void (*code)(Word*), uint8_t flags) {
|
||||||
Word* w = malloc(sizeof(Word));
|
Word* w = forth_alloc_word();
|
||||||
if (!w) {
|
|
||||||
fprintf(stderr, "Out of memory\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
w->prev = dict_head;
|
w->prev = dict_head;
|
||||||
dict_head = w;
|
dict_head = w;
|
||||||
|
|
||||||
|
|||||||
+17
-19
@@ -19,17 +19,12 @@ char* next_token(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure compile_buf has room for at least 'needed' more cells
|
// Ensure compile_buf has room for at least 'needed' more cells
|
||||||
void ensure_compile_cap(int32_t needed) {
|
int ensure_compile_cap(int32_t needed) {
|
||||||
while (compile_idx + needed > compile_cap) {
|
if (compile_idx + needed > compile_cap) {
|
||||||
int32_t new_cap = compile_cap ? compile_cap * 2 : 256;
|
forth_printf("Compile buffer overflow\n");
|
||||||
Cell *tmp = realloc(compile_buf, new_cap * sizeof(Cell));
|
return 0;
|
||||||
if (!tmp) {
|
|
||||||
fprintf(stderr, "Out of memory\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
compile_buf = tmp;
|
|
||||||
compile_cap = new_cap;
|
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inner interpreter (unchanged)
|
// Inner interpreter (unchanged)
|
||||||
@@ -62,7 +57,7 @@ void process_token(const char* token) {
|
|||||||
w->code(w);
|
w->code(w);
|
||||||
}
|
}
|
||||||
} else { // Compile normal word
|
} else { // Compile normal word
|
||||||
ensure_compile_cap(1);
|
if (!ensure_compile_cap(1)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w};
|
compile_buf[compile_idx++] = (Cell){.word = w};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,27 +69,30 @@ void process_token(const char* token) {
|
|||||||
data_push((int64_t)v);
|
data_push((int64_t)v);
|
||||||
} else { // Compile lit + number
|
} else { // Compile lit + number
|
||||||
if (!w_lit) {
|
if (!w_lit) {
|
||||||
fprintf(stderr, "Fatal: lit word not found\n");
|
forth_printf("Fatal: lit word not found\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ensure_compile_cap(2);
|
if (!ensure_compile_cap(2)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w_lit};
|
compile_buf[compile_idx++] = (Cell){.word = w_lit};
|
||||||
compile_buf[compile_idx++] = (Cell){.num = (int64_t)v};
|
compile_buf[compile_idx++] = (Cell){.num = (int64_t)v};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("Unknown word: '%s'\n", token);
|
forth_printf("Unknown word: '%s'\n", token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void outer_interpreter(void) {
|
void outer_interpreter(void) {
|
||||||
|
static char line_buf[256];
|
||||||
while (1) {
|
while (1) {
|
||||||
printf("ok ");
|
forth_printf("ok ");
|
||||||
fflush(stdout);
|
forth_fflush();
|
||||||
ssize_t n = getline(&input_buf, &input_buf_cap, stdin);
|
if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) {
|
||||||
if (n < 0) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
input_buf = line_buf;
|
||||||
|
input_buf_cap = sizeof(line_buf);
|
||||||
|
size_t n = strlen(input_buf);
|
||||||
if (n > 0 && input_buf[n - 1] == '\n') {
|
if (n > 0 && input_buf[n - 1] == '\n') {
|
||||||
input_buf[n - 1] = '\0';
|
input_buf[n - 1] = '\0';
|
||||||
}
|
}
|
||||||
@@ -104,5 +102,5 @@ void outer_interpreter(void) {
|
|||||||
process_token(tok);
|
process_token(tok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\n");
|
forth_printf("\n");
|
||||||
}
|
}
|
||||||
|
|||||||
+64
-66
@@ -98,7 +98,7 @@ void do_div(Word* w) {
|
|||||||
int64_t b = data_pop();
|
int64_t b = data_pop();
|
||||||
int64_t a = data_pop();
|
int64_t a = data_pop();
|
||||||
if (b == 0) {
|
if (b == 0) {
|
||||||
fprintf(stderr, "Division by zero\n");
|
forth_printf("Division by zero\n");
|
||||||
data_push(a);
|
data_push(a);
|
||||||
data_push(b);
|
data_push(b);
|
||||||
return;
|
return;
|
||||||
@@ -112,7 +112,7 @@ void do_mod(Word* w) {
|
|||||||
int64_t b = data_pop();
|
int64_t b = data_pop();
|
||||||
int64_t a = data_pop();
|
int64_t a = data_pop();
|
||||||
if (b == 0) {
|
if (b == 0) {
|
||||||
fprintf(stderr, "Modulo by zero\n");
|
forth_printf("Modulo by zero\n");
|
||||||
data_push(a);
|
data_push(a);
|
||||||
data_push(b);
|
data_push(b);
|
||||||
return;
|
return;
|
||||||
@@ -126,7 +126,7 @@ void do_slash_mod(Word* w) {
|
|||||||
int64_t b = data_pop();
|
int64_t b = data_pop();
|
||||||
int64_t a = data_pop();
|
int64_t a = data_pop();
|
||||||
if (b == 0) {
|
if (b == 0) {
|
||||||
fprintf(stderr, "Modulo by zero\n");
|
forth_printf("Modulo by zero\n");
|
||||||
data_push(a);
|
data_push(a);
|
||||||
data_push(b);
|
data_push(b);
|
||||||
return;
|
return;
|
||||||
@@ -309,26 +309,26 @@ void do_zero_gt(Word* w) {
|
|||||||
void do_dot(Word* w) {
|
void do_dot(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (data_sp < 0) return;
|
if (data_sp < 0) return;
|
||||||
printf("%" PRId64 " ", data_pop());
|
forth_printf("%" PRId64 " ", data_pop());
|
||||||
fflush(stdout);
|
forth_fflush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_cr(Word* w) {
|
void do_cr(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
printf("\n");
|
forth_printf("\n");
|
||||||
fflush(stdout);
|
forth_fflush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_emit(Word* w) {
|
void do_emit(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (data_sp < 0) return;
|
if (data_sp < 0) return;
|
||||||
putchar((char)data_pop());
|
forth_putchar((char)data_pop());
|
||||||
fflush(stdout);
|
forth_fflush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_key(Word* w) {
|
void do_key(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
int c = getchar();
|
int c = forth_getchar();
|
||||||
data_push(c == EOF ? -1 : c);
|
data_push(c == EOF ? -1 : c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,28 +336,28 @@ void do_dot_quote(Word* w) {
|
|||||||
(void)w;
|
(void)w;
|
||||||
if (state == 0) {
|
if (state == 0) {
|
||||||
// Interpret mode: print immediately
|
// Interpret mode: print immediately
|
||||||
if (input_ptr == NULL) { fprintf(stderr, "Missing string\n"); return; }
|
if (input_ptr == NULL) { forth_printf("Missing string\n"); return; }
|
||||||
while (*input_ptr && isspace((unsigned char)*input_ptr)) input_ptr++;
|
while (*input_ptr && isspace((unsigned char)*input_ptr)) input_ptr++;
|
||||||
if (*input_ptr != '"') { fprintf(stderr, "Expected \" to start string\n"); return; }
|
if (*input_ptr != '"') { forth_printf("Expected \" to start string\n"); return; }
|
||||||
input_ptr++;
|
input_ptr++;
|
||||||
char* start = input_ptr;
|
char* start = input_ptr;
|
||||||
while (*input_ptr && *input_ptr != '"') input_ptr++;
|
while (*input_ptr && *input_ptr != '"') input_ptr++;
|
||||||
if (*input_ptr != '"') { fprintf(stderr, "Unterminated string\n"); return; }
|
if (*input_ptr != '"') { forth_printf("Unterminated string\n"); return; }
|
||||||
while (start < input_ptr) putchar(*start++);
|
while (start < input_ptr) forth_putchar(*start++);
|
||||||
input_ptr++;
|
input_ptr++;
|
||||||
fflush(stdout);
|
forth_fflush();
|
||||||
} else {
|
} else {
|
||||||
// Compile mode: compile string for runtime
|
// Compile mode: compile string for runtime
|
||||||
if (input_ptr == NULL) { fprintf(stderr, "Missing string\n"); return; }
|
if (input_ptr == NULL) { forth_printf("Missing string\n"); return; }
|
||||||
while (*input_ptr && isspace((unsigned char)*input_ptr)) input_ptr++;
|
while (*input_ptr && isspace((unsigned char)*input_ptr)) input_ptr++;
|
||||||
if (*input_ptr != '"') { fprintf(stderr, "Expected \" to start string\n"); return; }
|
if (*input_ptr != '"') { forth_printf("Expected \" to start string\n"); return; }
|
||||||
input_ptr++;
|
input_ptr++;
|
||||||
char* start = input_ptr;
|
char* start = input_ptr;
|
||||||
while (*input_ptr && *input_ptr != '"') input_ptr++;
|
while (*input_ptr && *input_ptr != '"') input_ptr++;
|
||||||
if (*input_ptr != '"') { fprintf(stderr, "Unterminated string\n"); return; }
|
if (*input_ptr != '"') { forth_printf("Unterminated string\n"); return; }
|
||||||
size_t len = input_ptr - start;
|
size_t len = input_ptr - start;
|
||||||
if (!w_dot_quote_inner) { fprintf(stderr, "Fatal: do_dot_quote_inner not found\n"); return; }
|
if (!w_dot_quote_inner) { forth_printf("Fatal: do_dot_quote_inner not found\n"); return; }
|
||||||
ensure_compile_cap(2 + (int32_t)len);
|
if (!ensure_compile_cap(2 + (int32_t)len)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w_dot_quote_inner};
|
compile_buf[compile_idx++] = (Cell){.word = w_dot_quote_inner};
|
||||||
compile_buf[compile_idx++] = (Cell){.num = (int64_t)len};
|
compile_buf[compile_idx++] = (Cell){.num = (int64_t)len};
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
@@ -372,21 +372,21 @@ void do_dot_quote_inner(Word* w) {
|
|||||||
int64_t len = ip->num;
|
int64_t len = ip->num;
|
||||||
ip++;
|
ip++;
|
||||||
for (int64_t i = 0; i < len; i++) {
|
for (int64_t i = 0; i < len; i++) {
|
||||||
putchar((char)ip->num);
|
forth_putchar((char)ip->num);
|
||||||
ip++;
|
ip++;
|
||||||
}
|
}
|
||||||
fflush(stdout);
|
forth_fflush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_words(Word* w) {
|
void do_words(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
printf("Dictionary words:\n");
|
forth_printf("Dictionary words:\n");
|
||||||
for (Word* cur = dict_head; cur != NULL; cur = cur->prev) {
|
for (Word* cur = dict_head; cur != NULL; cur = cur->prev) {
|
||||||
if (cur->flags & (1 << 6)) continue;
|
if (cur->flags & (1 << 6)) continue;
|
||||||
printf("%s ", cur->name);
|
forth_printf("%s ", cur->name);
|
||||||
}
|
}
|
||||||
printf("\n");
|
forth_printf("\n");
|
||||||
fflush(stdout);
|
forth_fflush();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory operations
|
// Memory operations
|
||||||
@@ -394,7 +394,7 @@ void do_fetch(Word* w) {
|
|||||||
(void)w;
|
(void)w;
|
||||||
int64_t addr = data_pop();
|
int64_t addr = data_pop();
|
||||||
if (addr < 0 || addr >= user_mem_size) {
|
if (addr < 0 || addr >= user_mem_size) {
|
||||||
fprintf(stderr, "Address out of bounds\n");
|
forth_printf("Address out of bounds\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data_push(user_mem[addr].num);
|
data_push(user_mem[addr].num);
|
||||||
@@ -405,7 +405,7 @@ void do_store(Word* w) {
|
|||||||
int64_t addr = data_pop();
|
int64_t addr = data_pop();
|
||||||
int64_t val = data_pop();
|
int64_t val = data_pop();
|
||||||
if (addr < 0 || addr >= user_mem_size) {
|
if (addr < 0 || addr >= user_mem_size) {
|
||||||
fprintf(stderr, "Address out of bounds\n");
|
forth_printf("Address out of bounds\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
user_mem[addr].num = val;
|
user_mem[addr].num = val;
|
||||||
@@ -416,7 +416,7 @@ void do_plus_store(Word* w) {
|
|||||||
int64_t addr = data_pop();
|
int64_t addr = data_pop();
|
||||||
int64_t val = data_pop();
|
int64_t val = data_pop();
|
||||||
if (addr < 0 || addr >= user_mem_size) {
|
if (addr < 0 || addr >= user_mem_size) {
|
||||||
fprintf(stderr, "Address out of bounds\n");
|
forth_printf("Address out of bounds\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
user_mem[addr].num += val;
|
user_mem[addr].num += val;
|
||||||
@@ -427,7 +427,7 @@ void do_cfetch(Word* w) {
|
|||||||
int64_t addr = data_pop(); // byte offset
|
int64_t addr = data_pop(); // byte offset
|
||||||
int64_t max_byte = user_mem_size * (int64_t)sizeof(Cell);
|
int64_t max_byte = user_mem_size * (int64_t)sizeof(Cell);
|
||||||
if (addr < 0 || addr >= max_byte) {
|
if (addr < 0 || addr >= max_byte) {
|
||||||
fprintf(stderr, "Address out of bounds\n");
|
forth_printf("Address out of bounds\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint8_t* base = (uint8_t*)user_mem;
|
uint8_t* base = (uint8_t*)user_mem;
|
||||||
@@ -440,7 +440,7 @@ void do_cstore(Word* w) {
|
|||||||
int64_t val = data_pop();
|
int64_t val = data_pop();
|
||||||
int64_t max_byte = user_mem_size * (int64_t)sizeof(Cell);
|
int64_t max_byte = user_mem_size * (int64_t)sizeof(Cell);
|
||||||
if (addr < 0 || addr >= max_byte) {
|
if (addr < 0 || addr >= max_byte) {
|
||||||
fprintf(stderr, "Address out of bounds\n");
|
forth_printf("Address out of bounds\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint8_t* base = (uint8_t*)user_mem;
|
uint8_t* base = (uint8_t*)user_mem;
|
||||||
@@ -457,7 +457,7 @@ void do_allot(Word* w) {
|
|||||||
(void)w;
|
(void)w;
|
||||||
int64_t n = data_pop();
|
int64_t n = data_pop();
|
||||||
if (here + n > user_mem + user_mem_size) {
|
if (here + n > user_mem + user_mem_size) {
|
||||||
fprintf(stderr, "User memory overflow\n");
|
forth_printf("User memory overflow\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
here += n;
|
here += n;
|
||||||
@@ -467,11 +467,11 @@ void do_allot(Word* w) {
|
|||||||
void do_variable(Word* w) {
|
void do_variable(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
char* name = next_token();
|
char* name = next_token();
|
||||||
if (!name) { fprintf(stderr, "VARIABLE expects a name\n"); return; }
|
if (!name) { forth_printf("VARIABLE expects a name\n"); return; }
|
||||||
|
|
||||||
// allocate one cell in user memory for the variable's data
|
// allocate one cell in user memory for the variable's data
|
||||||
if (here + 1 > user_mem + user_mem_size) {
|
if (here + 1 > user_mem + user_mem_size) {
|
||||||
fprintf(stderr, "User memory overflow\n");
|
forth_printf("User memory overflow\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Cell* var_cell = here; // address of the data cell
|
Cell* var_cell = here; // address of the data cell
|
||||||
@@ -479,8 +479,7 @@ void do_variable(Word* w) {
|
|||||||
here++;
|
here++;
|
||||||
|
|
||||||
// create dictionary entry
|
// create dictionary entry
|
||||||
Word* new_w = malloc(sizeof(Word));
|
Word* new_w = forth_alloc_word();
|
||||||
if (!new_w) { printf("Out of memory\n"); exit(1); }
|
|
||||||
new_w->prev = dict_head;
|
new_w->prev = dict_head;
|
||||||
dict_head = new_w;
|
dict_head = new_w;
|
||||||
|
|
||||||
@@ -497,11 +496,11 @@ void do_constant(Word* w) {
|
|||||||
(void)w;
|
(void)w;
|
||||||
int64_t val = data_pop();
|
int64_t val = data_pop();
|
||||||
char* name = next_token();
|
char* name = next_token();
|
||||||
if (!name) { fprintf(stderr, "CONSTANT expects a name\n"); data_push(val); return; }
|
if (!name) { forth_printf("CONSTANT expects a name\n"); data_push(val); return; }
|
||||||
|
|
||||||
// allocate a cell in user memory to hold the constant value
|
// allocate a cell in user memory to hold the constant value
|
||||||
if (here + 1 > user_mem + user_mem_size) {
|
if (here + 1 > user_mem + user_mem_size) {
|
||||||
fprintf(stderr, "User memory overflow\n");
|
forth_printf("User memory overflow\n");
|
||||||
data_push(val); // restore the value (optional)
|
data_push(val); // restore the value (optional)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -509,8 +508,7 @@ void do_constant(Word* w) {
|
|||||||
val_cell->num = val;
|
val_cell->num = val;
|
||||||
here++;
|
here++;
|
||||||
|
|
||||||
Word* new_w = malloc(sizeof(Word));
|
Word* new_w = forth_alloc_word();
|
||||||
if (!new_w) { printf("Out of memory\n"); exit(1); }
|
|
||||||
new_w->prev = dict_head;
|
new_w->prev = dict_head;
|
||||||
dict_head = new_w;
|
dict_head = new_w;
|
||||||
|
|
||||||
@@ -547,7 +545,7 @@ void do_r_from(Word* w) {
|
|||||||
|
|
||||||
void do_r_fetch(Word* w) {
|
void do_r_fetch(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (rp < 0) { fprintf(stderr, "Return stack underflow\n"); return; }
|
if (rp < 0) { forth_printf("Return stack underflow\n"); return; }
|
||||||
data_push(ret_stack[rp].num);
|
data_push(ret_stack[rp].num);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,7 +570,7 @@ void do_lit(Word* w) {
|
|||||||
void do_colon(Word* w) {
|
void do_colon(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
char* name = next_token();
|
char* name = next_token();
|
||||||
if (!name) { fprintf(stderr, "':' expects a name\n"); return; }
|
if (!name) { forth_printf("':' expects a name\n"); return; }
|
||||||
size_t len = strlen(name);
|
size_t len = strlen(name);
|
||||||
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
memcpy(compiling_name, name, len);
|
memcpy(compiling_name, name, len);
|
||||||
@@ -584,20 +582,20 @@ void do_colon(Word* w) {
|
|||||||
|
|
||||||
void do_semicolon(Word* w) {
|
void do_semicolon(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (state != 1) { fprintf(stderr, "';' only valid in compile mode\n"); return; }
|
if (state != 1) { forth_printf("';' only valid in compile mode\n"); return; }
|
||||||
if (!w_exit) { fprintf(stderr, "Fatal: exit word not found\n"); return; }
|
if (!w_exit) { forth_printf("Fatal: exit word not found\n"); return; }
|
||||||
|
|
||||||
ensure_compile_cap(1);
|
if (!ensure_compile_cap(1)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w_exit};
|
compile_buf[compile_idx++] = (Cell){.word = w_exit};
|
||||||
|
|
||||||
// Create body copy of compiled cells
|
// Create body copy of compiled cells
|
||||||
Cell* body_copy = malloc(compile_idx * sizeof(Cell));
|
Cell* body_copy = forth_alloc_body(compile_idx);
|
||||||
if (!body_copy) { printf("Out of memory\n"); exit(1); }
|
if (!body_copy) { forth_printf("Out of memory\n"); return; }
|
||||||
memcpy(body_copy, compile_buf, compile_idx * sizeof(Cell));
|
memcpy(body_copy, compile_buf, compile_idx * sizeof(Cell));
|
||||||
|
|
||||||
// Create new word entry
|
// Create new word entry
|
||||||
Word* new_w = malloc(sizeof(Word));
|
Word* new_w = forth_alloc_word();
|
||||||
if (!new_w) { printf("Out of memory\n"); free(body_copy); exit(1); }
|
if (!new_w) { forth_printf("Out of memory\n"); return; }
|
||||||
new_w->prev = dict_head;
|
new_w->prev = dict_head;
|
||||||
dict_head = new_w;
|
dict_head = new_w;
|
||||||
|
|
||||||
@@ -632,9 +630,9 @@ void do_zero_branch(Word* w) {
|
|||||||
// Control flow using compile stack (indices)
|
// Control flow using compile stack (indices)
|
||||||
void do_if(Word* w) {
|
void do_if(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (state != 1) { fprintf(stderr, "IF only valid in compile mode\n"); return; }
|
if (state != 1) { forth_printf("IF only valid in compile mode\n"); return; }
|
||||||
if (!w_zbranch) { fprintf(stderr, "Fatal: 0branch not found\n"); return; }
|
if (!w_zbranch) { forth_printf("Fatal: 0branch not found\n"); return; }
|
||||||
ensure_compile_cap(2);
|
if (!ensure_compile_cap(2)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w_zbranch};
|
compile_buf[compile_idx++] = (Cell){.word = w_zbranch};
|
||||||
// compile_push current index (where the offset will be placed)
|
// compile_push current index (where the offset will be placed)
|
||||||
compile_push(compile_idx);
|
compile_push(compile_idx);
|
||||||
@@ -643,7 +641,7 @@ void do_if(Word* w) {
|
|||||||
|
|
||||||
void do_then(Word* w) {
|
void do_then(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (state != 1) { fprintf(stderr, "THEN only valid in compile mode\n"); return; }
|
if (state != 1) { forth_printf("THEN only valid in compile mode\n"); return; }
|
||||||
int64_t offset_idx = compile_pop();
|
int64_t offset_idx = compile_pop();
|
||||||
if (offset_idx < 0) return;
|
if (offset_idx < 0) return;
|
||||||
compile_buf[offset_idx].num = compile_idx - offset_idx;
|
compile_buf[offset_idx].num = compile_idx - offset_idx;
|
||||||
@@ -651,12 +649,12 @@ void do_then(Word* w) {
|
|||||||
|
|
||||||
void do_else(Word* w) {
|
void do_else(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (state != 1) { fprintf(stderr, "ELSE only valid in compile mode\n"); return; }
|
if (state != 1) { forth_printf("ELSE only valid in compile mode\n"); return; }
|
||||||
int64_t if_offset_idx = compile_pop();
|
int64_t if_offset_idx = compile_pop();
|
||||||
if (if_offset_idx < 0) return;
|
if (if_offset_idx < 0) return;
|
||||||
|
|
||||||
if (!w_branch) { fprintf(stderr, "Fatal: branch not found\n"); return; }
|
if (!w_branch) { forth_printf("Fatal: branch not found\n"); return; }
|
||||||
ensure_compile_cap(2);
|
if (!ensure_compile_cap(2)) return;
|
||||||
|
|
||||||
// resolve IF offset to skip the ELSE branch
|
// resolve IF offset to skip the ELSE branch
|
||||||
compile_buf[if_offset_idx].num = (compile_idx + 2) - if_offset_idx;
|
compile_buf[if_offset_idx].num = (compile_idx + 2) - if_offset_idx;
|
||||||
@@ -669,30 +667,30 @@ void do_else(Word* w) {
|
|||||||
|
|
||||||
void do_begin(Word* w) {
|
void do_begin(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (state != 1) { fprintf(stderr, "BEGIN only valid in compile mode\n"); return; }
|
if (state != 1) { forth_printf("BEGIN only valid in compile mode\n"); return; }
|
||||||
compile_push(compile_idx);
|
compile_push(compile_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_until(Word* w) {
|
void do_until(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (state != 1) { fprintf(stderr, "UNTIL only valid in compile mode\n"); return; }
|
if (state != 1) { forth_printf("UNTIL only valid in compile mode\n"); return; }
|
||||||
int64_t begin_idx = compile_pop();
|
int64_t begin_idx = compile_pop();
|
||||||
if (begin_idx < 0) return;
|
if (begin_idx < 0) return;
|
||||||
|
|
||||||
if (!w_zbranch) { fprintf(stderr, "Fatal: 0branch not found\n"); return; }
|
if (!w_zbranch) { forth_printf("Fatal: 0branch not found\n"); return; }
|
||||||
ensure_compile_cap(2);
|
if (!ensure_compile_cap(2)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w_zbranch};
|
compile_buf[compile_idx++] = (Cell){.word = w_zbranch};
|
||||||
compile_buf[compile_idx++] = (Cell){.num = begin_idx - compile_idx};
|
compile_buf[compile_idx++] = (Cell){.num = begin_idx - compile_idx};
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_while(Word* w) {
|
void do_while(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (state != 1) { fprintf(stderr, "WHILE only valid in compile mode\n"); return; }
|
if (state != 1) { forth_printf("WHILE only valid in compile mode\n"); return; }
|
||||||
int64_t begin_idx = compile_pop();
|
int64_t begin_idx = compile_pop();
|
||||||
if (begin_idx < 0) return;
|
if (begin_idx < 0) return;
|
||||||
|
|
||||||
if (!w_zbranch) { fprintf(stderr, "Fatal: 0branch not found\n"); return; }
|
if (!w_zbranch) { forth_printf("Fatal: 0branch not found\n"); return; }
|
||||||
ensure_compile_cap(2);
|
if (!ensure_compile_cap(2)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w_zbranch};
|
compile_buf[compile_idx++] = (Cell){.word = w_zbranch};
|
||||||
int64_t while_offset_idx = compile_idx;
|
int64_t while_offset_idx = compile_idx;
|
||||||
compile_idx++; // reserve offset
|
compile_idx++; // reserve offset
|
||||||
@@ -703,14 +701,14 @@ void do_while(Word* w) {
|
|||||||
|
|
||||||
void do_repeat(Word* w) {
|
void do_repeat(Word* w) {
|
||||||
(void)w;
|
(void)w;
|
||||||
if (state != 1) { fprintf(stderr, "REPEAT only valid in compile mode\n"); return; }
|
if (state != 1) { forth_printf("REPEAT only valid in compile mode\n"); return; }
|
||||||
int64_t begin_idx = compile_pop();
|
int64_t begin_idx = compile_pop();
|
||||||
if (begin_idx < 0) return;
|
if (begin_idx < 0) return;
|
||||||
int64_t while_offset_idx = compile_pop();
|
int64_t while_offset_idx = compile_pop();
|
||||||
if (while_offset_idx < 0) return;
|
if (while_offset_idx < 0) return;
|
||||||
|
|
||||||
if (!w_branch) { fprintf(stderr, "Fatal: branch not found\n"); return; }
|
if (!w_branch) { forth_printf("Fatal: branch not found\n"); return; }
|
||||||
ensure_compile_cap(2);
|
if (!ensure_compile_cap(2)) return;
|
||||||
compile_buf[compile_idx++] = (Cell){.word = w_branch};
|
compile_buf[compile_idx++] = (Cell){.word = w_branch};
|
||||||
compile_buf[compile_idx++] = (Cell){.num = begin_idx - compile_idx};
|
compile_buf[compile_idx++] = (Cell){.num = begin_idx - compile_idx};
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
#include "forth.h"
|
#include "forth.h"
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
// Allocate user memory
|
|
||||||
user_mem_size = 1024 * 1024; // 1 Mega cells
|
|
||||||
user_mem = calloc((size_t)user_mem_size, sizeof(Cell));
|
|
||||||
if (!user_mem) {
|
|
||||||
fprintf(stderr, "Failed to allocate user memory\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
here = user_mem;
|
here = user_mem;
|
||||||
|
|
||||||
// Hidden words first
|
// Hidden words first
|
||||||
|
|||||||
Reference in New Issue
Block a user