move sdl to own thing, add array + plex handling

This commit is contained in:
zongor 2025-08-16 21:51:23 -04:00
parent 70b9a82a97
commit 63d67b5c0d
9 changed files with 282 additions and 190 deletions

157
src/arch/linux-sdl/main.c Normal file
View File

@ -0,0 +1,157 @@
#include "../../compiler.h"
#include "../../vm.h"
#include <SDL2/SDL.h>
#define MAX_SRC_SIZE 16384
void compileFile(const char *path, VM *vm) {
FILE *f = fopen(path, "rb");
if (!f) {
perror("fopen");
exit(1);
}
static char source[MAX_SRC_SIZE + 1];
fseek(f, 0, SEEK_END);
long len = ftell(f);
fseek(f, 0, SEEK_SET);
if (len >= MAX_SRC_SIZE) {
perror("source is larget than buffer");
exit(1);
}
size_t read = fread(source, 1, len, f);
source[read] = '\0';
fclose(f);
compile(source, vm);
}
static void repl(VM *vm) {
char line[1024];
for (;;) {
printf("> ");
if (!fgets(line, sizeof(line), stdin)) {
printf("\n");
break;
}
/* reset the code counter to 0 */
vm->cp = 0;
vm->sp = 0;
vm->pc = 0;
vm->mp = 0;
compile(line, vm);
while (step_vm(vm));
}
exit(0);
}
int main(int argc, char **argv) {
VM vm = {0};
vm.frames_size = FRAMES_SIZE;
vm.return_stack_size = STACK_SIZE;
vm.stack_size = STACK_SIZE;
vm.memory_size = MEMORY_SIZE;
if (argc == 1) {
repl(&vm);
} else if (argc == 2) {
compileFile(argv[1], &vm);
} else {
fprintf(stderr, "Usage: %s <file.zrl>\n", argv[0]);
return 64;
}
uint32_t buffer_size = 640 * 480 * sizeof(uint32_t);
Device screen;
screen.type = SCREEN;
screen.s = (Screen){.width = (uint8_t)480,
.height = (uint8_t)640,
.allocated = {vm.mp, buffer_size},
.buffer = &vm.memory[vm.mp]};
vm.devices[vm.dp++] = screen;
vm.mp += buffer_size;
Device mouse;
mouse.type = MOUSE;
mouse.m = (Mouse){.x = 0, .y = 0, .btn1 = 0, .btn2 = 0, .btn3 = 0};
vm.devices[vm.dp++] = mouse;
Device keyboard;
keyboard.type = KEYBOARD;
const uint8_t *state = SDL_GetKeyboardState(NULL);
keyboard.k = (Keyboard){.length = SDL_NUM_SCANCODES, .keys = state};
vm.devices[vm.dp++] = keyboard;
/* Create window and renderer */
SDL_Window *window =
SDL_CreateWindow("Reality Engine VM", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, screen.s.width, screen.s.height,
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
SDL_Renderer *renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
/* Create texture for 640x480 buffer */
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
screen.s.width, screen.s.height);
/* Enable nearest-neighbor scaling (preserves pixel art) */
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); /* "0" = nearest-neighbor */
bool running = true;
while (running) {
step_vm(&vm);
SDL_PumpEvents();
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN:
printf("mouse_down: x=%d, y=%d, btn=%d\n", event.button.x,
event.button.y, event.button.button);
break;
case SDL_MOUSEMOTION:
printf("mouse_move: x=%d, y=%d\n", event.motion.x, event.motion.y);
break;
case SDL_FINGERDOWN:
printf("touch_down x=%d, y=%d\n",
(int)(event.tfinger.x * screen.s.width),
(int)(event.tfinger.y * screen.s.height));
break;
case SDL_FINGERMOTION:
printf("touch_move x=%d, y=%d\n",
(int)(event.tfinger.x * screen.s.width),
(int)(event.tfinger.y * screen.s.height));
break;
}
}
SDL_UpdateTexture(texture, NULL, screen.s.buffer,
screen.s.width * sizeof(uint32_t));
SDL_RenderClear(renderer);
/* (Scales to fit screen while preserving pixel grid) */
SDL_Rect output_rect;
SDL_RenderGetViewport(renderer, &output_rect);
float scale_x = (float)output_rect.w / screen.s.width;
float scale_y = (float)output_rect.h / screen.s.height;
float scale = SDL_min(scale_x, scale_y);
SDL_Rect dstrect = {(int)((output_rect.w - screen.s.width * scale) / 2),
(int)((output_rect.h - screen.s.height * scale) / 2),
(int)(screen.s.width * scale),
(int)(screen.s.height * scale)};
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
SDL_RenderPresent(renderer);
}
return 0;
}

View File

