Files
forth_bootslop/attempt_1/main.c.bak
2026-02-21 12:11:39 -05:00

889 lines
29 KiB
C

#include "duffle.amd64.win32.h"
// --- Semantic Tags (Using X-Macros & Enum_) ---
#define Tag_Entries() \
X(Define, "Define", 0x0018AEFF, ":") \
X(Call, "Call", 0x00D6A454, "~") \
X(Data, "Data", 0x0094BAA1, "$") \
X(Imm, "Imm", 0x004AA4C2, "^") \
X(Comment, "Comment", 0x00AAAAAA, ".") \
X(Format, "Format", 0x003A2F3B, " ")
typedef Enum_(U4, STag) {
#define X(n, s, c, p) tmpl(STag, n),
Tag_Entries()
#undef X
STag_Count,
};
global U4 tag_colors[] = {
#define X(n, s, c, p) c,
Tag_Entries()
#undef X
};
global const char* tag_prefixes[] = {
#define X(n, s, c, p) p,
Tag_Entries()
#undef X
};
global const char* tag_names[] = {
#define X(n, s, c, p) s,
Tag_Entries()
#undef X
};
#define pack_token(tag, val) ((u4_(tag) << 28) | (u4_(val) & 0x0FFFFFFF))
#define unpack_tag(token) ( ((token) >> 28) & 0x0F)
#define unpack_val(token) ( (token) & 0x0FFFFFFF)
#define TOKENS_PER_ROW 8
#define MODE_NAV 0
#define MODE_EDIT 1
global FArena tape_arena;
global FArena anno_arena;
global U8 cursor_idx = 0;
global U4 editor_mode = MODE_NAV;
global B4 mode_switch_now = false;
global FArena code_arena;
global U8 vm_rax = 0;
global U8 vm_rdx = 0;
global U8 vm_globals[16] = {0};
global B4 run_full = false;
global U8 log_buffer[16] = {0};
global U4 log_count = 0;
global S4 scroll_y_offset = 0;
// New GDI log
#define GDI_LOG_MAX_LINES 10
#define GDI_LOG_MAX_LINE_LEN 128
global char gdi_log_buffer[GDI_LOG_MAX_LINES][GDI_LOG_MAX_LINE_LEN] = {0};
global U4 gdi_log_count = 0;
internal void debug_log(Str8 fmt, KTL_Str8 table) {
// A static buffer for our log lines.
LP_ UTF8 console_log_buffer[1024];
mem_zero(u8_(console_log_buffer), 1024);
// Format the string.
Str8 result = str8_fmt_ktl_buf(slice_ut_arr(console_log_buffer), table, fmt);
// Also write to our GDI log buffer
if (gdi_log_count < GDI_LOG_MAX_LINES) {
U4 len_to_copy = result.len < GDI_LOG_MAX_LINE_LEN - 1 ? result.len : GDI_LOG_MAX_LINE_LEN - 1;
mem_copy(u8_(gdi_log_buffer[gdi_log_count]), u8_(result.ptr), len_to_copy);
gdi_log_buffer[gdi_log_count][len_to_copy] = '\0';
gdi_log_count++;
}
// Get stdout handle.
MS_Handle stdout_handle = ms_get_std_handle(MS_STD_OUTPUT);
// Write the formatted string.
ms_write_console(stdout_handle, result.ptr, (U4)result.len, nullptr, 0);
// Write a newline.
ms_write_console(stdout_handle, (UTF8 const*r)"\n", 1, nullptr, 0);
}
U8 ms_builtin_print(U8 val, U8 rdx_val, U8 r8_val, U8 r9_val) {
char hex1[9], hex2[9], hex3[9], hex4[9];
u64_to_hex(val, hex1, 8); hex1[8] = '\0';
u64_to_hex(rdx_val, hex2, 8); hex2[8] = '\0';
u64_to_hex(r8_val, hex3, 8); hex3[8] = '\0';
u64_to_hex(r9_val, hex4, 8); hex4[8] = '\0';
KTL_Slot_Str8 log_table[] = {
{ ktl_str8_key("v1"), str8(hex1) },
{ ktl_str8_key("v2"), str8(hex2) },
{ ktl_str8_key("v3"), str8(hex3) },
{ ktl_str8_key("v4"), str8(hex4) },
};
debug_log(str8("FFI PRINT -> RCX:<v1> RDX:<v2> R8:<v3> R9:<v4>"), ktl_str8_from_arr(log_table));
if (log_count < 16) log_buffer[log_count++] = val;
return val;
}
// Visual Linker & O(1) Dictionary
global U4 tape_to_code_offset[65536] = {0};
// --- WinAPI Persistence ---
#define MS_GENERIC_READ 0x80000000
#define MS_GENERIC_WRITE 0x40000000
#define MS_CREATE_ALWAYS 2
#define MS_OPEN_EXISTING 3
#define MS_FILE_ATTRIBUTE_NORMAL 0x80
#define MS_VK_F1 0x70
#define MS_VK_F2 0x71
WinAPI void* ms_create_file_a(char const* lpFileName, U4 dwDesiredAccess, U4 dwShareMode, void* lpSecurityAttributes, U4 dwCreationDisposition, U4 dwFlagsAndAttributes, void* hTemplateFile) asm("CreateFileA");
WinAPI B4 ms_write_file(void* hFile, void const* lpBuffer, U4 nNumberOfBytesToWrite, U4* lpNumberOfBytesWritten, void* lpOverlapped) asm("WriteFile");
WinAPI B4 ms_read_file(void* hFile, void* lpBuffer, U4 nNumberOfBytesToRead, U4* lpNumberOfBytesRead, void* lpOverlapped) asm("ReadFile");
WinAPI B4 ms_close_handle(void* hObject) asm("CloseHandle");
#define PRIM_SWAP 1
#define PRIM_MULT 2
#define PRIM_ADD 3
#define PRIM_FETCH 4
#define PRIM_DEC 5
#define PRIM_STORE 6
#define PRIM_RET_Z 7
#define PRIM_RET 8
#define PRIM_PRINT 9
#define PRIM_RET_S 10
#define PRIM_DUP 11
#define PRIM_DROP 12
#define PRIM_SUB 13
global const char* prim_names[] = {
"",
"SWAP ",
"MULT ",
"ADD ",
"FETCH ",
"DEC ",
"STORE ",
"RET_IF_Z",
"RETURN ",
"PRINT ",
"RET_IF_S",
"DUP ",
"DROP ",
"SUB "
};
internal U4 resolve_name_to_index(const char* ref_name);
internal void relink_tape(void);
IA_ void compile_and_run_tape(void);
internal void save_cartridge(void) {
void* hFile = ms_create_file_a("cartridge.bin", MS_GENERIC_WRITE, 0, nullptr, MS_CREATE_ALWAYS, MS_FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile != (void*)-1) {
U4 written = 0;
ms_write_file(hFile, & tape_arena.used, 8, & written, nullptr);
ms_write_file(hFile, & anno_arena.used, 8, & written, nullptr);
ms_write_file(hFile, & cursor_idx, 8, & written, nullptr);
ms_write_file(hFile, (void*)tape_arena.start, (U4)tape_arena.used, & written, nullptr);
ms_write_file(hFile, (void*)anno_arena.start, (U4)anno_arena.used, & written, nullptr);
ms_close_handle(hFile);
}
}
internal void load_cartridge(void) {
void* hFile = ms_create_file_a("cartridge.bin", MS_GENERIC_READ, 0, nullptr, MS_OPEN_EXISTING, MS_FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile != (void*)-1) {
U4 read = 0;
ms_read_file(hFile, & tape_arena.used, 8, & read, nullptr);
ms_read_file(hFile, & anno_arena.used, 8, & read, nullptr);
ms_read_file(hFile, & cursor_idx, 8, & read, nullptr);
ms_read_file(hFile, (void*)tape_arena.start, (U4)tape_arena.used, & read, nullptr);
ms_read_file(hFile, (void*)anno_arena.start, (U4)anno_arena.used, & read, nullptr);
ms_close_handle(hFile);
relink_tape();
compile_and_run_tape();
}
}
IA_ void scatter(U4 token, const char* anno_str) {
if (tape_arena.used + sizeof(U4) <= tape_arena.capacity && anno_arena.used + sizeof(U8) <= anno_arena.capacity) {
U4 tag = unpack_tag(token);
U4 val = unpack_val(token);
if (anno_str && (tag == STag_Call || tag == STag_Imm)) {
val = resolve_name_to_index(anno_str);
}
U4*r ptr = u4_r(tape_arena.start + tape_arena.used);
ptr[0] = pack_token(tag, val);
tape_arena.used += sizeof(U4);
U8*r aptr = u8_r(anno_arena.start + anno_arena.used);
aptr[0] = 0;
if (anno_str) {
char* dest = (char*)aptr;
int i = 0; while(i < 8 && anno_str[i]) { dest[i] = anno_str[i]; i ++; }
}
anno_arena.used += sizeof(U8);
}
}
internal void emit8(U1 b) {
if (code_arena.used + 1 <= code_arena.capacity) {
u1_r(code_arena.start + code_arena.used)[0] = b;
code_arena.used += 1;
}
}
internal void emit32(U4 val) {
if (code_arena.used + 4 <= code_arena.capacity) {
u4_r(code_arena.start + code_arena.used)[0] = val;
code_arena.used += 4;
}
}
internal void pad32(void) {
while ((code_arena.used % 4) != 0) emit8(0x90);
}
internal U4 resolve_name_to_index(const char* ref_name) {
U8 tape_count = tape_arena.used / sizeof(U4);
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
U8 prim_count = array_len(prim_names);
for (int p = 1; p < prim_count; p++) {
int match = 1;
for (int c = 0; c < 8; c++) {
char c1 = ref_name[c] ? ref_name[c] : ' ';
char c2 = prim_names[p][c] ? prim_names[p][c] : ' ';
if (c1 != c2) { match = 0; break; }
}
if (match) return p + 0x10000;
}
for (U8 j = 0; j < tape_count; j++) {
if (unpack_tag(tape_ptr[j]) == STag_Define) {
char* def_name = (char*)&anno_ptr[j];
int match = 1;
for (int c = 0; c < 8; c++) {
char c1 = ref_name[c] ? ref_name[c] : ' ';
char c2 = def_name[c] ? def_name[c] : ' ';
if (c1 != c2) { match = 0; break; }
}
if (match) return j;
}
}
return 0;
}
internal void relink_tape(void) {
U8 tape_count = tape_arena.used / sizeof(U4);
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
for (U8 i = 0; i < tape_count; i++) {
U4 t = tape_ptr[i];
U4 tag = unpack_tag(t);
if (tag == STag_Call || tag == STag_Imm) {
char* ref_name = (char*)&anno_ptr[i];
U4 new_val = resolve_name_to_index(ref_name);
tape_ptr[i] = pack_token(tag, new_val);
}
}
}
internal void compile_action(U4 val)
{
if (val >= 0x10000) {
U4 p = val - 0x10000;
if (p == PRIM_SWAP) {
emit8(0x48); emit8(0x87); emit8(0xC2);
pad32();
return;
} else if (p == PRIM_MULT) {
emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2);
pad32();
return;
} else if (p == PRIM_ADD) {
emit8(0x48); emit8(0x01); emit8(0xD0);
pad32();
return;
} else if (p == PRIM_SUB) {
emit8(0x48); emit8(0x29); emit8(0xD0);
pad32();
return;
} else if (p == PRIM_FETCH) {
emit8(0x48); emit8(0x8B); emit8(0x04); emit8(0xC3); // mov rax, [rbx + rax*8]
pad32();
return;
} else if (p == PRIM_DEC) {
emit8(0x48); emit8(0xFF); emit8(0xC8);
pad32();
return;
} else if (p == PRIM_STORE) {
emit8(0x48); emit8(0x89); emit8(0x14); emit8(0xC3); // mov [rbx + rax*8], rdx
pad32();
return;
} else if (p == PRIM_RET_Z) {
emit8(0x48); emit8(0x85); emit8(0xC0);
emit8(0x75); emit8(0x01);
emit8(0xC3);
pad32();
return;
} else if (p == PRIM_RET_S) {
emit8(0x48); emit8(0x85); emit8(0xC0);
emit8(0x79); emit8(0x01);
emit8(0xC3);
pad32();
return;
} else if (p == PRIM_RET) {
emit8(0xC3);
pad32();
return;
} else if (p == PRIM_DUP) {
emit8(0x48); emit8(0x89); emit8(0xC2);
pad32();
return;
} else if (p == PRIM_DROP) {
emit8(0x48); emit8(0x89); emit8(0xD0);
pad32();
return;
} else if (p == PRIM_PRINT) {
// FFI Dance: Save RDX, Align RSP (32 shadow + 8 align = 40)
emit8(0x52); // push rdx
emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x28); // sub rsp, 40
// Map arguments: RCX=RAX, RDX=RDX(already loaded), R8=Globals[0], R9=Globals[1]
emit8(0x48); emit8(0x89); emit8(0xC1); // mov rcx, rax
emit8(0x4C); emit8(0x8B); emit8(0x03); // mov r8, [rbx]
emit8(0x4C); emit8(0x8B); emit8(0x4B); emit8(0x08); // mov r9, [rbx+8]
// Load func ptr and call
emit8(0x49); emit8(0xBA); // mov r10, ...
U8 addr = u8_(& ms_builtin_print);
emit32(u4_(addr & 0xFFFFFFFF));
emit32(u4_(addr >> 32));
emit8(0x41); emit8(0xFF); emit8(0xD2); // call r10
// Restore
emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x28); // add rsp, 40
emit8(0x5A); // pop rdx
pad32();
return;
}
}
if (val > 0 && val < 0x10000) {
U4 target = tape_to_code_offset[val];
pad32();
S4 rel32 = s4_(target) - s4_(code_arena.used + 5);
emit8(0xE8);
emit32(u4_(rel32));
pad32();
}
}
IA_ void compile_and_run_tape(void)
{
farena_reset(& code_arena);
log_count = 0;
gdi_log_count = 0;
emit8(0x53); // push rbx (callee-saved; also aligns RSP to 0 mod 16)
emit8(0x48); emit8(0x89); emit8(0xCB); // mov rbx, rcx (stable globals ptr for whole JIT session)
emit8(0x48); emit8(0x8B); emit8(0x43); emit8(0x70); // mov rax, [rbx+0x70]
emit8(0x48); emit8(0x8B); emit8(0x53); emit8(0x78); // mov rdx, [rbx+0x78]
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
B4 in_def = false;
U4 def_jmp_offset = 0;
U8 end_idx = run_full ? (tape_arena.used / sizeof(U4)) : (cursor_idx + 1);
for (U8 i = 0; i < end_idx; i++)
{
U4 tag = unpack_tag(tape_ptr[i]);
U4 val = unpack_val(tape_ptr[i]);
if (tag == STag_Define)
{
if (in_def == false) {
pad32();
emit8(0xE9);
def_jmp_offset = code_arena.used;
emit32(0);
pad32();
in_def = true;
} else {
emit8(0xC3);
pad32();
}
tape_to_code_offset[i] = code_arena.used;
emit8(0x48); emit8(0x87); emit8(0xC2);
pad32();
}
else if (tag == STag_Call || tag == STag_Imm)
{
char* name = (char*)&anno_ptr[i];
char val_hex[9];
u64_to_hex(val, val_hex, 8);
val_hex[8] = '\0';
KTL_Slot_Str8 call_log_table[] = {
{ ktl_str8_key("name"), str8(name) },
{ ktl_str8_key("val"), str8(val_hex) },
};
debug_log(str8("Compiling call: <name> (val: <val>)"), ktl_str8_from_arr(call_log_table));
if (tag == STag_Imm && in_def) {
emit8(0xC3);
pad32();
U4 current = code_arena.used;
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
in_def = false;
}
compile_action(val);
}
else if (tag == STag_Data) {
emit8(0x48); emit8(0x89); emit8(0xC2);
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val);
pad32();
}
}
if (in_def) {
emit8(0xC3);
pad32();
U4 current = code_arena.used;
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
}
emit8(0x48); emit8(0x89); emit8(0x43); emit8(0x70); // mov [rbx+0x70], rax
emit8(0x48); emit8(0x89); emit8(0x53); emit8(0x78); // mov [rbx+0x78], rdx
emit8(0x5B); // pop rbx
emit8(0xC3); // ret
typedef void JIT_Func(U8* globals_ptr);
JIT_Func* func = (JIT_Func*)code_arena.start;
func(vm_globals);
vm_rax = vm_globals[14];
vm_rdx = vm_globals[15];
char rax_hex[9];
u64_to_hex(vm_rax, rax_hex, 8);
rax_hex[8] = '\0';
char rdx_hex[9];
u64_to_hex(vm_rdx, rdx_hex, 8);
rdx_hex[8] = '\0';
KTL_Slot_Str8 post_jit_log_table[] = {
{ ktl_str8_key("rax"), str8(rax_hex) },
{ ktl_str8_key("rdx"), str8(rdx_hex) },
};
debug_log(str8("JIT finished. RAX: <rax>, RDX: <rdx>"), ktl_str8_from_arr(post_jit_log_table));
}
S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
{
U8 tape_count = tape_arena.used / sizeof(U4);
U4*r tape_ptr = u4_r(tape_arena.start);
switch (msg) {
case MS_WM_CHAR: {
if (editor_mode != MODE_EDIT) return 0;
U4 t = tape_ptr[cursor_idx];
U4 tag = unpack_tag(t);
U4 val = unpack_val(t);
U1 c = u1_(wparam);
B4 should_skip = c < 32 || (c == 'e' && mode_switch_now);
if (should_skip) { mode_switch_now = false; return 0; }
if (tag == STag_Data) {
U4 digit = 16;
if (c >= '0' && c <= '9') digit = c - '0';
if (c >= 'a' && c <= 'f') digit = c - 'a' + 10;
if (c >= 'A' && c <= 'F') digit = c - 'A' + 10;
if (digit < 16) {
val = ((val << 4) | digit) & 0x0FFFFFFF;
tape_ptr[cursor_idx] = pack_token(tag, val);
}
}
else if (tag != STag_Format) {
U8*r anno_ptr = u8_r(anno_arena.start);
char* anno_str = (char*) & anno_ptr[cursor_idx];
int len = 0;
while (len < 8 && anno_str[len] != '\0' && anno_str[len] != ' ') len ++;
if (len < 8) {
anno_str[len] = (char)c;
for (int i = len + 1; i < 8; i++) anno_str[i] = '\0';
if (tag == STag_Call || tag == STag_Imm || tag == STag_Define) {
U4 new_val = resolve_name_to_index(anno_str);
tape_ptr[cursor_idx] = pack_token(tag, new_val);
if (tag == STag_Define) relink_tape();
}
}
}
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
compile_and_run_tape();
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_KEYDOWN: {
if (wparam == 0x45 && editor_mode == MODE_NAV) {
editor_mode = MODE_EDIT;
mode_switch_now = true;
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
if (wparam == 0x1B && editor_mode == MODE_EDIT) {
editor_mode = MODE_NAV;
relink_tape();
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
if (editor_mode == MODE_EDIT) {
if (wparam == MS_VK_BACK) {
U4 t = tape_ptr[cursor_idx];
U4 tag = unpack_tag(t);
U4 val = unpack_val(t);
if (tag == STag_Data) {
val = val >> 4;
tape_ptr[cursor_idx] = pack_token(tag, val);
}
else if (tag != STag_Format) {
U8*r anno_ptr = u8_r(anno_arena.start);
char* anno_str = (char*) & anno_ptr[cursor_idx];
int len = 0;
while (len < 8 && anno_str[len] != '\0' && anno_str[len] != ' ') len ++;
if (len > 0) {
anno_str[len - 1] = '\0';
if (tag == STag_Call || tag == STag_Imm || tag == STag_Define) {
U4 new_val = resolve_name_to_index(anno_str);
tape_ptr[cursor_idx] = pack_token(tag, new_val);
if (tag == STag_Define) relink_tape();
}
}
}
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
compile_and_run_tape();
ms_invalidate_rect(hwnd, nullptr, true);
}
return 0;
}
if (wparam == MS_VK_RIGHT && cursor_idx < tape_count - 1) cursor_idx ++;
if (wparam == MS_VK_LEFT && cursor_idx > 0) cursor_idx --;
if (wparam == MS_VK_UP) {
U8 line_start = cursor_idx;
while (line_start > 0 && unpack_tag(tape_ptr[line_start - 1]) != STag_Format) line_start--;
if (line_start > 0) {
U8 col = cursor_idx - line_start;
U8 prev_line_start = line_start - 1;
while (prev_line_start > 0 && unpack_tag(tape_ptr[prev_line_start - 1]) != STag_Format) prev_line_start--;
U8 prev_line_len = (line_start - 1) - prev_line_start;
cursor_idx = prev_line_start + (col < prev_line_len ? col : prev_line_len);
}
}
if (wparam == MS_VK_DOWN) {
U8 line_start = cursor_idx;
while (line_start > 0 && unpack_tag(tape_ptr[line_start - 1]) != STag_Format) line_start --;
U8 col = cursor_idx - line_start;
U8 next_line_start = cursor_idx;
while (next_line_start < tape_count && unpack_tag(tape_ptr[next_line_start]) != STag_Format) next_line_start ++;
if (next_line_start < tape_count) {
next_line_start ++;
U8 next_line_end = next_line_start;
while (next_line_end < tape_count && unpack_tag(tape_ptr[next_line_end]) != STag_Format) next_line_end ++;
U8 next_line_len = next_line_end - next_line_start;
cursor_idx = next_line_start + (col < next_line_len ? col : next_line_len);
}
}
if (wparam == MS_VK_PRIOR) { scroll_y_offset -= 100; if (scroll_y_offset < 0) scroll_y_offset = 0; }
if (wparam == MS_VK_NEXT) { scroll_y_offset += 100; }
if (wparam == MS_VK_F5) { run_full = !run_full; }
if (wparam == MS_VK_F1) { save_cartridge(); }
if (wparam == MS_VK_F2) { load_cartridge(); ms_invalidate_rect(hwnd, nullptr, true); }
if (wparam == MS_VK_TAB) {
U4 t = tape_ptr[cursor_idx];
U4 tag = (unpack_tag(t) + 1) % STag_Count;
tape_ptr[cursor_idx] = pack_token(tag, unpack_val(t));
}
else if (wparam == MS_VK_BACK)
{
U8 delete_idx = cursor_idx;
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
if (is_shift == false) {
if (cursor_idx > 0) {
delete_idx = cursor_idx - 1;
cursor_idx--;
}
else return 0;
}
if (tape_count > 0) {
U8*r anno_ptr = u8_r(anno_arena.start);
for (U8 i = delete_idx; i < tape_count - 1; i ++) {
tape_ptr[i] = tape_ptr[i + 1];
anno_ptr[i] = anno_ptr[i + 1];
}
tape_arena.used -= sizeof(U4);
anno_arena.used -= sizeof(U8);
}
relink_tape();
}
else if (wparam == MS_VK_SPACE || wparam == MS_VK_RETURN) {
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
U8 insert_idx = cursor_idx;
if (is_shift) insert_idx ++;
if (tape_arena.used + sizeof(U4) <= tape_arena.capacity && anno_arena.used + sizeof(U8) <= anno_arena.capacity) {
U8*r anno_ptr = u8_r(anno_arena.start);
for (U8 i = tape_count; i > insert_idx; i --) {
tape_ptr[i] = tape_ptr[i-1];
anno_ptr[i] = anno_ptr[i-1];
}
if (wparam == MS_VK_RETURN) {
tape_ptr[insert_idx] = pack_token(STag_Format, 0xA);
anno_ptr[insert_idx] = 0;
} else {
tape_ptr[insert_idx] = pack_token(STag_Comment, 0);
anno_ptr[insert_idx] = 0;
}
if (is_shift) cursor_idx ++;
tape_arena.used += sizeof(U4);
anno_arena.used += sizeof(U8);
}
}
vm_rax = 0; vm_rdx = 0;
mem_zero(u8_(vm_globals), sizeof(vm_globals));
compile_and_run_tape();
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_PAINT: {
MS_PAINTSTRUCT ps;
void* hdc = ms_begin_paint(hwnd, & ps);
void* hFont = ms_create_font_a(20, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Consolas");
void* hOldFont = ms_select_object(hdc, hFont);
ms_set_bk_mode(hdc, 1);
void* hBgBrush = ms_create_solid_brush(0x00222222);
ms_select_object(hdc, hBgBrush);
ms_rectangle(hdc, -1, -1, 3000, 3000);
void* hBrushEdit = ms_create_solid_brush(0x008E563B);
void* hBrushNav = ms_create_solid_brush(0x00262F3B);
S4 start_x = 40, start_y = 60, spacing_x = 110, spacing_y = 35;
S4 x = start_x, y = start_y;
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
for (U8 i = 0; i < tape_count; i++)
{
if (x >= start_x + (TOKENS_PER_ROW * spacing_x)) {
x = start_x; y += spacing_y;
}
S4 render_y = y - scroll_y_offset;
if (i == cursor_idx && render_y >= 30 && render_y < 500) {
ms_select_object(hdc, editor_mode == MODE_EDIT ? hBrushEdit : hBrushNav);
ms_rectangle(hdc, x - 5, render_y - 2, x + 95, render_y + 22);
}
if (render_y >= 30 && render_y < 500)
{
U4 t = tape_ptr[i];
U4 tag = unpack_tag(t);
U4 val = unpack_val(t);
U8 anno = anno_ptr[i];
if (tag == STag_Format && val == 0xA) {
ms_set_text_color(hdc, 0x00444444);
ms_text_out_a(hdc, x, render_y, " \\n ", 6);
x = start_x;
y += spacing_y;
}
else
{
U4 color = tag_colors[tag];
const char* prefix = tag_prefixes[tag];
ms_set_text_color(hdc, color);
if (editor_mode == MODE_EDIT && i == cursor_idx) {
ms_set_text_color(hdc, 0x001E1E1E);
}
char val_str[9];
if (tag == STag_Data) {
u64_to_hex(val, val_str, 6);
val_str[6] = '\0';
}
else
{
char* a_str = (char*) & anno;
for(int c=0; c<8; c++) {
val_str[c] = a_str[c] ? a_str[c] : ' ';
}
val_str[8] = '\0';
}
char out_buf[12];
out_buf[0] = prefix[0];
out_buf[1] = ' ';
mem_copy(u8_(out_buf + 2), u8_(val_str), 8);
out_buf[10] = '\0';
ms_text_out_a(hdc, x, render_y, out_buf, 10);
x += spacing_x;
}
}
else if (unpack_tag(tape_ptr[i]) == STag_Format && unpack_val(tape_ptr[i]) == 0xA) {
x = start_x;
y += spacing_y;
}
else {
x += spacing_x;
}
}
void* hHudBrush = ms_create_solid_brush(0x00141E23);
ms_select_object(hdc, hHudBrush);
ms_rectangle(hdc, -1, 500, 3000, 3000);
ms_rectangle(hdc, -1, -1, 3000, 40);
ms_set_text_color(hdc, 0x00AAAAAA);
ms_text_out_a(hdc, 40, 10, "x86-64 Machine Code Emitter | 2-Reg Stack | [F5] Toggle Run Mode | [PgUp/PgDn] Scroll", 85);
ms_set_text_color(hdc, 0x00FFFFFF);
char jit_str[64] = "Mode: Incremental | JIT Size: 0x000 bytes";
if (run_full) mem_copy(u8_(jit_str + 6), u8_("Full "), 11);
u64_to_hex(code_arena.used, jit_str + 32, 3);
ms_text_out_a(hdc, 40, 520, jit_str, 41);
char state_str[64] = "RAX: 00000000 | RDX: 00000000";
u64_to_hex(vm_rax, state_str + 5, 8);
u64_to_hex(vm_rdx, state_str + 21, 8);
ms_set_text_color(hdc, 0x0094BAA1);
ms_text_out_a(hdc, 40, 550, state_str, 29);
if (tape_count > 0 && cursor_idx < tape_count) {
U4 cur_tag = unpack_tag(tape_ptr[cursor_idx]);
const char* tag_name = tag_names [cur_tag];
U4 cur_color = tag_colors[cur_tag];
char semantics_str[64] = "Current Tag: ";
U4 name_len = 0;
while (tag_name[name_len]) {
semantics_str[13 + name_len] = tag_name[name_len];
name_len ++;
}
semantics_str[13 + name_len] = '\0';
ms_set_text_color(hdc, cur_color);
ms_text_out_a(hdc, 40, 580, semantics_str, 13 + name_len);
}
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 400, 520, "Global Memory (Contiguous Array):", 33);
for (int i=0; i < 4; i ++) {
char glob_str[32] = "[0]: 00000000";
glob_str[1] = '0' + i;
u64_to_hex(vm_globals[i], glob_str + 5, 8);
ms_set_text_color(hdc, 0x00D6A454);
ms_text_out_a(hdc, 400, 550 + (i * 25), glob_str, 13);
}
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 750, 520, "Print Log:", 10);
for (int i = 0; i<log_count && i < 4; i ++) {
char log_str[32] = "00000000";
u64_to_hex(log_buffer[i], log_str, 8);
ms_set_text_color(hdc, 0x0094BAA1);
ms_text_out_a(hdc, 750, 550 + (i * 25), log_str, 8);
}
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 40, 650, "Debug Log:", 10);
for (U4 i = 0; i < gdi_log_count; i++) {
U4 len = 0;
while(gdi_log_buffer[i][len] != '\0' && len < GDI_LOG_MAX_LINE_LEN) {
len++;
}
ms_set_text_color(hdc, 0x00AAAAAA);
ms_text_out_a(hdc, 40, 670 + (i * 20), gdi_log_buffer[i], len);
}
ms_select_object(hdc, hOldFont);
ms_delete_object(hBgBrush);
ms_delete_object(hBrushEdit);
ms_delete_object(hBrushNav);
ms_delete_object(hHudBrush);
ms_end_paint(hwnd, & ps);
return 0;
}
case MS_WM_DESTROY: { ms_post_quit_message(0); return 0; }
}
return ms_def_window_proc_a(hwnd, msg, wparam, lparam);
}
int main(void) {
Slice tape_mem = slice_ut_(u8_(ms_virtual_alloc(nullptr, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_READWRITE)), 64 * 1024);
Slice anno_mem = slice_ut_(u8_(ms_virtual_alloc(nullptr, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_READWRITE)), 64 * 1024);
Slice code_mem = slice_ut_(u8_(ms_virtual_alloc(nullptr, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_EXECUTE_READWRITE)), 64 * 1024);
if (! tape_mem.ptr || ! anno_mem.ptr || ! code_mem.ptr) ms_exit_process(1);
farena_init(& tape_arena, tape_mem);
farena_init(& anno_arena, anno_mem);
farena_init(& code_arena, code_mem);
scatter(pack_token(STag_Comment, 0), "INIT ");
scatter(pack_token(STag_Data, 5), 0);
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Imm, 0), "STORE ");
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Imm, 0), "STORE ");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Define, 0), "F_STEP ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "RET_IF_Z");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "MULT ");
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, 0), "STORE ");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "DEC ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "STORE ");
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "PRINT ");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
relink_tape();
run_full = true;
compile_and_run_tape();
run_full = false;
MS_WNDCLASSA wc;
mem_fill(u8_(& wc), 0, sizeof(wc));
wc.lpfnWndProc = win_proc;
wc.hInstance = ms_get_stock_object(0);
wc.lpszClassName = "ColorForthWindow";
wc.hbrBackground = ms_get_stock_object(4);
ms_register_class_a(& wc);
void* hwnd = ms_create_window_ex_a(0, wc.lpszClassName, "Sourceless Global Memory Explorer", MS_WS_OVERLAPPEDWINDOW | MS_WS_VISIBLE, 100, 100, 1100, 750, nullptr, nullptr, wc.hInstance, nullptr);
MS_MSG msg;
while (ms_get_message_a(& msg, nullptr, 0, 0)) { ms_translate_message(& msg); ms_dispatch_message_a(& msg); }
ms_exit_process(0);
return 0;
}