dbf4eb5d0e
Co-authored-by: aider (openrouter/moonshotai/kimi-k2.6) <aider@aider.chat>
252 lines
5.9 KiB
C
252 lines
5.9 KiB
C
#ifndef FORTH_H
|
||
#define FORTH_H
|
||
|
||
#include <stdint.h>
|
||
#include <stddef.h>
|
||
#include <stdarg.h>
|
||
|
||
// Configuration (all hard limits removed)
|
||
#define MAX_NAME_LEN 31
|
||
#define FORTH_EOF (-1)
|
||
|
||
/* Platform interface -- must be provided by the target platform layer. */
|
||
void forth_putchar(char c);
|
||
int forth_getchar(void);
|
||
void forth_printf(const char* fmt, ...);
|
||
void forth_fflush(void);
|
||
void forth_panic(void);
|
||
|
||
/* Platform string-to-number (base 10 is required). */
|
||
int64_t forth_strtoll(const char* str, char** endptr, int base);
|
||
|
||
/* Portable character classification. */
|
||
static inline int forth_isspace(int c) {
|
||
return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v';
|
||
}
|
||
|
||
/* Portable string operations. */
|
||
static inline size_t forth_strlen(const char* s) {
|
||
size_t n = 0;
|
||
while (s[n]) n++;
|
||
return n;
|
||
}
|
||
|
||
static inline void forth_memcpy(void* dst, const void* src, size_t n) {
|
||
char* d = dst;
|
||
const char* s = src;
|
||
while (n--) *d++ = *s++;
|
||
}
|
||
|
||
static inline int forth_strcmp(const char* a, const char* b) {
|
||
while (*a && *a == *b) { a++; b++; }
|
||
return (unsigned char)*a - (unsigned char)*b;
|
||
}
|
||
|
||
/* Static memory sizes (override before including forth.h) */
|
||
#ifndef FORTH_DATA_STACK_SIZE
|
||
#define FORTH_DATA_STACK_SIZE 128
|
||
#endif
|
||
#ifndef FORTH_RET_STACK_SIZE
|
||
#define FORTH_RET_STACK_SIZE 128
|
||
#endif
|
||
#ifndef FORTH_COMPILE_STACK_SIZE
|
||
#define FORTH_COMPILE_STACK_SIZE 64
|
||
#endif
|
||
#ifndef FORTH_COMPILE_BUF_SIZE
|
||
#define FORTH_COMPILE_BUF_SIZE 256
|
||
#endif
|
||
#ifndef FORTH_USER_MEM_CELLS
|
||
#define FORTH_USER_MEM_CELLS (1024 * 1024)
|
||
#endif
|
||
#ifndef FORTH_MAX_WORDS
|
||
#define FORTH_MAX_WORDS 256
|
||
#endif
|
||
#ifndef FORTH_MAX_WORD_BODY_CELLS
|
||
#define FORTH_MAX_WORD_BODY_CELLS 4096
|
||
#endif
|
||
|
||
#define F_IMMEDIATE (1 << 7)
|
||
#define F_HIDDEN (1 << 6)
|
||
|
||
// Core types
|
||
typedef struct Word Word;
|
||
typedef union Cell {
|
||
Word* word;
|
||
int64_t num;
|
||
void* ptr; // used for return stack (holds Cell*)
|
||
} Cell;
|
||
|
||
struct Word {
|
||
Word* prev;
|
||
uint8_t flags; // Bit7=immediate, Bit6=hidden, Bits0-5=name length
|
||
char name[MAX_NAME_LEN + 1];
|
||
void (*code)(Word*);
|
||
Cell* body; // points to the word’s body (allocated dynamically)
|
||
};
|
||
|
||
// Globals (all dynamic)
|
||
extern int64_t *data_stack;
|
||
extern int32_t data_sp; // stack indices are small enough for int32_t
|
||
extern int32_t data_cap;
|
||
|
||
extern Cell *ret_stack;
|
||
extern int32_t rp;
|
||
extern int32_t ret_cap;
|
||
extern Cell* ip; // instruction pointer
|
||
|
||
extern Word* dict_head;
|
||
|
||
extern int state;
|
||
extern Cell *compile_buf;
|
||
extern int32_t compile_idx;
|
||
extern int32_t compile_cap;
|
||
extern char compiling_name[MAX_NAME_LEN + 1];
|
||
|
||
extern char* input_buf; // line buffer (dynamic, managed by getline)
|
||
extern size_t input_buf_cap;
|
||
extern char* input_ptr;
|
||
|
||
extern int64_t *compile_stack; // holds indices into compile_buf
|
||
extern int32_t compile_sp;
|
||
extern int32_t compile_stack_cap;
|
||
|
||
extern Cell *user_mem;
|
||
extern int64_t user_mem_size; // in cells
|
||
extern Cell* here;
|
||
|
||
// Pointers to critical hidden/primitive words (set during init)
|
||
extern Word* w_exit;
|
||
extern Word* w_docolon;
|
||
extern Word* w_lit;
|
||
extern Word* w_branch;
|
||
extern Word* w_zbranch;
|
||
extern Word* w_dot_quote_inner;
|
||
|
||
// Entry point
|
||
void forth_run(void);
|
||
|
||
// Core function prototypes
|
||
void data_push(int64_t val);
|
||
int64_t data_pop(void);
|
||
void ret_push_ip(Cell* val);
|
||
Cell* ret_pop_ip(void);
|
||
void ret_push_num(int64_t val);
|
||
int64_t ret_pop_num(void);
|
||
void compile_push(int64_t idx);
|
||
int64_t compile_pop(void);
|
||
|
||
Word* add_primitive(const char* name, void (*code)(Word*), uint8_t flags);
|
||
Word* lookup_word(const char* name);
|
||
Word* lookup_word_internal(const char* name);
|
||
|
||
char* next_token(void);
|
||
void inner_interpreter(void);
|
||
void process_token(const char* token);
|
||
void outer_interpreter(void);
|
||
|
||
// Ensure compile_buf has at least 'needed' free cells (returns 0 on overflow)
|
||
int ensure_compile_cap(int32_t needed);
|
||
|
||
Word* forth_alloc_word(void);
|
||
Cell* forth_alloc_body(int32_t cells);
|
||
|
||
// Stack ops
|
||
void do_dup(Word* w);
|
||
void do_drop(Word* w);
|
||
void do_swap(Word* w);
|
||
void do_over(Word* w);
|
||
void do_rot(Word* w);
|
||
void do_minus_rot(Word* w);
|
||
void do_nip(Word* w);
|
||
void do_tuck(Word* w);
|
||
|
||
// Arithmetic
|
||
void do_add(Word* w);
|
||
void do_sub(Word* w);
|
||
void do_mul(Word* w);
|
||
void do_div(Word* w);
|
||
void do_mod(Word* w);
|
||
void do_slash_mod(Word* w);
|
||
void do_one_plus(Word* w);
|
||
void do_one_minus(Word* w);
|
||
void do_two_plus(Word* w);
|
||
void do_two_minus(Word* w);
|
||
void do_negate(Word* w);
|
||
void do_abs(Word* w);
|
||
void do_min(Word* w);
|
||
void do_max(Word* w);
|
||
|
||
// Logic
|
||
void do_and(Word* w);
|
||
void do_or(Word* w);
|
||
void do_xor(Word* w);
|
||
void do_invert(Word* w);
|
||
void do_lshift(Word* w);
|
||
void do_rshift(Word* w);
|
||
|
||
// Comparison
|
||
void do_eq(Word* w);
|
||
void do_neq(Word* w);
|
||
void do_lt(Word* w);
|
||
void do_gt(Word* w);
|
||
void do_lte(Word* w);
|
||
void do_gte(Word* w);
|
||
void do_zero_eq(Word* w);
|
||
void do_zero_lt(Word* w);
|
||
void do_zero_gt(Word* w);
|
||
|
||
// I/O
|
||
void do_dot(Word* w);
|
||
void do_cr(Word* w);
|
||
void do_emit(Word* w);
|
||
void do_key(Word* w);
|
||
void do_dot_quote(Word* w);
|
||
void do_dot_quote_inner(Word* w);
|
||
void do_words(Word* w);
|
||
|
||
// Memory
|
||
void do_fetch(Word* w);
|
||
void do_store(Word* w);
|
||
void do_plus_store(Word* w);
|
||
void do_cfetch(Word* w);
|
||
void do_cstore(Word* w);
|
||
void do_variable(Word* w);
|
||
void do_constant(Word* w);
|
||
void do_do_var(Word* w);
|
||
void do_do_const(Word* w);
|
||
void do_here(Word* w);
|
||
void do_allot(Word* w);
|
||
void do_comma(Word* w);
|
||
|
||
// Return stack
|
||
void do_to_r(Word* w);
|
||
void do_r_from(Word* w);
|
||
void do_r_fetch(Word* w);
|
||
|
||
// Control flow
|
||
void do_exit(Word* w);
|
||
void do_docolon(Word* w);
|
||
void do_lit(Word* w);
|
||
void do_colon(Word* w);
|
||
void do_semicolon(Word* w);
|
||
void do_branch(Word* w);
|
||
void do_zero_branch(Word* w);
|
||
void do_if(Word* w);
|
||
void do_else(Word* w);
|
||
void do_then(Word* w);
|
||
void do_begin(Word* w);
|
||
void do_until(Word* w);
|
||
void do_while(Word* w);
|
||
void do_repeat(Word* w);
|
||
|
||
/* Additional stack words */
|
||
void do_depth(Word* w);
|
||
void do_pick(Word* w);
|
||
void do_roll(Word* w);
|
||
void do_qdup(Word* w);
|
||
void do_2dup(Word* w);
|
||
void do_2drop(Word* w);
|
||
void do_2swap(Word* w);
|
||
|
||
#endif
|