@ -1,6 +1,5 @@
#include "../../compiler.h"
#include "../../vm.h"
#include <SDL2/SDL.h>
#define MAX_SRC_SIZE 16384
@ -64,94 +63,9 @@ int main(int argc, char **argv) {
return 64;
}
uint32_t buffer_size = 640 * 480 * sizeof(uint32_t);
Device screen;
screen.type = SCREEN;
screen.s = (Screen){.width = (uint8_t)480,
.height = (uint8_t)640,
.allocated = {vm.mp, buffer_size},
.buffer = &vm.memory[vm.mp]};
vm.devices[vm.dp++] = screen;
vm.mp += buffer_size;
Device mouse;
mouse.type = MOUSE;
mouse.m = (Mouse){.x = 0, .y = 0, .btn1 = 0, .btn2 = 0, .btn3 = 0};
vm.devices[vm.dp++] = mouse;
Device keyboard;
keyboard.type = KEYBOARD;
const uint8_t *state = SDL_GetKeyboardState(NULL);
keyboard.k = (Keyboard){.length = SDL_NUM_SCANCODES, .keys = state};
vm.devices[vm.dp++] = keyboard;
/* Create window and renderer */
SDL_Window *window =
SDL_CreateWindow("Reality Engine VM", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, screen.s.width, screen.s.height,
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
SDL_Renderer *renderer = SDL_CreateRenderer(
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
/* Create texture for 640x480 buffer */
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
screen.s.width, screen.s.height);
/* Enable nearest-neighbor scaling (preserves pixel art) */
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); /* "0" = nearest-neighbor */
bool running = true;
while (running) {
step_vm(&vm);
SDL_PumpEvents();
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN:
printf("mouse_down: x=%d, y=%d, btn=%d\n", event.button.x,
event.button.y, event.button.button);
break;
case SDL_MOUSEMOTION:
printf("mouse_move: x=%d, y=%d\n", event.motion.x, event.motion.y);
break;
case SDL_FINGERDOWN:
printf("touch_down x=%d, y=%d\n",
(int)(event.tfinger.x * screen.s.width),
(int)(event.tfinger.y * screen.s.height));
break;
case SDL_FINGERMOTION:
printf("touch_move x=%d, y=%d\n",
(int)(event.tfinger.x * screen.s.width),
(int)(event.tfinger.y * screen.s.height));
break;
}
}
SDL_UpdateTexture(texture, NULL, screen.s.buffer,
screen.s.width * sizeof(uint32_t));
SDL_RenderClear(renderer);
/* (Scales to fit screen while preserving pixel grid) */
SDL_Rect output_rect;
SDL_RenderGetViewport(renderer, &output_rect);
float scale_x = (float)output_rect.w / screen.s.width;
float scale_y = (float)output_rect.h / screen.s.height;
float scale = SDL_min(scale_x, scale_y);
SDL_Rect dstrect = {(int)((output_rect.w - screen.s.width * scale) / 2),
(int)((output_rect.h - screen.s.height * scale) / 2),
(int)(screen.s.width * scale),
(int)(screen.s.height * scale)};
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
SDL_RenderPresent(renderer);
running = step_vm(&vm);
}
return 0;
}

View File

