feat: implement missing Forth features and fix compiler warnings
Co-authored-by: aider (openrouter/moonshotai/kimi-k2.6) <aider@aider.chat>
This commit is contained in:
+1
-1
@@ -12,7 +12,7 @@ Word* add_primitive(const char* name, void (*code)(Word*), uint8_t flags) {
|
|||||||
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;
|
||||||
w->flags = flags | (uint8_t)len;
|
w->flags = flags | (uint8_t)len;
|
||||||
strncpy(w->name, name, len);
|
memcpy(w->name, name, len);
|
||||||
w->name[len] = '\0';
|
w->name[len] = '\0';
|
||||||
w->code = code;
|
w->code = code;
|
||||||
w->body = NULL;
|
w->body = NULL;
|
||||||
|
|||||||
+384
-30
@@ -2,16 +2,19 @@
|
|||||||
|
|
||||||
// Stack operations
|
// Stack operations
|
||||||
void do_dup(Word* w) {
|
void do_dup(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
int32_t v = data_stack[sp];
|
int32_t v = data_stack[sp];
|
||||||
data_push(v);
|
data_push(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_drop(Word* w) {
|
void do_drop(Word* w) {
|
||||||
|
(void)w;
|
||||||
data_pop();
|
data_pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_swap(Word* w) {
|
void do_swap(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t a = data_stack[sp-1];
|
int32_t a = data_stack[sp-1];
|
||||||
int32_t b = data_stack[sp];
|
int32_t b = data_stack[sp];
|
||||||
@@ -20,11 +23,13 @@ void do_swap(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_over(Word* w) {
|
void do_over(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
data_push(data_stack[sp-1]);
|
data_push(data_stack[sp-1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_rot(Word* w) {
|
void do_rot(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 2) return;
|
if (sp < 2) return;
|
||||||
int32_t a = data_stack[sp-2];
|
int32_t a = data_stack[sp-2];
|
||||||
int32_t b = data_stack[sp-1];
|
int32_t b = data_stack[sp-1];
|
||||||
@@ -35,6 +40,7 @@ void do_rot(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_minus_rot(Word* w) {
|
void do_minus_rot(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 2) return;
|
if (sp < 2) return;
|
||||||
int32_t a = data_stack[sp-2];
|
int32_t a = data_stack[sp-2];
|
||||||
int32_t b = data_stack[sp-1];
|
int32_t b = data_stack[sp-1];
|
||||||
@@ -45,12 +51,14 @@ void do_minus_rot(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_nip(Word* w) {
|
void do_nip(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
data_stack[sp-1] = data_stack[sp];
|
data_stack[sp-1] = data_stack[sp];
|
||||||
sp--;
|
sp--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_tuck(Word* w) {
|
void do_tuck(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t a = data_stack[sp-1];
|
int32_t a = data_stack[sp-1];
|
||||||
int32_t b = data_stack[sp];
|
int32_t b = data_stack[sp];
|
||||||
@@ -60,6 +68,7 @@ void do_tuck(Word* w) {
|
|||||||
|
|
||||||
// Arithmetic operations
|
// Arithmetic operations
|
||||||
void do_add(Word* w) {
|
void do_add(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -67,6 +76,7 @@ void do_add(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_sub(Word* w) {
|
void do_sub(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -74,6 +84,7 @@ void do_sub(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_mul(Word* w) {
|
void do_mul(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -81,6 +92,7 @@ void do_mul(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_div(Word* w) {
|
void do_div(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -94,6 +106,7 @@ void do_div(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_mod(Word* w) {
|
void do_mod(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -107,6 +120,7 @@ void do_mod(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_slash_mod(Word* w) {
|
void do_slash_mod(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -121,37 +135,44 @@ void do_slash_mod(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_one_plus(Word* w) {
|
void do_one_plus(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
data_stack[sp]++;
|
data_stack[sp]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_one_minus(Word* w) {
|
void do_one_minus(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
data_stack[sp]--;
|
data_stack[sp]--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_two_plus(Word* w) {
|
void do_two_plus(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
data_stack[sp] += 2;
|
data_stack[sp] += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_two_minus(Word* w) {
|
void do_two_minus(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
data_stack[sp] -= 2;
|
data_stack[sp] -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_negate(Word* w) {
|
void do_negate(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
data_stack[sp] = -data_stack[sp];
|
data_stack[sp] = -data_stack[sp];
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_abs(Word* w) {
|
void do_abs(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
int32_t v = data_pop();
|
int32_t v = data_pop();
|
||||||
data_push(v < 0 ? -v : v);
|
data_push(v < 0 ? -v : v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_min(Word* w) {
|
void do_min(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -159,6 +180,7 @@ void do_min(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_max(Word* w) {
|
void do_max(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -167,6 +189,7 @@ void do_max(Word* w) {
|
|||||||
|
|
||||||
// Logic operations
|
// Logic operations
|
||||||
void do_and(Word* w) {
|
void do_and(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -174,6 +197,7 @@ void do_and(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_or(Word* w) {
|
void do_or(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -181,6 +205,7 @@ void do_or(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_xor(Word* w) {
|
void do_xor(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -188,11 +213,13 @@ void do_xor(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_invert(Word* w) {
|
void do_invert(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
data_stack[sp] = ~data_stack[sp];
|
data_stack[sp] = ~data_stack[sp];
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_lshift(Word* w) {
|
void do_lshift(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -200,6 +227,7 @@ void do_lshift(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_rshift(Word* w) {
|
void do_rshift(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -208,13 +236,15 @@ void do_rshift(Word* w) {
|
|||||||
|
|
||||||
// Comparison operations
|
// Comparison operations
|
||||||
void do_eq(Word* w) {
|
void do_eq(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
data_push(a == b ? -1 : 0); // Forth uses -1 for true, 0 for false
|
data_push(a == b ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_neq(Word* w) {
|
void do_neq(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -222,6 +252,7 @@ void do_neq(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_lt(Word* w) {
|
void do_lt(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -229,6 +260,7 @@ void do_lt(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_gt(Word* w) {
|
void do_gt(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -236,6 +268,7 @@ void do_gt(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_lte(Word* w) {
|
void do_lte(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -243,6 +276,7 @@ void do_lte(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_gte(Word* w) {
|
void do_gte(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 1) return;
|
if (sp < 1) return;
|
||||||
int32_t b = data_pop();
|
int32_t b = data_pop();
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
@@ -250,18 +284,21 @@ void do_gte(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_zero_eq(Word* w) {
|
void do_zero_eq(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
data_push(a == 0 ? -1 : 0);
|
data_push(a == 0 ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_zero_lt(Word* w) {
|
void do_zero_lt(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
data_push(a < 0 ? -1 : 0);
|
data_push(a < 0 ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_zero_gt(Word* w) {
|
void do_zero_gt(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
int32_t a = data_pop();
|
int32_t a = data_pop();
|
||||||
data_push(a > 0 ? -1 : 0);
|
data_push(a > 0 ? -1 : 0);
|
||||||
@@ -269,28 +306,33 @@ void do_zero_gt(Word* w) {
|
|||||||
|
|
||||||
// I/O operations
|
// I/O operations
|
||||||
void do_dot(Word* w) {
|
void do_dot(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
printf("%d ", data_pop());
|
printf("%d ", data_pop());
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_cr(Word* w) {
|
void do_cr(Word* w) {
|
||||||
|
(void)w;
|
||||||
printf("\n");
|
printf("\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_emit(Word* w) {
|
void do_emit(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (sp < 0) return;
|
if (sp < 0) return;
|
||||||
putchar((char)data_pop());
|
putchar((char)data_pop());
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_key(Word* w) {
|
void do_key(Word* w) {
|
||||||
|
(void)w;
|
||||||
int c = getchar();
|
int c = getchar();
|
||||||
data_push(c == EOF ? -1 : c);
|
data_push(c == EOF ? -1 : c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_dot_quote(Word* w) {
|
void do_dot_quote(Word* w) {
|
||||||
|
(void)w;
|
||||||
// Immediate word: parse string until " and print/compile
|
// Immediate word: parse string until " and print/compile
|
||||||
if (state == 0) { // Interpret mode: print immediately
|
if (state == 0) { // Interpret mode: print immediately
|
||||||
if (input_ptr == NULL) {
|
if (input_ptr == NULL) {
|
||||||
@@ -351,7 +393,7 @@ void do_dot_quote(Word* w) {
|
|||||||
printf("Fatal: do_dot_quote_inner not found\n");
|
printf("Fatal: do_dot_quote_inner not found\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (compile_idx + 2 + len > COMPILE_BUF_SIZE) {
|
if (compile_idx + 2 + (int32_t)len > COMPILE_BUF_SIZE) {
|
||||||
printf("Compile buffer full\n");
|
printf("Compile buffer full\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -366,6 +408,7 @@ void do_dot_quote(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_dot_quote_inner(Word* w) {
|
void do_dot_quote_inner(Word* w) {
|
||||||
|
(void)w;
|
||||||
// Runtime: ip points to length cell, followed by string characters
|
// Runtime: ip points to length cell, followed by string characters
|
||||||
int32_t len = ip->num;
|
int32_t len = ip->num;
|
||||||
ip++;
|
ip++;
|
||||||
@@ -377,6 +420,7 @@ void do_dot_quote_inner(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_words(Word* w) {
|
void do_words(Word* w) {
|
||||||
|
(void)w;
|
||||||
printf("Dictionary words:\n");
|
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; // Skip hidden
|
if (cur->flags & (1 << 6)) continue; // Skip hidden
|
||||||
@@ -388,6 +432,7 @@ void do_words(Word* w) {
|
|||||||
|
|
||||||
// Control flow operations
|
// Control flow operations
|
||||||
void do_exit(Word* w) {
|
void do_exit(Word* w) {
|
||||||
|
(void)w;
|
||||||
Cell* ret_addr = ret_pop_ip();
|
Cell* ret_addr = ret_pop_ip();
|
||||||
ip = ret_addr;
|
ip = ret_addr;
|
||||||
}
|
}
|
||||||
@@ -400,24 +445,29 @@ void do_docolon(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_lit(Word* w) {
|
void do_lit(Word* w) {
|
||||||
|
(void)w;
|
||||||
// ip points to the number cell (inner interpreter already incremented past lit word)
|
// ip points to the number cell (inner interpreter already incremented past lit word)
|
||||||
data_push(ip->num);
|
data_push(ip->num);
|
||||||
ip++; // Move past number cell
|
ip++; // Move past number cell
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_colon(Word* w) {
|
void do_colon(Word* w) {
|
||||||
|
(void)w;
|
||||||
char* name = next_token();
|
char* name = next_token();
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
printf("':' expects a name\n");
|
printf("':' expects a name\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
strncpy(compiling_name, name, MAX_NAME_LEN);
|
size_t len = strlen(name);
|
||||||
compiling_name[MAX_NAME_LEN] = '\0';
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
|
memcpy(compiling_name, name, len);
|
||||||
|
compiling_name[len] = '\0';
|
||||||
state = 1; // Enter compile mode
|
state = 1; // Enter compile mode
|
||||||
compile_idx = 0; // Reset compile buffer
|
compile_idx = 0; // Reset compile buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_semicolon(Word* w) {
|
void do_semicolon(Word* w) {
|
||||||
|
(void)w;
|
||||||
if (state != 1) {
|
if (state != 1) {
|
||||||
printf("';' is only valid in compile mode\n");
|
printf("';' is only valid in compile mode\n");
|
||||||
return;
|
return;
|
||||||
@@ -452,7 +502,7 @@ void do_semicolon(Word* w) {
|
|||||||
size_t len = strlen(compiling_name);
|
size_t len = strlen(compiling_name);
|
||||||
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
new_w->flags = (uint8_t)len; // No hidden, no immediate
|
new_w->flags = (uint8_t)len; // No hidden, no immediate
|
||||||
strncpy(new_w->name, compiling_name, len);
|
memcpy(new_w->name, compiling_name, len);
|
||||||
new_w->name[len] = '\0';
|
new_w->name[len] = '\0';
|
||||||
new_w->code = do_docolon;
|
new_w->code = do_docolon;
|
||||||
new_w->body = &dict_bodies[body_idx];
|
new_w->body = &dict_bodies[body_idx];
|
||||||
@@ -462,12 +512,14 @@ void do_semicolon(Word* w) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_branch(Word* w) {
|
void do_branch(Word* w) {
|
||||||
|
(void)w;
|
||||||
// Unconditional branch: ip points to offset cell
|
// Unconditional branch: ip points to offset cell
|
||||||
int32_t offset = ip->num;
|
int32_t offset = ip->num;
|
||||||
ip += offset; // Jump offset cells (offset is relative to after the offset cell)
|
ip += offset; // Jump offset cells (relative to offset cell itself)
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_zero_branch(Word* w) {
|
void do_zero_branch(Word* w) {
|
||||||
|
(void)w;
|
||||||
// Conditional branch: if top of stack is 0, branch
|
// Conditional branch: if top of stack is 0, branch
|
||||||
int32_t cond = data_pop();
|
int32_t cond = data_pop();
|
||||||
if (cond == 0) {
|
if (cond == 0) {
|
||||||
@@ -478,29 +530,331 @@ void do_zero_branch(Word* w) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory operations (stubs for now)
|
// Memory operations
|
||||||
void do_fetch(Word* w) { /* TODO */ }
|
void do_fetch(Word* w) {
|
||||||
void do_store(Word* w) { /* TODO */ }
|
(void)w;
|
||||||
void do_plus_store(Word* w) { /* TODO */ }
|
int32_t addr = data_pop();
|
||||||
void do_cfetch(Word* w) { /* TODO */ }
|
if (addr < 0 || addr >= USER_MEMORY_SIZE) {
|
||||||
void do_cstore(Word* w) { /* TODO */ }
|
printf("Address out of bounds\n");
|
||||||
void do_variable(Word* w) { /* TODO */ }
|
return;
|
||||||
void do_constant(Word* w) { /* TODO */ }
|
}
|
||||||
void do_do_var(Word* w) { /* TODO */ }
|
data_push(user_mem[addr]);
|
||||||
void do_do_const(Word* w) { /* TODO */ }
|
}
|
||||||
void do_here(Word* w) { /* TODO */ }
|
|
||||||
void do_allot(Word* w) { /* TODO */ }
|
|
||||||
|
|
||||||
// Return stack operations (stubs for now)
|
void do_store(Word* w) {
|
||||||
void do_to_r(Word* w) { /* TODO */ }
|
(void)w;
|
||||||
void do_r_from(Word* w) { /* TODO */ }
|
int32_t val = data_pop();
|
||||||
void do_r_fetch(Word* w) { /* TODO */ }
|
int32_t addr = data_pop();
|
||||||
|
if (addr < 0 || addr >= USER_MEMORY_SIZE) {
|
||||||
|
printf("Address out of bounds\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
user_mem[addr] = val;
|
||||||
|
}
|
||||||
|
|
||||||
// Additional control flow stubs
|
void do_plus_store(Word* w) {
|
||||||
void do_if(Word* w) { /* TODO */ }
|
(void)w;
|
||||||
void do_else(Word* w) { /* TODO */ }
|
int32_t val = data_pop();
|
||||||
void do_then(Word* w) { /* TODO */ }
|
int32_t addr = data_pop();
|
||||||
void do_begin(Word* w) { /* TODO */ }
|
if (addr < 0 || addr >= USER_MEMORY_SIZE) {
|
||||||
void do_until(Word* w) { /* TODO */ }
|
printf("Address out of bounds\n");
|
||||||
void do_while(Word* w) { /* TODO */ }
|
return;
|
||||||
void do_repeat(Word* w) { /* TODO */ }
|
}
|
||||||
|
user_mem[addr] += val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_cfetch(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
int32_t addr = data_pop();
|
||||||
|
int32_t max_addr = USER_MEMORY_SIZE * (int32_t)sizeof(int32_t);
|
||||||
|
if (addr < 0 || addr >= max_addr) {
|
||||||
|
printf("Address out of bounds\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int32_t cell = addr / (int32_t)sizeof(int32_t);
|
||||||
|
int32_t byte = addr % (int32_t)sizeof(int32_t);
|
||||||
|
uint8_t* p = (uint8_t*)&user_mem[cell];
|
||||||
|
data_push((int32_t)p[byte]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_cstore(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
int32_t val = data_pop();
|
||||||
|
int32_t addr = data_pop();
|
||||||
|
int32_t max_addr = USER_MEMORY_SIZE * (int32_t)sizeof(int32_t);
|
||||||
|
if (addr < 0 || addr >= max_addr) {
|
||||||
|
printf("Address out of bounds\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int32_t cell = addr / (int32_t)sizeof(int32_t);
|
||||||
|
int32_t byte = addr % (int32_t)sizeof(int32_t);
|
||||||
|
uint8_t* p = (uint8_t*)&user_mem[cell];
|
||||||
|
p[byte] = (uint8_t)val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_here(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
data_push((int32_t)(here - user_mem));
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_allot(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
int32_t n = data_pop();
|
||||||
|
here += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_variable(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
char* name = next_token();
|
||||||
|
if (name == NULL) {
|
||||||
|
printf("VARIABLE expects a name\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dict_idx >= DICT_SIZE) {
|
||||||
|
printf("Dictionary full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (body_idx >= BODY_SIZE) {
|
||||||
|
printf("Dictionary body storage full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Word* new_w = &dict[dict_idx++];
|
||||||
|
new_w->prev = dict_head;
|
||||||
|
dict_head = new_w;
|
||||||
|
|
||||||
|
size_t len = strlen(name);
|
||||||
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
|
new_w->flags = (uint8_t)len;
|
||||||
|
memcpy(new_w->name, name, len);
|
||||||
|
new_w->name[len] = '\0';
|
||||||
|
new_w->code = do_do_var;
|
||||||
|
|
||||||
|
// Allocate body cell to hold the address (cell index in user_mem)
|
||||||
|
new_w->body = &dict_bodies[body_idx++];
|
||||||
|
int32_t addr = (int32_t)(here - user_mem);
|
||||||
|
new_w->body->num = addr;
|
||||||
|
|
||||||
|
// Allocate one cell in user_mem
|
||||||
|
here++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_constant(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
int32_t val = data_pop();
|
||||||
|
char* name = next_token();
|
||||||
|
if (name == NULL) {
|
||||||
|
printf("CONSTANT expects a name\n");
|
||||||
|
data_push(val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dict_idx >= DICT_SIZE) {
|
||||||
|
printf("Dictionary full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (body_idx >= BODY_SIZE) {
|
||||||
|
printf("Dictionary body storage full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Word* new_w = &dict[dict_idx++];
|
||||||
|
new_w->prev = dict_head;
|
||||||
|
dict_head = new_w;
|
||||||
|
|
||||||
|
size_t len = strlen(name);
|
||||||
|
if (len > MAX_NAME_LEN) len = MAX_NAME_LEN;
|
||||||
|
new_w->flags = (uint8_t)len;
|
||||||
|
memcpy(new_w->name, name, len);
|
||||||
|
new_w->name[len] = '\0';
|
||||||
|
new_w->code = do_do_const;
|
||||||
|
|
||||||
|
// Allocate body cell to hold the constant value
|
||||||
|
new_w->body = &dict_bodies[body_idx++];
|
||||||
|
new_w->body->num = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_do_var(Word* w) {
|
||||||
|
data_push(w->body->num); // Push the user_mem cell index
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_do_const(Word* w) {
|
||||||
|
data_push(w->body->num); // Push the constant value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return stack operations
|
||||||
|
void do_to_r(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
int32_t val = data_pop();
|
||||||
|
ret_push_num(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_r_from(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
int32_t val = ret_pop_num();
|
||||||
|
data_push(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_r_fetch(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
if (rp < 0) {
|
||||||
|
printf("Return stack underflow\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data_push(ret_stack[rp].num);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Control flow: IF, ELSE, THEN, BEGIN, UNTIL, WHILE, REPEAT
|
||||||
|
void do_if(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
if (state != 1) {
|
||||||
|
printf("IF only valid in compile mode\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Word* zbranch = lookup_word("0branch");
|
||||||
|
if (zbranch == NULL) {
|
||||||
|
printf("Fatal: 0branch not found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (compile_idx + 2 > COMPILE_BUF_SIZE) {
|
||||||
|
printf("Compile buffer full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
compile_buf[compile_idx++] = (Cell){.word = zbranch};
|
||||||
|
compile_push((Cell*)&compile_buf[compile_idx]);
|
||||||
|
compile_idx++; // Reserve offset cell
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_then(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
if (state != 1) {
|
||||||
|
printf("THEN only valid in compile mode\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Cell* offset_addr = compile_pop();
|
||||||
|
if (offset_addr == NULL) return;
|
||||||
|
int32_t offset_idx = (int32_t)(offset_addr - compile_buf);
|
||||||
|
int32_t target_idx = compile_idx;
|
||||||
|
offset_addr->num = target_idx - offset_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_else(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
if (state != 1) {
|
||||||
|
printf("ELSE only valid in compile mode\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Cell* if_offset = compile_pop();
|
||||||
|
if (if_offset == NULL) return;
|
||||||
|
|
||||||
|
Word* branch_w = lookup_word("branch");
|
||||||
|
if (branch_w == NULL) {
|
||||||
|
printf("Fatal: branch not found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (compile_idx + 2 > COMPILE_BUF_SIZE) {
|
||||||
|
printf("Compile buffer full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve IF offset to jump to after this branch
|
||||||
|
int32_t if_offset_idx = (int32_t)(if_offset - compile_buf);
|
||||||
|
int32_t target_idx = compile_idx + 2; // after branch + its offset
|
||||||
|
if_offset->num = target_idx - if_offset_idx;
|
||||||
|
|
||||||
|
// Compile unconditional branch for ELSE part
|
||||||
|
compile_buf[compile_idx++] = (Cell){.word = branch_w};
|
||||||
|
compile_push((Cell*)&compile_buf[compile_idx]);
|
||||||
|
compile_idx++; // Reserve offset cell
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_begin(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
if (state != 1) {
|
||||||
|
printf("BEGIN only valid in compile mode\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
compile_push((Cell*)&compile_buf[compile_idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_until(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
if (state != 1) {
|
||||||
|
printf("UNTIL only valid in compile mode\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Cell* begin_addr = compile_pop();
|
||||||
|
if (begin_addr == NULL) return;
|
||||||
|
|
||||||
|
Word* zbranch = lookup_word("0branch");
|
||||||
|
if (zbranch == NULL) {
|
||||||
|
printf("Fatal: 0branch not found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (compile_idx + 2 > COMPILE_BUF_SIZE) {
|
||||||
|
printf("Compile buffer full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t begin_idx = (int32_t)(begin_addr - compile_buf);
|
||||||
|
compile_buf[compile_idx++] = (Cell){.word = zbranch};
|
||||||
|
int32_t offset_idx = compile_idx;
|
||||||
|
compile_buf[compile_idx++] = (Cell){.num = begin_idx - offset_idx};
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_while(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
if (state != 1) {
|
||||||
|
printf("WHILE only valid in compile mode\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Cell* begin_addr = compile_pop();
|
||||||
|
if (begin_addr == NULL) return;
|
||||||
|
|
||||||
|
Word* zbranch = lookup_word("0branch");
|
||||||
|
if (zbranch == NULL) {
|
||||||
|
printf("Fatal: 0branch not found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (compile_idx + 2 > COMPILE_BUF_SIZE) {
|
||||||
|
printf("Compile buffer full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
compile_buf[compile_idx++] = (Cell){.word = zbranch};
|
||||||
|
Cell* while_offset = (Cell*)&compile_buf[compile_idx];
|
||||||
|
compile_idx++; // Reserve offset cell
|
||||||
|
|
||||||
|
compile_push(while_offset);
|
||||||
|
compile_push(begin_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_repeat(Word* w) {
|
||||||
|
(void)w;
|
||||||
|
if (state != 1) {
|
||||||
|
printf("REPEAT only valid in compile mode\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Cell* begin_addr = compile_pop();
|
||||||
|
if (begin_addr == NULL) return;
|
||||||
|
Cell* while_offset = compile_pop();
|
||||||
|
if (while_offset == NULL) return;
|
||||||
|
|
||||||
|
Word* branch_w = lookup_word("branch");
|
||||||
|
if (branch_w == NULL) {
|
||||||
|
printf("Fatal: branch not found\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (compile_idx + 2 > COMPILE_BUF_SIZE) {
|
||||||
|
printf("Compile buffer full\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile backward branch to begin
|
||||||
|
int32_t begin_idx = (int32_t)(begin_addr - compile_buf);
|
||||||
|
compile_buf[compile_idx++] = (Cell){.word = branch_w};
|
||||||
|
int32_t offset_idx = compile_idx;
|
||||||
|
compile_buf[compile_idx++] = (Cell){.num = begin_idx - offset_idx};
|
||||||
|
|
||||||
|
// Resolve WHILE offset to point after this backward branch
|
||||||
|
int32_t while_offset_idx = (int32_t)(while_offset - compile_buf);
|
||||||
|
int32_t target_idx = compile_idx;
|
||||||
|
while_offset->num = target_idx - while_offset_idx;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ int main(void) {
|
|||||||
add_primitive("docolon", do_docolon, 1 << 6); // Hidden
|
add_primitive("docolon", do_docolon, 1 << 6); // Hidden
|
||||||
add_primitive("lit", do_lit, 1 << 6); // Hidden
|
add_primitive("lit", do_lit, 1 << 6); // Hidden
|
||||||
add_primitive("do_dot_quote_inner", do_dot_quote_inner, 1 << 6); // Hidden
|
add_primitive("do_dot_quote_inner", do_dot_quote_inner, 1 << 6); // Hidden
|
||||||
add_primitive("0branch", do_zero_branch, 1 << 6); // Hidden (for IF)
|
add_primitive("0branch", do_zero_branch, 1 << 6); // Hidden (for IF, UNTIL, WHILE)
|
||||||
add_primitive("branch", do_branch, 1 << 6); // Hidden (for ELSE, BEGIN)
|
add_primitive("branch", do_branch, 1 << 6); // Hidden (for ELSE, REPEAT)
|
||||||
|
|
||||||
// Public primitives
|
// Public primitives
|
||||||
// Stack ops
|
// Stack ops
|
||||||
@@ -64,9 +64,32 @@ int main(void) {
|
|||||||
add_primitive(".\"", do_dot_quote, 1 << 7); // Immediate
|
add_primitive(".\"", do_dot_quote, 1 << 7); // Immediate
|
||||||
add_primitive("words", do_words, 0);
|
add_primitive("words", do_words, 0);
|
||||||
|
|
||||||
// Compilation words
|
// Memory
|
||||||
|
add_primitive("@", do_fetch, 0);
|
||||||
|
add_primitive("!", do_store, 0);
|
||||||
|
add_primitive("+!", do_plus_store, 0);
|
||||||
|
add_primitive("c@", do_cfetch, 0);
|
||||||
|
add_primitive("c!", do_cstore, 0);
|
||||||
|
add_primitive("variable", do_variable, 0);
|
||||||
|
add_primitive("constant", do_constant, 0);
|
||||||
|
add_primitive("here", do_here, 0);
|
||||||
|
add_primitive("allot", do_allot, 0);
|
||||||
|
|
||||||
|
// Return stack
|
||||||
|
add_primitive(">r", do_to_r, 0);
|
||||||
|
add_primitive("r>", do_r_from, 0);
|
||||||
|
add_primitive("r@", do_r_fetch, 0);
|
||||||
|
|
||||||
|
// Compilation / control flow
|
||||||
add_primitive(":", do_colon, 0);
|
add_primitive(":", do_colon, 0);
|
||||||
add_primitive(";", do_semicolon, 1 << 7); // Immediate
|
add_primitive(";", do_semicolon, 1 << 7); // Immediate
|
||||||
|
add_primitive("if", do_if, 1 << 7); // Immediate
|
||||||
|
add_primitive("else", do_else, 1 << 7); // Immediate
|
||||||
|
add_primitive("then", do_then, 1 << 7); // Immediate
|
||||||
|
add_primitive("begin", do_begin, 1 << 7); // Immediate
|
||||||
|
add_primitive("until", do_until, 1 << 7); // Immediate
|
||||||
|
add_primitive("while", do_while, 1 << 7); // Immediate
|
||||||
|
add_primitive("repeat", do_repeat, 1 << 7); // Immediate
|
||||||
|
|
||||||
// Start outer interpreter
|
// Start outer interpreter
|
||||||
outer_interpreter();
|
outer_interpreter();
|
||||||
|
|||||||
Reference in New Issue
Block a user