progress
This commit is contained in:
@@ -36,8 +36,11 @@ The application presents a visual grid of 32-bit tokens and allows the user to n
|
||||
## What's Missing (TODO)
|
||||
|
||||
* **Saving/Loading:** The tape and annotation arenas are purely in-memory and are lost when the program closes.
|
||||
* **Expanded Instruction Set:** The JIT only knows a handful of primitives (`SWAP`, `MULT`, `ADD`, `FETCH`, `STORE`, `DEC`, `RET_IF_ZERO`, `PRINT`). It has no support for floating point, stack manipulation for C FFI, or more complex branches.
|
||||
* **Robust Dictionary:** The current dictionary is a simple array that is rebuilt on every compile. It doesn't handle collisions, scoping, or namespaces.
|
||||
* **Expanded Instruction Set:** The JIT only knows a handful of primitives (`SWAP`, `MULT`, `ADD`, `FETCH`, `STORE`, `DEC`, `RET_IF_ZERO`, `PRINT`). It has no support for floating point or more complex branches.
|
||||
* **The FFI Bridge:** The system needs a macro (like Onat's `CCALL`) to align the `RSP` stack to 16 bytes and map the 2-register data stack/globals into the Windows C-ABI (`RCX`, `RDX`, `R8`, `R9`) to call WinAPI safely from the JIT.
|
||||
* **Implicit Definition Boundaries (Magenta Pipe):** Definitions should not need explicit `begin`/`end`. A definition token should implicitly cause the JIT to emit a `RET` to close the prior block, and an `xchg rax, rdx` to rotate the stack for the new block.
|
||||
* **x68 Instruction Padding:** The JIT currently emits variable-length instructions (`emit8`). It needs to pad every logical block/instruction to exact 32-bit multiples using ignored prefixes or NOPs to perfectly align with the visual token grid.
|
||||
* **O(1) Dictionary & Visual Linking:** The current dictionary is a simple string-matched array rebuilt on compile. It needs to transition to a true "visual linker" where visual tokens store the absolute source memory indices, resolving locations instantly at edit-time.
|
||||
* **Annotation Editing:** Typing into an annotation just appends characters. A proper text-editing cursor within the token is needed.
|
||||
|
||||
## References Utilized
|
||||
|
||||
376
attempt_1/main.c
376
attempt_1/main.c
@@ -1,16 +1,13 @@
|
||||
#include "duffle.amd64.win32.h"
|
||||
|
||||
// --- Semantic Tags (Using X-Macros & Enum_) ---
|
||||
// Colors translated from Cozy-and-WIndy:
|
||||
// 0x00bbggrr Win32 format
|
||||
|
||||
#define Tag_Entries() \
|
||||
X(Define, "Define", 0x0018AEFF, ":") /* Orange-ish (Language.Type) */ \
|
||||
X(Call, "Call", 0x00D6A454, "~") /* Soft Blue (Language.Class) */ \
|
||||
X(Data, "Data", 0x0094BAA1, "$") /* Muted Green (Language.Number) */ \
|
||||
X(Imm, "Imm", 0x004AA4C2, "^") /* Sand/Yellow (Language.Keyword) */ \
|
||||
X(Comment, "Comment", 0x00AAAAAA, ".") /* Grey (Language.Comment) */ \
|
||||
X(Format, "Format", 0x003A2F3B, " ") /* Current Line BG for invisibles */
|
||||
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),
|
||||
@@ -34,55 +31,61 @@ global const char* tag_names[] = {
|
||||
#undef X
|
||||
};
|
||||
|
||||
// Token Packing: 28 bits payload | 4 bits tag
|
||||
#define pack_token(tag, val) ((u4_(tag) << 28) | (u4_(val) & 0x0FFFFFFF))
|
||||
#define unpack_tag(token) ( ((token) >> 28) & 0x0F)
|
||||
#define unpack_val(token) ( (token) & 0x0FFFFFFF)
|
||||
|
||||
// 2-Character Mapped Dictionary Helper
|
||||
#define id2(a, b) ((u4_(a) << 8) | u4_(b))
|
||||
|
||||
#define TOKENS_PER_ROW 8
|
||||
|
||||
#define MODE_NAV 0
|
||||
#define MODE_EDIT 1
|
||||
|
||||
// The Tape Drive (Using FArena from duffle)
|
||||
global FArena tape_arena;
|
||||
global FArena anno_arena;
|
||||
global U8 cursor_idx = 0;
|
||||
global U4 editor_mode = MODE_NAV;
|
||||
global U4 mode_switch_now = false;
|
||||
|
||||
// Executable Code Arena (The JIT)
|
||||
global FArena code_arena;
|
||||
|
||||
// VM State: 2-Reg Stack + Global Memory
|
||||
global U8 vm_rax = 0; // Top
|
||||
global U8 vm_rdx = 0; // Next
|
||||
global U8 vm_rax = 0;
|
||||
global U8 vm_rdx = 0;
|
||||
global U8 vm_globals[16] = {0};
|
||||
|
||||
// Execution Mode & Logging
|
||||
global B4 run_full = false;
|
||||
global U8 log_buffer[16] = {0};
|
||||
global U4 log_count = 0;
|
||||
|
||||
// UI State
|
||||
global S4 scroll_y_offset = 0;
|
||||
|
||||
void ms_builtin_print(U8 val) {
|
||||
if (log_count < 16) {
|
||||
log_buffer[log_count++] = val;
|
||||
}
|
||||
if (log_count < 16) log_buffer[log_count++] = val;
|
||||
}
|
||||
|
||||
// Dictionary
|
||||
typedef struct {
|
||||
U4 val;
|
||||
U4 offset;
|
||||
} DictEntry;
|
||||
global DictEntry dict[256];
|
||||
global U8 dict_count = 0;
|
||||
// Visual Linker & O(1) Dictionary
|
||||
global U4 tape_to_code_offset[65536] = {0};
|
||||
|
||||
#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
|
||||
|
||||
global const char* prim_names[] = {
|
||||
"",
|
||||
"SWAP ",
|
||||
"MULT ",
|
||||
"ADD ",
|
||||
"FETCH ",
|
||||
"DEC ",
|
||||
"STORE ",
|
||||
"RET_IF_Z",
|
||||
"RETURN ",
|
||||
"PRINT "
|
||||
};
|
||||
|
||||
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) {
|
||||
@@ -93,96 +96,138 @@ IA_ void scatter(U4 token, const char* anno_str) {
|
||||
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 ++;
|
||||
}
|
||||
int i = 0; while(i < 8 && anno_str[i]) { dest[i] = anno_str[i]; i ++; }
|
||||
}
|
||||
anno_arena.used += sizeof(U8);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Minimal x86-64 Emitter ---
|
||||
internal void emit8(U1 b) {
|
||||
if (code_arena.used + 1 <= code_arena.capacity) {
|
||||
U1*r ptr = u1_r(code_arena.start + code_arena.used);
|
||||
ptr[0] = b;
|
||||
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 ptr = u4_r(code_arena.start + code_arena.used);
|
||||
ptr[0] = val;
|
||||
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 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 = 0;
|
||||
for (int p = 1; p <= 9; 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) { new_val = p; break; }
|
||||
}
|
||||
|
||||
if (new_val == 0) {
|
||||
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) { new_val = j; break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
tape_ptr[i] = pack_token(tag, new_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void compile_action(U4 val)
|
||||
{
|
||||
if (val == id2('S','W')) { // SWAP: xchg rax, rdx
|
||||
if (val == PRIM_SWAP) {
|
||||
emit8(0x48); emit8(0x87); emit8(0xC2);
|
||||
pad32();
|
||||
return;
|
||||
} else if (val == id2('M','*')) { // MULT: imul rax, rdx
|
||||
} else if (val == PRIM_MULT) {
|
||||
emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2);
|
||||
pad32();
|
||||
return;
|
||||
} else if (val == id2('+',' ')) { // ADD: add rax, rdx
|
||||
} else if (val == PRIM_ADD) {
|
||||
emit8(0x48); emit8(0x01); emit8(0xD0);
|
||||
pad32();
|
||||
return;
|
||||
} else if (val == id2('@',' ')) { // FETCH: mov rax, QWORD PTR [rcx + rax*8]
|
||||
} else if (val == PRIM_FETCH) {
|
||||
emit8(0x48); emit8(0x8B); emit8(0x04); emit8(0xC1);
|
||||
pad32();
|
||||
return;
|
||||
} else if (val == id2('-','1')) { // DEC: dec rax
|
||||
} else if (val == PRIM_DEC) {
|
||||
emit8(0x48); emit8(0xFF); emit8(0xC8);
|
||||
pad32();
|
||||
return;
|
||||
} else if (val == id2('!',' ')) { // STORE: mov QWORD PTR [rcx + rax*8], rdx
|
||||
} else if (val == PRIM_STORE) {
|
||||
emit8(0x48); emit8(0x89); emit8(0x14); emit8(0xC1);
|
||||
pad32();
|
||||
return;
|
||||
} else if (val == id2('R','0')) { // RET_IF_ZERO: test rax, rax; jnz +1; ret
|
||||
emit8(0x48); emit8(0x85); emit8(0xC0); // test rax, rax
|
||||
emit8(0x75); emit8(0x01); // jnz skip_ret (+1 byte)
|
||||
emit8(0xC3); // ret
|
||||
} else if (val == PRIM_RET_Z) {
|
||||
emit8(0x48); emit8(0x85); emit8(0xC0);
|
||||
emit8(0x75); emit8(0x01);
|
||||
emit8(0xC3);
|
||||
pad32();
|
||||
return;
|
||||
} else if (val == id2('R','E')) { // RET
|
||||
} else if (val == PRIM_RET) {
|
||||
emit8(0xC3);
|
||||
pad32();
|
||||
return;
|
||||
} else if (val == id2('P','R')) { // PRINT: call ms_builtin_print
|
||||
emit8(0x51); // push rcx
|
||||
emit8(0x52); // push rdx
|
||||
emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x20); // sub rsp, 32
|
||||
emit8(0x48); emit8(0x89); emit8(0xC1); // mov rcx, rax
|
||||
emit8(0x49); emit8(0xB8); // mov r8, imm64
|
||||
} else if (val == PRIM_PRINT) {
|
||||
emit8(0x51); emit8(0x52);
|
||||
emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x20);
|
||||
emit8(0x48); emit8(0x89); emit8(0xC1);
|
||||
emit8(0x49); emit8(0xB8);
|
||||
U8 addr = u8_(& ms_builtin_print);
|
||||
emit32(u4_(addr & 0xFFFFFFFF));
|
||||
emit32(u4_(addr >> 32));
|
||||
emit8(0x41); emit8(0xFF); emit8(0xD0); // call r8
|
||||
emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x20); // add rsp, 32
|
||||
emit8(0x5A); // pop rdx
|
||||
emit8(0x59); // pop rcx
|
||||
emit8(0x41); emit8(0xFF); emit8(0xD0);
|
||||
emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x20);
|
||||
emit8(0x5A); emit8(0x59);
|
||||
pad32();
|
||||
return;
|
||||
}
|
||||
// Dictionary Resolver (Call User Word)
|
||||
for (U8 entry = 0; entry < dict_count; entry++) {
|
||||
if (dict[entry].val == val) {
|
||||
U4 target = dict[entry].offset;
|
||||
U4 current = code_arena.used;
|
||||
S4 rel32 = s4_(target) - s4_(current + 5);
|
||||
emit8(0xE8); // CALL rel32
|
||||
emit32(u4_(rel32));
|
||||
return;
|
||||
}
|
||||
|
||||
if (val > 0) {
|
||||
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);
|
||||
dict_count = 0;
|
||||
log_count = 0;
|
||||
|
||||
// Prologue: Load VM state from globals[14] and [15]
|
||||
emit8(0x48); emit8(0x8B); emit8(0x41); emit8(0x70); // mov rax, [rcx+112]
|
||||
emit8(0x48); emit8(0x8B); emit8(0x51); emit8(0x78); // mov rdx, [rcx+120]
|
||||
emit8(0x48); emit8(0x8B); emit8(0x41); emit8(0x70);
|
||||
emit8(0x48); emit8(0x8B); emit8(0x51); emit8(0x78);
|
||||
|
||||
U4*r tape_ptr = u4_r(tape_arena.start);
|
||||
B4 in_def = false;
|
||||
@@ -195,35 +240,36 @@ IA_ void compile_and_run_tape(void)
|
||||
if (tag == STag_Define)
|
||||
{
|
||||
if (in_def == false) {
|
||||
emit8(0xE9); // JMP rel32 (Skip over definition body)
|
||||
pad32();
|
||||
emit8(0xE9);
|
||||
def_jmp_offset = code_arena.used;
|
||||
emit32(0);
|
||||
pad32();
|
||||
in_def = true;
|
||||
} else {
|
||||
emit8(0xC3);
|
||||
pad32();
|
||||
}
|
||||
if (dict_count < 256) {
|
||||
dict[dict_count].val = val;
|
||||
dict[dict_count].offset = code_arena.used;
|
||||
dict_count++;
|
||||
}
|
||||
|
||||
tape_to_code_offset[i] = code_arena.used;
|
||||
|
||||
emit8(0x48); emit8(0x87); emit8(0xC2);
|
||||
pad32();
|
||||
}
|
||||
else if (tag == STag_Call)
|
||||
{
|
||||
compile_action(val);
|
||||
if (val == id2('R','E') && in_def) {
|
||||
// End of definition block, patch the jump
|
||||
U4 current = code_arena.used;
|
||||
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
|
||||
in_def = false;
|
||||
}
|
||||
}
|
||||
else if (tag == STag_Data) {
|
||||
emit8(0x48); emit8(0x89); emit8(0xC2); // mov rdx, rax
|
||||
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val); // mov rax, imm32
|
||||
emit8(0x48); emit8(0x89); emit8(0xC2);
|
||||
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val);
|
||||
pad32();
|
||||
}
|
||||
else if (tag == STag_Imm)
|
||||
{
|
||||
if (in_def) {
|
||||
// If we execute something, we jump out of def block first
|
||||
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;
|
||||
@@ -233,27 +279,24 @@ IA_ void compile_and_run_tape(void)
|
||||
}
|
||||
|
||||
if (in_def) {
|
||||
// If we hit cursor inside a definition, patch jump so it doesn't crash on execution
|
||||
emit8(0xC3);
|
||||
pad32();
|
||||
U4 current = code_arena.used;
|
||||
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
|
||||
}
|
||||
|
||||
// Epilogue: Save VM state back to globals
|
||||
emit8(0x48); emit8(0x89); emit8(0x41); emit8(0x70); // mov [rcx+112], rax
|
||||
emit8(0x48); emit8(0x89); emit8(0x51); emit8(0x78); // mov [rcx+120], rdx
|
||||
emit8(0xC3); // ret
|
||||
emit8(0x48); emit8(0x89); emit8(0x41); emit8(0x70);
|
||||
emit8(0x48); emit8(0x89); emit8(0x51); emit8(0x78);
|
||||
emit8(0xC3);
|
||||
|
||||
// Cast code arena to function pointer and CALL it!
|
||||
typedef void JIT_Func(U8* globals_ptr);
|
||||
JIT_Func* func = (JIT_Func*)code_arena.start;
|
||||
func(vm_globals);
|
||||
|
||||
// Read state for UI
|
||||
vm_rax = vm_globals[14];
|
||||
vm_rdx = vm_globals[15];
|
||||
}
|
||||
|
||||
// --- Window Procedure ---
|
||||
S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
{
|
||||
U8 tape_count = tape_arena.used / sizeof(U4);
|
||||
@@ -267,12 +310,10 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
U4 val = unpack_val(t);
|
||||
U1 c = u1_(wparam);
|
||||
|
||||
// Skip control characters and the 'E' that triggered the mode
|
||||
bool should_skip = c < 32 || (c == 'e' && mode_switch_now);
|
||||
if (should_skip) { mode_switch_now = false; return 0; }
|
||||
|
||||
if (tag == STag_Data) {
|
||||
// Hex input
|
||||
U4 digit = 16;
|
||||
if (c >= '0' && c <= '9') digit = c - '0';
|
||||
if (c >= 'a' && c <= 'f') digit = c - 'a' + 10;
|
||||
@@ -290,28 +331,22 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
if (len < 8) {
|
||||
anno_str[len] = (char)c;
|
||||
for (int i = len + 1; i < 8; i++) anno_str[i] = '\0';
|
||||
// Update the 2-char token ID from the first 2 chars
|
||||
char c1 = anno_str[0] ? anno_str[0] : ' ';
|
||||
char c2 = anno_str[1] ? anno_str[1] : ' ';
|
||||
val = id2(c1, c2);
|
||||
tape_ptr[cursor_idx] = pack_token(tag, val);
|
||||
}
|
||||
}
|
||||
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
|
||||
relink_tape();
|
||||
compile_and_run_tape();
|
||||
ms_invalidate_rect(hwnd, nullptr, true);
|
||||
return 0;
|
||||
}
|
||||
case MS_WM_KEYDOWN: {
|
||||
if (wparam == 0x45 && editor_mode == MODE_NAV) { // 'E'
|
||||
if (wparam == 0x45 && editor_mode == MODE_NAV) {
|
||||
editor_mode = MODE_EDIT;
|
||||
mode_switch_now = true;
|
||||
ms_invalidate_rect(hwnd, nullptr, true);
|
||||
return 0;
|
||||
// ~~Consume the keypress so it doesn't trigger WM_CHAR~~
|
||||
// NOTE(Ed): Still triggers WM_CHAR we need to track when we just entered edit mode and that must be consumed.
|
||||
}
|
||||
if (wparam == 0x1B && editor_mode == MODE_EDIT) { // ESC
|
||||
if (wparam == 0x1B && editor_mode == MODE_EDIT) {
|
||||
editor_mode = MODE_NAV;
|
||||
ms_invalidate_rect(hwnd, nullptr, true);
|
||||
return 0;
|
||||
@@ -332,16 +367,14 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
while (len < 8 && anno_str[len] != '\0' && anno_str[len] != ' ') len ++;
|
||||
if (len > 0) {
|
||||
anno_str[len - 1] = '\0';
|
||||
char c1 = anno_str[0] ? anno_str[0] : ' ';
|
||||
char c2 = anno_str[1] ? anno_str[1] : ' ';
|
||||
tape_ptr[cursor_idx] = pack_token(tag, id2(c1, c2));
|
||||
}
|
||||
}
|
||||
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
|
||||
relink_tape();
|
||||
compile_and_run_tape();
|
||||
ms_invalidate_rect(hwnd, nullptr, true);
|
||||
}
|
||||
return 0; // Block navigation keys in Edit Mode
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wparam == MS_VK_RIGHT && cursor_idx < tape_count - 1) cursor_idx ++;
|
||||
@@ -365,7 +398,7 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
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 ++; // Skip the newline
|
||||
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;
|
||||
@@ -378,15 +411,12 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
if (wparam == MS_VK_F5) { run_full = !run_full; }
|
||||
|
||||
if (wparam == MS_VK_TAB) {
|
||||
// Cycle Color Tag
|
||||
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)
|
||||
{
|
||||
// Delete Token
|
||||
// Shift: delete AT cursor | Regular: delete TO THE LEFT
|
||||
U8 delete_idx = cursor_idx;
|
||||
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
|
||||
if (is_shift == false) {
|
||||
@@ -407,8 +437,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
}
|
||||
}
|
||||
else if (wparam == MS_VK_SPACE || wparam == MS_VK_RETURN) {
|
||||
// Insert New Token
|
||||
// Shift: insert AFTER cursor | Regular: insert BEFORE cursor
|
||||
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
|
||||
U8 insert_idx = cursor_idx;
|
||||
if (is_shift) insert_idx ++;
|
||||
@@ -423,7 +451,7 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
tape_ptr[insert_idx] = pack_token(STag_Format, 0xA);
|
||||
anno_ptr[insert_idx] = 0;
|
||||
} else {
|
||||
tape_ptr[insert_idx] = pack_token(STag_Comment, id2(' ',' '));
|
||||
tape_ptr[insert_idx] = pack_token(STag_Comment, 0);
|
||||
anno_ptr[insert_idx] = 0;
|
||||
}
|
||||
if (is_shift) cursor_idx ++;
|
||||
@@ -432,10 +460,10 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
}
|
||||
}
|
||||
|
||||
// Interaction: Reset VM and compile
|
||||
vm_rax = 0; vm_rdx = 0;
|
||||
mem_zero(u8_(vm_globals), sizeof(vm_globals));
|
||||
|
||||
relink_tape();
|
||||
compile_and_run_tape();
|
||||
|
||||
ms_invalidate_rect(hwnd, nullptr, true);
|
||||
@@ -447,7 +475,7 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
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); // TRANSPARENT text background
|
||||
ms_set_bk_mode(hdc, 1);
|
||||
|
||||
void* hBgBrush = ms_create_solid_brush(0x00222222);
|
||||
ms_select_object(hdc, hBgBrush);
|
||||
@@ -462,7 +490,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
U4*r tape_ptr = u4_r(tape_arena.start);
|
||||
U8*r anno_ptr = u8_r(anno_arena.start);
|
||||
|
||||
// Render Tokens
|
||||
for (U8 i = 0; i < tape_count; i++)
|
||||
{
|
||||
if (x >= start_x + (TOKENS_PER_ROW * spacing_x)) {
|
||||
@@ -492,7 +519,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
|
||||
ms_set_text_color(hdc, color);
|
||||
if (editor_mode == MODE_EDIT && i == cursor_idx) {
|
||||
// Better visibility in Edit Mode: White text on White-ish cursor
|
||||
ms_set_text_color(hdc, 0x001E1E1E);
|
||||
}
|
||||
|
||||
@@ -503,19 +529,11 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Extract annotation string
|
||||
char* a_str = (char*) & anno;
|
||||
if (a_str[0] == '\0') {
|
||||
// Fallback to 2-character ID
|
||||
val_str[0] = (char)((val >> 8) & 0xFF);
|
||||
val_str[1] = (char)(val & 0xFF);
|
||||
val_str[2] = ' '; val_str[3] = ' '; val_str[4] = ' '; val_str[5] = ' ';
|
||||
val_str[6] = '\0';
|
||||
}
|
||||
else {
|
||||
mem_copy(u8_(val_str), u8_(a_str), 8);
|
||||
val_str[8] = '\0';
|
||||
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];
|
||||
@@ -536,7 +554,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a solid background behind the HUD to cover scrolling text
|
||||
void* hHudBrush = ms_create_solid_brush(0x00141E23);
|
||||
ms_select_object(hdc, hHudBrush);
|
||||
ms_rectangle(hdc, -1, 500, 3000, 3000);
|
||||
@@ -545,7 +562,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
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);
|
||||
|
||||
// Render VM State
|
||||
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);
|
||||
@@ -555,10 +571,9 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
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); // Number green
|
||||
ms_set_text_color(hdc, 0x0094BAA1);
|
||||
ms_text_out_a(hdc, 40, 550, state_str, 29);
|
||||
|
||||
// HUD: Display Current Token Meaning
|
||||
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];
|
||||
@@ -580,11 +595,10 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
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); // Soft blue
|
||||
ms_set_text_color(hdc, 0x00D6A454);
|
||||
ms_text_out_a(hdc, 400, 550 + (i * 25), glob_str, 13);
|
||||
}
|
||||
|
||||
// Print Log
|
||||
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 ++) {
|
||||
@@ -607,7 +621,6 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
// 1. Initialize Memory Arenas using WinAPI + FArena
|
||||
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);
|
||||
@@ -617,54 +630,51 @@ int main(void) {
|
||||
farena_init(& anno_arena, anno_mem);
|
||||
farena_init(& code_arena, code_mem);
|
||||
|
||||
// Bootstrap Robust Sample: Factorial State Machine
|
||||
scatter(pack_token(STag_Comment, id2('I','N')), "INIT "); // .IN
|
||||
scatter(pack_token(STag_Data, 5), 0); // $5
|
||||
scatter(pack_token(STag_Data, 0), 0); // $0 (Addr)
|
||||
scatter(pack_token(STag_Imm, id2('!',' ')), "STORE "); // ^!
|
||||
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); // $1
|
||||
scatter(pack_token(STag_Data, 1), 0); // $1 (Addr)
|
||||
scatter(pack_token(STag_Imm, id2('!',' ')), "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); // Newline
|
||||
scatter(pack_token(STag_Format, 0xA), 0);
|
||||
|
||||
// Define the FS (Factorial Step) word in memory
|
||||
scatter(pack_token(STag_Define, id2('F','S')), "F_STEP ");
|
||||
scatter(pack_token(STag_Data, 0), 0);
|
||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Call, id2('R','0')), "RET_IF_Z");
|
||||
scatter(pack_token(STag_Format, 0xA), 0); // Newline
|
||||
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, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Data, 0), 0);
|
||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Call, id2('M','*')), "MULT ");
|
||||
scatter(pack_token(STag_Data, 1), 0);
|
||||
scatter(pack_token(STag_Call, id2('!',' ')), "STORE ");
|
||||
scatter(pack_token(STag_Format, 0xA), 0); // Newline
|
||||
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, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Call, id2('-','1')), "DEC ");
|
||||
scatter(pack_token(STag_Data, 0), 0);
|
||||
scatter(pack_token(STag_Call, id2('!',' ')), "STORE ");
|
||||
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, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Call, id2('P','R')), "PRINT "); // Print Accumulator!
|
||||
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_Call, id2('R','E')), "RETURN "); // Return!
|
||||
scatter(pack_token(STag_Format, 0xA), 0);
|
||||
|
||||
scatter(pack_token(STag_Format, 0xA), 0); // Newline
|
||||
|
||||
// Call it
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP "); // ^FS
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "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 ");
|
||||
scatter(pack_token(STag_Imm, 0), "F_STEP ");
|
||||
|
||||
relink_tape();
|
||||
|
||||
MS_WNDCLASSA wc;
|
||||
mem_fill(u8_(& wc), 0, sizeof(wc));
|
||||
@@ -679,4 +689,4 @@ int main(void) {
|
||||
while (ms_get_message_a(& msg, nullptr, 0, 0)) { ms_translate_message(& msg); ms_dispatch_message_a(& msg); }
|
||||
ms_exit_process(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user