@ -51,9 +51,7 @@ void errorAt(Token *token, const char *message) {
void error(const char *message) { errorAt(&parser.previous, message); }
void errorAtCurrent(const char *message) {
errorAt(&parser.current, message);
}
void errorAtCurrent(const char *message) { errorAt(&parser.current, message); }
void advance() {
parser.previous = parser.current;
@ -76,20 +74,16 @@ void consume(TokenType type, const char *message) {
errorAtCurrent(message);
}
static bool check(TokenType type) {
return parser.current.type == type;
}
static bool check(TokenType type) { return parser.current.type == type; }
static bool match(TokenType type) {
if (!check(type)) return false;
if (!check(type))
return false;
advance();
return true;
}
void emitOp(VM *vm, uint8_t opcode, uint8_t dest, uint8_t src1,
uint8_t src2) {
void emitOp(VM *vm, uint8_t opcode, uint8_t dest, uint8_t src1, uint8_t src2) {
vm->code[vm->cp++].u = OP(opcode, dest, src1, src2);
}
@ -155,22 +149,23 @@ void unary(VM *vm) {
static void literal(VM *vm) {
switch (parser.previous.type) {
case TOKEN_KEYWORD_NIL: {
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
vm->code[vm->cp++].u = 0;
break;
}
case TOKEN_KEYWORD_FALSE: {
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
vm->code[vm->cp++].u = 0;
break;
}
case TOKEN_KEYWORD_TRUE: {
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
vm->code[vm->cp++].u = 1;
break;
}
default: return;
case TOKEN_KEYWORD_NIL: {
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
vm->code[vm->cp++].u = 0;
break;
}
case TOKEN_KEYWORD_FALSE: {
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
vm->code[vm->cp++].u = 0;
break;
}
case TOKEN_KEYWORD_TRUE: {
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
vm->code[vm->cp++].u = 1;
break;
}
default:
return;
}
}
@ -180,25 +175,18 @@ void binary(VM *vm) {
parsePrecedence(vm, (Precedence)(rule->precedence + 1));
TokenType operandType = parser.previous.type;
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
switch (operatorType) {
case TOKEN_PLUS:
if (operandType == TOKEN_UINT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_ADD_UINT, dest, src1, src2);
} else if (operandType == TOKEN_INT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_ADD_INT, dest, src1, src2);
} else if (operandType == TOKEN_FLOAT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_ADD_REAL, dest, src1, src2);
} else {
error("not numeric");
@ -206,22 +194,10 @@ void binary(VM *vm) {
break;
case TOKEN_MINUS:
if (operandType == TOKEN_UINT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_SUB_UINT, dest, src1, src2);
} else if (operandType == TOKEN_INT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_SUB_INT, dest, src1, src2);
} else if (operandType == TOKEN_FLOAT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_SUB_REAL, dest, src1, src2);
} else {
error("not numeric");
@ -229,22 +205,10 @@ void binary(VM *vm) {
break;
case TOKEN_STAR:
if (operandType == TOKEN_UINT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_MUL_UINT, dest, src1, src2);
} else if (operandType == TOKEN_INT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_MUL_INT, dest, src1, src2);
} else if (operandType == TOKEN_FLOAT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_MUL_REAL, dest, src1, src2);
} else {
error("not numeric");
@ -252,22 +216,10 @@ void binary(VM *vm) {
break;
case TOKEN_SLASH:
if (operandType == TOKEN_UINT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_DIV_UINT, dest, src1, src2);
} else if (operandType == TOKEN_INT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_DIV_INT, dest, src1, src2);
} else if (operandType == TOKEN_FLOAT_LITERAL) {
Frame f = vm->frames[vm->fp];
uint32_t src1 = f.rp--;
uint32_t src2 = f.rp--;
uint32_t dest = f.rp++;
emitOp(vm, OP_DIV_REAL, dest, src1, src2);
} else {
error("not numeric");
@ -355,18 +307,29 @@ static void expressionStatement(VM *vm) {
consume(TOKEN_SEMICOLON, "Expect ';' after expression.");
}
static void intDeclaration(VM *vm) {
/* insert variable name in symbol table */
if (match(TOKEN_EQ)) {
expression(vm);
} else {
/* not sure here yet */
}
consume(TOKEN_SEMICOLON, "Expect ';' after expression.");
}
void statement(VM *vm) {
if (match(TOKEN_KEYWORD_PRINT)) {
printStatement(vm);
} else if (match(TOKEN_TYPE_INT)) {
intDeclaration(vm);
} else {
expressionStatement(vm);
}
}
void declaration(VM *vm) {
statement(vm);
}
void declaration(VM *vm) { statement(vm); }
bool compile(const char *source, VM *vm) {
initLexer(source);

View File

@ -4,6 +4,15 @@
#include "lexer.h"
#include "opcodes.h"
typedef struct symbol_table_t {
char name[32];
} Symbol;
typedef struct module_t {
char name[32];
Symbol list[256];
} Module;
bool compile(const char* source, VM* vm);

View File

@ -77,21 +77,21 @@ typedef struct vm_s {
} VM;
typedef enum {
OP_HALT, /* halt : terminate execution */
OP_LOADI, /* lodi : dest = next memory location as int */
OP_LOADU, /* lodu : dest = next memory location as uint */
OP_LOADF, /* lodf : dest = next memory location as float */
OP_STOREI, /* stri : next memory location = src1 as int */
OP_STOREU, /* stru : next memory location = src1 as uint */
OP_STOREF, /* strf : next memory location = src1 as float */
OP_PUSHI, /* pshi : push int from register onto the stack */
OP_PUSHU, /* pshu : push uint from register onto the stack */
OP_PUSHF, /* pshf : push float from register onto the stack */
OP_PUSHS, /* pshs : push str ref from register onto the stack and copy str */
OP_POPI, /* popi : pop int from stack onto the register */
OP_POPU, /* popu : pop uint from stack onto the register */
OP_POPF, /* popf : pop float from stack onto the register */
OP_POPS, /* pops : pop str ref from stack and move/copy to register */
OP_HALT, /* halt : terminate execution */
OP_LOADI, /* lodi : dest = next memory location as int */
OP_LOADU, /* lodu : dest = next memory location as uint */
OP_LOADF, /* lodf : dest = next memory location as float */
OP_STOREI, /* stri : next memory location = src1 as int */
OP_STOREU, /* stru : next memory location = src1 as uint */
OP_STOREF, /* strf : next memory location = src1 as float */
OP_PUSHI, /* pshi : push int from register onto the stack */
OP_PUSHU, /* pshu : push uint from register onto the stack */
OP_PUSHF, /* pshf : push float from register onto the stack */
OP_PUSHS, /* pshs : push str ref from register onto the stack and copy str */
OP_POPI, /* popi : pop int from stack onto the register */
OP_POPU, /* popu : pop uint from stack onto the register */
OP_POPF, /* popf : pop float from stack onto the register */
OP_POPS, /* pops : pop str ref from stack and move/copy to register */
OP_ADD_INT, /* addi : dest = src1 + src2 */
OP_SUB_INT, /* subi : dest = src1 - src2 */
OP_MUL_INT, /* muli : dest = src1 * src2 */
@ -123,7 +123,8 @@ typedef enum {
OP_JLE_REAL, /* jger : jump to address dest if src1 as real <= src2 as real */
OP_REAL_TO_INT, /* rtoi : dest = src1 as int */
OP_REAL_TO_UINT, /* rtou : dest = src1 as uint */
OP_MOV, /* move : dest = src1 */
OP_REG_MOV, /* rmov : dest = src1 */
OP_REG_SWAP, /* rswp : dest = src1, src1 = dest */
OP_JMP, /* jump : jump to address src1 unconditionally */
OP_CALL, /* call : creates a new frame */
OP_RETURN, /* retn : returns from a frame to the parent frame */
@ -134,6 +135,10 @@ typedef enum {
OP_PRINT_STRING, /* puts : write src1 to stdout */
OP_CMP_STRING, /* cmps : dest = (str == src2) as bool */
OP_NOT,
OP_MEM_SWAP,
OP_MEM_MOV,
OP_NEW_ARRAY,
OP_NEW_PLEX,
} Opcode;
typedef enum {

View File

@ -150,8 +150,16 @@ bool step_vm(VM *vm) {
vm->frames[vm->fp].registers[dest].f =
(float)(vm->frames[vm->fp].registers[src1].u);
return true;
case OP_MOV:
vm->frames[vm->fp].registers[dest] = vm->frames[vm->fp].registers[src1];
case OP_REG_SWAP:
vm->frames[vm->fp].registers[dest].u ^=
vm->frames[vm->fp].registers[src1].u;
vm->frames[vm->fp].registers[src1].u ^=
vm->frames[vm->fp].registers[dest].u;
vm->frames[vm->fp].registers[dest].u ^=
vm->frames[vm->fp].registers[src1].u;
return true;
case OP_REG_MOV:
vm->frames[vm->fp].registers[dest].i = vm->code[vm->pc++].i;
return true;
case OP_JMP:
vm->pc = vm->frames[vm->fp].registers[dest].u; /* Jump to address */
@ -288,6 +296,42 @@ bool step_vm(VM *vm) {
vm->memory[dest].u = equal;
return true;
}
case OP_NEW_ARRAY: {
uint32_t arr_dest = (uint32_t)vm->frames[vm->fp]
.allocated.end; /* get start of unallocated */
vm->frames[vm->fp].registers[dest].u =
arr_dest; /* store ptr of array to dest register */
uint32_t length = vm->code[vm->pc++].u;
if (src1) { /* if has inline data */
uint32_t i = 0;
for (i = 0; i < length; i++) {
vm->memory[arr_dest + i] = vm->code[vm->pc++];
}
}
vm->memory[arr_dest].u = length;
vm->frames[vm->fp].allocated.end +=
length; /* increment to end of allocated */
return true;
}
case OP_NEW_PLEX: {
uint32_t plex_dest = (uint32_t)vm->frames[vm->fp]
.allocated.end; /* get start of unallocated */
vm->frames[vm->fp].registers[dest].u =
plex_dest; /* store ptr of array to dest register */
uint32_t length = vm->code[vm->pc++].u;
vm->memory[plex_dest].u = length;
vm->frames[vm->fp].allocated.end +=
length; /* increment to end of allocated */
return true;
}
case OP_MEM_MOV:
vm->memory[dest] = vm->memory[src1];
return true;
case OP_MEM_SWAP:
vm->memory[dest].u ^= vm->memory[src1].u;
vm->memory[src1].u ^= vm->memory[dest].u;
vm->memory[dest].u ^= vm->memory[src1].u;
return true;
}
return false; /* something bad happened */
}

View File

@ -3,4 +3,4 @@ fn add(int a, int b) int {
}
int sum = add(1, 1);
print(sum.toS());
print(sum.str);

View File

@ -1 +1 @@
print("nuqheH 'u'?");
print("nuqneH 'u'?");

View File

@ -1,2 +1,2 @@
int sum = 1 + 2;
print(sum.toS());
print(sum.str);