add call frames, refactor to allow call frames to work, add debug

This commit is contained in:
zongor 2025-06-27 13:06:06 -04:00
parent f909071287
commit aab4c887ca
10 changed files with 271 additions and 121 deletions

View File

@ -1,20 +1,8 @@
#include "compiler.h" #include "compiler.h"
#include "parser.h" #include "parser.h"
#define MEMORY_SIZE 1024 void demo_add_compile(Value *memory) {
uint32_t i = 0;
Code *demo_add_compile() {
Code *code = (Code *)malloc(sizeof(Code));
Value memory[MEMORY_SIZE] = {0}; /* Memory array */
code->memory = memory;
code->size = MEMORY_SIZE;
code->current.pc = 1;
uint32_t i = 1;
memory[0].c[0] = 0;
memory[0].c[1] = 'z';
memory[0].c[2] = 'r';
memory[0].c[3] = 'e';
memory[i++].u = OP(OP_LOADU, 0, 0, 0); memory[i++].u = OP(OP_LOADU, 0, 0, 0);
memory[i++].u = 0; memory[i++].u = 0;
memory[i++].u = OP(OP_LOADU, 1, 0, 0); memory[i++].u = OP(OP_LOADU, 1, 0, 0);
@ -43,26 +31,13 @@ Code *demo_add_compile() {
memory[i++].u = OP(OP_READ_STRING, 7, 0, 0); memory[i++].u = OP(OP_READ_STRING, 7, 0, 0);
memory[i++].u = OP(OP_PRINT_STRING, 0, 7, 0); memory[i++].u = OP(OP_PRINT_STRING, 0, 7, 0);
memory[i++].u = OP(OP_HALT, 0, 0, 0); memory[i++].u = OP(OP_HALT, 0, 0, 0);
return code;
} }
Code *compile(char *buffer) { void compile(Value *memory, char *buffer) {
Code *code = (Code *)malloc(sizeof(Code));
Value memory[MEMORY_SIZE] = {0}; /* Memory array */
code->memory = memory;
code->size = MEMORY_SIZE;
/* char number[100]; */
memory[0].c[0] = 0;
memory[0].c[1] = 'z';
memory[0].c[2] = 'r';
memory[0].c[3] = 'e';
initTokenizer(buffer); initTokenizer(buffer);
Token t = nextToken(); Token t = nextToken();
do { do {
debug_printToken(t); printToken(t);
switch (t.type) { switch (t.type) {
case TOKEN_LEFT_PAREN: case TOKEN_LEFT_PAREN:
break; break;
@ -195,6 +170,4 @@ Code *compile(char *buffer) {
} }
t = nextToken(); t = nextToken();
} while (t.type != TOKEN_EOF); } while (t.type != TOKEN_EOF);
return code;
} }

View File

@ -3,14 +3,7 @@
#include "opcodes.h" #include "opcodes.h"
typedef struct Code Code; void demo_add_compile (Value* memory);
struct Code { void compile (Value* memory, char *buffer);
Value *memory;
uint32_t size;
Frame current;
};
Code* demo_add_compile ();
Code* compile (char *buffer);
#endif #endif

View File

@ -1,15 +1,15 @@
#include "debug.h" #include "debug.h"
int core_dump(Value *memory, uint32_t memory_size) { int core_dump(VM *vm) {
FILE *file = fopen("memory_dump.bin", "wb"); FILE *file = fopen("memory_dump.bin", "wb");
if (!file) { if (!file) {
perror("Failed to open file"); perror("Failed to open file");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
size_t written = fwrite(memory, 1, memory_size, file); size_t written = fwrite(vm->memory, 1, vm->memory_size, file);
if (written != memory_size) { if (written != vm->memory_size) {
fprintf(stderr, "Incomplete write: %zu bytes written out of %u\n", written, fprintf(stderr, "Incomplete write: %zu bytes written out of %u\n", written,
memory_size); vm->memory_size);
fclose(file); fclose(file);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -17,3 +17,147 @@ int core_dump(Value *memory, uint32_t memory_size) {
fclose(file); fclose(file);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
void printOp(uint8_t op, uint8_t dest, uint8_t src1, uint8_t src2) {
switch (op) {
case OP_HALT:
printf("[HALT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_LOADI:
printf("[LOADI] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_LOADU:
printf("[LOADU] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_LOADF:
printf("[LOADF] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_STOREI:
printf("[STOREI] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_STOREU:
printf("[STOREU] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_STOREF:
printf("[STOREF] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_ADD_INT:
printf("[ADD_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_SUB_INT:
printf("[SUB_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_MUL_INT:
printf("[MUL_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_DIV_INT:
printf("[DIV_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JEQ_INT:
printf("[JEQ_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JGT_INT:
printf("[JGT_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JLT_INT:
printf("[JLT_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JLE_INT:
printf("[JLE_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JGE_INT:
printf("[JGE_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_INT_TO_REAL:
printf("[INT_TO_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_ADD_UINT:
printf("[ADD_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_SUB_UINT:
printf("[SUB_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_MUL_UINT:
printf("[MUL_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_DIV_UINT:
printf("[DIV_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JEQ_UINT:
printf("[JEQ_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JGT_UINT:
printf("[JGT_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JLT_UINT:
printf("[JLT_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JLE_UINT:
printf("[JLE_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JGE_UINT:
printf("[JGE_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_UINT_TO_REAL:
printf("[UINT_TO_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_ADD_REAL:
printf("[ADD_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_SUB_REAL:
printf("[SUB_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_MUL_REAL:
printf("[MUL_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_DIV_REAL:
printf("[DIV_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JEQ_REAL:
printf("[JEQ_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JGE_REAL:
printf("[JGE_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JGT_REAL:
printf("[JGT_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JLT_REAL:
printf("[JLT_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JLE_REAL:
printf("[JLE_REAL] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_REAL_TO_INT:
printf("[REAL_TO_INT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_REAL_TO_UINT:
printf("[REAL_TO_UINT] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_MOV:
printf("[MOV] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_JMP:
printf("[JMP] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_INT_TO_STRING:
printf("[INT_TO_STRING] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_UINT_TO_STRING:
printf("[UINT_TO_STRING] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_REAL_TO_STRING:
printf("[REAL_TO_STRING] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_READ_STRING:
printf("[READ_STRING] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_PRINT_STRING:
printf("[PRINT_STRING] $%d, $%d, $%d\n", dest, src1, src2);
break;
case OP_CMP_STRING:
printf("[CMP_STRING] $%d, $%d, $%d\n", dest, src1, src2);
break;
}
}

View File

@ -2,7 +2,10 @@
#define ZRE_DEBUG_H #define ZRE_DEBUG_H
#include "vm.h" #include "vm.h"
#include "parser.h"
#include "opcodes.h"
int core_dump(Value *memory, uint32_t memory_size); int core_dump(VM *vm);
void printOp(uint8_t op, uint8_t dest, uint8_t src1, uint8_t src2);
#endif #endif

View File

@ -16,14 +16,14 @@
#include <emscripten.h> #include <emscripten.h>
#endif #endif
Code *code; VM *vm;
void mainloop() { void mainloop() {
if (!step_vm(&code->current, code->memory)) { if (!step_vm(vm)) {
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
emscripten_cancel_main_loop(); /* this should "kill" the app. */ emscripten_cancel_main_loop(); /* this should "kill" the app. */
#else #else
core_dump(code->memory, code->size); core_dump(vm);
exit(0); exit(0);
#endif #endif
} }
@ -50,8 +50,10 @@ int main(int argc, char **argv) {
} }
initTokenMap(); initTokenMap();
compile(buffer); vm = init_vm();
code = demo_add_compile(); vm->frame = (Frame*)malloc(sizeof(Frame));
compile(vm->memory, buffer);
demo_add_compile(vm->memory);
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
emscripten_set_main_loop(mainloop, 0, 1); emscripten_set_main_loop(mainloop, 0, 1);

View File

@ -10,13 +10,29 @@ typedef union {
char c[4]; /* 4 Byte char array for string packing */ char c[4]; /* 4 Byte char array for string packing */
} Value; } Value;
#define MAX_REGS 255 typedef union {
uint32_t length;
char *string;
Value *array;
Value *code;
} Object;
#define MAX_REGS 256
typedef struct { typedef struct {
Value registers[MAX_REGS]; /* R0-R255 */ Value registers[MAX_REGS]; /* R0-R255 */
uint32_t pc; /* Program counter */ Object *locals; /* Short lived object */
} Frame; } Frame;
#define STACK_SIZE 128
typedef struct {
Value stack[STACK_SIZE];
uint32_t stack_size;
uint32_t pc; /* Program counter */
Value *memory;
uint32_t memory_size;
Frame *frame;
} VM;
typedef enum { typedef enum {
OP_HALT, /* terminate execution */ OP_HALT, /* terminate execution */
OP_LOADI, /* dest = next memory location as int */ OP_LOADI, /* dest = next memory location as int */

View File

@ -229,7 +229,8 @@ Token nextToken() {
return errorToken("Unexpected character."); return errorToken("Unexpected character.");
} }
void debug_printToken(Token t) {
void printToken(Token t) {
char *str = currentTokenToS(); char *str = currentTokenToS();
switch (t.type) { switch (t.type) {

View File

@ -109,7 +109,7 @@ struct TokenMap
void initTokenMap(); void initTokenMap();
void initTokenizer (char *src); void initTokenizer (char *src);
void debug_printToken (Token t); void printToken (Token t);
Token nextToken(); Token nextToken();
#endif #endif

149
src/vm.c
View File

@ -1,18 +1,21 @@
#include "vm.h" #include "vm.h"
#include "debug.h"
#define COMPARE_AND_JUMP(type, accessor, op) \ #define COMPARE_AND_JUMP(type, accessor, op) \
do { \ do { \
type value = frame->registers[src1].accessor; \ type value = vm->frame->registers[src1].accessor; \
type value2 = frame->registers[src2].accessor; \ type value2 = vm->frame->registers[src2].accessor; \
frame->pc = (value op value2) ? dest : frame->pc; \ vm->pc = (value op value2) ? dest : vm->pc; \
return frame->pc; \ return true; \
} while (0) } while (0)
#define MATH_OP(accessor, op) \ #define MATH_OP(accessor, op) \
do { \ do { \
frame->registers[dest].accessor = \ vm->frame->registers[dest].accessor = \
frame->registers[src1].accessor op frame->registers[src2].accessor; \ vm->frame->registers[src1] \
return frame->pc; \ .accessor op vm->frame->registers[src2] \
.accessor; \
return true; \
} while (0) } while (0)
/** /**
@ -28,11 +31,23 @@ void mem_strcpy(Value *memory, const char *str, uint32_t length,
} }
} }
#define MEMORY_SIZE 1024
VM *init_vm() {
Value memory[MEMORY_SIZE] = {0}; /* Memory array */
VM *vm = (VM *)malloc(sizeof(VM));
vm->memory = memory;
vm->memory_size = MEMORY_SIZE;
vm->stack_size = 0;
return vm;
}
/** /**
* Step to the next opcode in the vm. * Step to the next opcode in the vm.
*/ */
uint32_t step_vm(Frame *frame, Value *memory) { bool step_vm(VM *vm) {
uint32_t instruction = memory[frame->pc].u; uint32_t instruction = vm->memory[vm->pc].u;
/* Extract 8-bit register indices from 32-bit instruction */ /* Extract 8-bit register indices from 32-bit instruction */
uint8_t opcode = (instruction >> 24) & 0xFF; uint8_t opcode = (instruction >> 24) & 0xFF;
@ -40,29 +55,31 @@ uint32_t step_vm(Frame *frame, Value *memory) {
uint8_t src1 = (instruction >> 8) & 0xFF; uint8_t src1 = (instruction >> 8) & 0xFF;
uint8_t src2 = instruction & 0xFF; uint8_t src2 = instruction & 0xFF;
/* Advance to next instruction */ /* Advance to next instruction */
frame->pc++; vm->pc++;
printOp(opcode, dest, src1, src2);
switch (opcode) { switch (opcode) {
case OP_HALT: case OP_HALT:
return 0; return false;
case OP_LOADI: case OP_LOADI:
frame->registers[dest].i = memory[frame->pc++].i; vm->frame->registers[dest].i = vm->memory[vm->pc++].i;
return frame->pc; return true;
case OP_LOADU: case OP_LOADU:
frame->registers[dest].u = memory[frame->pc++].u; vm->frame->registers[dest].u = vm->memory[vm->pc++].u;
return frame->pc; return true;
case OP_LOADF: case OP_LOADF:
frame->registers[dest].f = memory[frame->pc++].f; vm->frame->registers[dest].f = vm->memory[vm->pc++].f;
return frame->pc; return true;
case OP_STOREI: case OP_STOREI:
memory[frame->pc++].i = frame->registers[src1].i; vm->memory[vm->pc++].i = vm->frame->registers[src1].i;
return frame->pc; return true;
case OP_STOREU: case OP_STOREU:
memory[frame->pc++].u = frame->registers[src1].u; vm->memory[vm->pc++].u = vm->frame->registers[src1].u;
return frame->pc; return true;
case OP_STOREF: case OP_STOREF:
memory[frame->pc++].f = frame->registers[src1].f; vm->memory[vm->pc++].f = vm->frame->registers[src1].f;
return frame->pc; return true;
case OP_ADD_INT: case OP_ADD_INT:
MATH_OP(i, +); MATH_OP(i, +);
case OP_SUB_INT: case OP_SUB_INT:
@ -88,23 +105,23 @@ uint32_t step_vm(Frame *frame, Value *memory) {
case OP_DIV_REAL: case OP_DIV_REAL:
MATH_OP(f, /); MATH_OP(f, /);
case OP_REAL_TO_INT: case OP_REAL_TO_INT:
frame->registers[dest].i = (int32_t)(frame->registers[src1].f); vm->frame->registers[dest].i = (int32_t)(vm->frame->registers[src1].f);
return frame->pc; return true;
case OP_INT_TO_REAL: case OP_INT_TO_REAL:
frame->registers[dest].f = (float)(frame->registers[src1].i); vm->frame->registers[dest].f = (float)(vm->frame->registers[src1].i);
return frame->pc; return true;
case OP_REAL_TO_UINT: case OP_REAL_TO_UINT:
frame->registers[dest].u = (uint32_t)(frame->registers[src1].f); vm->frame->registers[dest].u = (uint32_t)(vm->frame->registers[src1].f);
return frame->pc; return true;
case OP_UINT_TO_REAL: case OP_UINT_TO_REAL:
frame->registers[dest].f = (float)(frame->registers[src1].u); vm->frame->registers[dest].f = (float)(vm->frame->registers[src1].u);
return frame->pc; return true;
case OP_MOV: case OP_MOV:
frame->registers[dest] = frame->registers[src1]; vm->frame->registers[dest] = vm->frame->registers[src1];
return frame->pc; return true;
case OP_JMP: case OP_JMP:
frame->pc = frame->registers[src1].u; /* Jump to address */ vm->pc = vm->frame->registers[src1].u; /* Jump to address */
return frame->pc; return true;
case OP_JEQ_UINT: { case OP_JEQ_UINT: {
COMPARE_AND_JUMP(uint32_t, u, ==); COMPARE_AND_JUMP(uint32_t, u, ==);
} }
@ -151,64 +168,64 @@ uint32_t step_vm(Frame *frame, Value *memory) {
COMPARE_AND_JUMP(float, u, <=); COMPARE_AND_JUMP(float, u, <=);
} }
case OP_INT_TO_STRING: { case OP_INT_TO_STRING: {
int32_t a = (int32_t)frame->registers[src1].i; int32_t a = (int32_t)vm->frame->registers[src1].i;
uint32_t str_dest = (uint32_t)frame->registers[dest].u; uint32_t str_dest = (uint32_t)vm->frame->registers[dest].u;
char buffer[32]; char buffer[32];
int len = sprintf(buffer, "%d", a); int len = sprintf(buffer, "%d", a);
mem_strcpy(memory, buffer, len, str_dest); mem_strcpy(vm->memory, buffer, len, str_dest);
return frame->pc; return true;
} }
case OP_UINT_TO_STRING: { case OP_UINT_TO_STRING: {
uint32_t a = (uint32_t)frame->registers[src1].u; uint32_t a = (uint32_t)vm->frame->registers[src1].u;
uint32_t str_dest = (uint32_t)frame->registers[dest].u; uint32_t str_dest = (uint32_t)vm->frame->registers[dest].u;
char buffer[32]; char buffer[32];
int len = sprintf(buffer, "%d", a); int len = sprintf(buffer, "%d", a);
mem_strcpy(memory, buffer, len, str_dest); mem_strcpy(vm->memory, buffer, len, str_dest);
return frame->pc; return true;
} }
case OP_REAL_TO_STRING: { case OP_REAL_TO_STRING: {
float a = (float)frame->registers[src1].f; float a = (float)vm->frame->registers[src1].f;
uint32_t str_dest = (uint32_t)frame->registers[dest].u; uint32_t str_dest = (uint32_t)vm->frame->registers[dest].u;
char buffer[32]; char buffer[32];
int len = sprintf(buffer, "%f", a); int len = sprintf(buffer, "%f", a);
mem_strcpy(memory, buffer, len, str_dest); mem_strcpy(vm->memory, buffer, len, str_dest);
return frame->pc; return true;
} }
case OP_READ_STRING: { case OP_READ_STRING: {
uint32_t str_dest = (uint32_t)frame->registers[dest].u; uint32_t str_dest = (uint32_t)vm->frame->registers[dest].u;
uint32_t buffer = str_dest + 1; uint32_t buffer = str_dest + 1;
uint32_t length = 0; uint32_t length = 0;
while (1) { while (1) {
int ch = getchar(); int ch = getchar();
if (ch == '\n' || ch == EOF) { if (ch == '\n' || ch == EOF) {
memory[buffer + (length / 4)].c[length % 4] = '\0'; vm->memory[buffer + (length / 4)].c[length % 4] = '\0';
break; break;
} }
memory[buffer + (length / 4)].c[length % 4] = ch; vm->memory[buffer + (length / 4)].c[length % 4] = ch;
length++; length++;
} }
memory[str_dest].u = length; vm->memory[str_dest].u = length;
return frame->pc; return true;
} }
case OP_PRINT_STRING: { case OP_PRINT_STRING: {
uint32_t ptr = (uint32_t)frame->registers[src1].u; uint32_t ptr = (uint32_t)vm->frame->registers[src1].u;
uint32_t length = memory[ptr].u; uint32_t length = vm->memory[ptr].u;
uint32_t str_src = ptr + 1; uint32_t str_src = ptr + 1;
uint32_t i; uint32_t i;
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
uint8_t ch = memory[str_src + (i / 4)].c[i % 4]; uint8_t ch = vm->memory[str_src + (i / 4)].c[i % 4];
if (ch == '\0') if (ch == '\0')
break; break;
putchar(ch); putchar(ch);
} }
putchar('\n'); putchar('\n');
return frame->pc; return true;
} }
case OP_CMP_STRING: { case OP_CMP_STRING: {
uint32_t addr1 = (uint32_t)frame->registers[src1].u; uint32_t addr1 = (uint32_t)vm->frame->registers[src1].u;
uint32_t addr2 = (uint32_t)frame->registers[src2].u; uint32_t addr2 = (uint32_t)vm->frame->registers[src2].u;
uint32_t length1 = memory[addr1 - 1].u; uint32_t length1 = vm->memory[addr1 - 1].u;
uint32_t length2 = memory[addr2 - 1].u; uint32_t length2 = vm->memory[addr2 - 1].u;
uint32_t equal = 1; uint32_t equal = 1;
if (length1 != length2) { if (length1 != length2) {
@ -216,19 +233,19 @@ uint32_t step_vm(Frame *frame, Value *memory) {
} else { } else {
uint32_t i = 0; uint32_t i = 0;
while (i < length1) { while (i < length1) {
uint32_t char1 = memory[addr1 + i].u; uint32_t char1 = vm->memory[addr1 + i].u;
uint32_t char2 = memory[addr2 + i].u; uint32_t char2 = vm->memory[addr2 + i].u;
if (char1 != char2) { if (char1 != char2) {
equal = 0; equal = 0;
break; break;
} }
if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0') if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0')
return frame->pc; return true;
} }
} }
memory[dest].u = equal; vm->memory[dest].u = equal;
return frame->pc; return true;
} }
} }
return 0; return false;
} }

View File

@ -3,6 +3,7 @@
#include "opcodes.h" #include "opcodes.h"
uint32_t step_vm(Frame *frame, Value *memory); VM* init_vm();
bool step_vm(VM *vm);
#endif #endif