move sdl to own thing, add array + plex handling
This commit is contained in:
parent
70b9a82a97
commit
63d67b5c0d
|
@ -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;
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
#include "../../compiler.h"
|
#include "../../compiler.h"
|
||||||
#include "../../vm.h"
|
#include "../../vm.h"
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#define MAX_SRC_SIZE 16384
|
#define MAX_SRC_SIZE 16384
|
||||||
|
|
||||||
|
@ -64,94 +63,9 @@ int main(int argc, char **argv) {
|
||||||
return 64;
|
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;
|
bool running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
step_vm(&vm);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
123
src/compiler.c
123
src/compiler.c
|
@ -51,9 +51,7 @@ void errorAt(Token *token, const char *message) {
|
||||||
|
|
||||||
void error(const char *message) { errorAt(&parser.previous, message); }
|
void error(const char *message) { errorAt(&parser.previous, message); }
|
||||||
|
|
||||||
void errorAtCurrent(const char *message) {
|
void errorAtCurrent(const char *message) { errorAt(&parser.current, message); }
|
||||||
errorAt(&parser.current, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void advance() {
|
void advance() {
|
||||||
parser.previous = parser.current;
|
parser.previous = parser.current;
|
||||||
|
@ -76,20 +74,16 @@ void consume(TokenType type, const char *message) {
|
||||||
errorAtCurrent(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) {
|
static bool match(TokenType type) {
|
||||||
if (!check(type)) return false;
|
if (!check(type))
|
||||||
|
return false;
|
||||||
advance();
|
advance();
|
||||||
return true;
|
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);
|
vm->code[vm->cp++].u = OP(opcode, dest, src1, src2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,22 +149,23 @@ void unary(VM *vm) {
|
||||||
|
|
||||||
static void literal(VM *vm) {
|
static void literal(VM *vm) {
|
||||||
switch (parser.previous.type) {
|
switch (parser.previous.type) {
|
||||||
case TOKEN_KEYWORD_NIL: {
|
case TOKEN_KEYWORD_NIL: {
|
||||||
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
|
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
|
||||||
vm->code[vm->cp++].u = 0;
|
vm->code[vm->cp++].u = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TOKEN_KEYWORD_FALSE: {
|
case TOKEN_KEYWORD_FALSE: {
|
||||||
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
|
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
|
||||||
vm->code[vm->cp++].u = 0;
|
vm->code[vm->cp++].u = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TOKEN_KEYWORD_TRUE: {
|
case TOKEN_KEYWORD_TRUE: {
|
||||||
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
|
emitOp(vm, OP_LOADU, vm->frames[vm->fp].rp++, 0, 0);
|
||||||
vm->code[vm->cp++].u = 1;
|
vm->code[vm->cp++].u = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: return;
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,25 +175,18 @@ void binary(VM *vm) {
|
||||||
parsePrecedence(vm, (Precedence)(rule->precedence + 1));
|
parsePrecedence(vm, (Precedence)(rule->precedence + 1));
|
||||||
TokenType operandType = parser.previous.type;
|
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) {
|
switch (operatorType) {
|
||||||
case TOKEN_PLUS:
|
case TOKEN_PLUS:
|
||||||
if (operandType == TOKEN_UINT_LITERAL) {
|
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);
|
emitOp(vm, OP_ADD_UINT, dest, src1, src2);
|
||||||
} else if (operandType == TOKEN_INT_LITERAL) {
|
} 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);
|
emitOp(vm, OP_ADD_INT, dest, src1, src2);
|
||||||
} else if (operandType == TOKEN_FLOAT_LITERAL) {
|
} 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);
|
emitOp(vm, OP_ADD_REAL, dest, src1, src2);
|
||||||
} else {
|
} else {
|
||||||
error("not numeric");
|
error("not numeric");
|
||||||
|
@ -206,22 +194,10 @@ void binary(VM *vm) {
|
||||||
break;
|
break;
|
||||||
case TOKEN_MINUS:
|
case TOKEN_MINUS:
|
||||||
if (operandType == TOKEN_UINT_LITERAL) {
|
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);
|
emitOp(vm, OP_SUB_UINT, dest, src1, src2);
|
||||||
} else if (operandType == TOKEN_INT_LITERAL) {
|
} 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);
|
emitOp(vm, OP_SUB_INT, dest, src1, src2);
|
||||||
} else if (operandType == TOKEN_FLOAT_LITERAL) {
|
} 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);
|
emitOp(vm, OP_SUB_REAL, dest, src1, src2);
|
||||||
} else {
|
} else {
|
||||||
error("not numeric");
|
error("not numeric");
|
||||||
|
@ -229,22 +205,10 @@ void binary(VM *vm) {
|
||||||
break;
|
break;
|
||||||
case TOKEN_STAR:
|
case TOKEN_STAR:
|
||||||
if (operandType == TOKEN_UINT_LITERAL) {
|
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);
|
emitOp(vm, OP_MUL_UINT, dest, src1, src2);
|
||||||
} else if (operandType == TOKEN_INT_LITERAL) {
|
} 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);
|
emitOp(vm, OP_MUL_INT, dest, src1, src2);
|
||||||
} else if (operandType == TOKEN_FLOAT_LITERAL) {
|
} 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);
|
emitOp(vm, OP_MUL_REAL, dest, src1, src2);
|
||||||
} else {
|
} else {
|
||||||
error("not numeric");
|
error("not numeric");
|
||||||
|
@ -252,22 +216,10 @@ void binary(VM *vm) {
|
||||||
break;
|
break;
|
||||||
case TOKEN_SLASH:
|
case TOKEN_SLASH:
|
||||||
if (operandType == TOKEN_UINT_LITERAL) {
|
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);
|
emitOp(vm, OP_DIV_UINT, dest, src1, src2);
|
||||||
} else if (operandType == TOKEN_INT_LITERAL) {
|
} 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);
|
emitOp(vm, OP_DIV_INT, dest, src1, src2);
|
||||||
} else if (operandType == TOKEN_FLOAT_LITERAL) {
|
} 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);
|
emitOp(vm, OP_DIV_REAL, dest, src1, src2);
|
||||||
} else {
|
} else {
|
||||||
error("not numeric");
|
error("not numeric");
|
||||||
|
@ -347,7 +299,7 @@ void printStatement(VM *vm) {
|
||||||
expression(vm);
|
expression(vm);
|
||||||
consume(TOKEN_SEMICOLON, "Expect ';' after value.");
|
consume(TOKEN_SEMICOLON, "Expect ';' after value.");
|
||||||
Frame f = vm->frames[vm->fp];
|
Frame f = vm->frames[vm->fp];
|
||||||
vm->code[vm->cp++].u = OP(OP_PRINT_STRING, 0, f.rp--, 0);
|
vm->code[vm->cp++].u = OP(OP_PRINT_STRING, 0, f.rp--, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void expressionStatement(VM *vm) {
|
static void expressionStatement(VM *vm) {
|
||||||
|
@ -355,18 +307,29 @@ static void expressionStatement(VM *vm) {
|
||||||
consume(TOKEN_SEMICOLON, "Expect ';' after expression.");
|
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) {
|
void statement(VM *vm) {
|
||||||
if (match(TOKEN_KEYWORD_PRINT)) {
|
if (match(TOKEN_KEYWORD_PRINT)) {
|
||||||
printStatement(vm);
|
printStatement(vm);
|
||||||
|
} else if (match(TOKEN_TYPE_INT)) {
|
||||||
|
intDeclaration(vm);
|
||||||
} else {
|
} else {
|
||||||
expressionStatement(vm);
|
expressionStatement(vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void declaration(VM *vm) {
|
void declaration(VM *vm) { statement(vm); }
|
||||||
statement(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool compile(const char *source, VM *vm) {
|
bool compile(const char *source, VM *vm) {
|
||||||
initLexer(source);
|
initLexer(source);
|
||||||
|
|
|
@ -4,6 +4,15 @@
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
#include "opcodes.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);
|
bool compile(const char* source, VM* vm);
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ typedef struct mouse_t {
|
||||||
uint8_t btn3;
|
uint8_t btn3;
|
||||||
} Mouse;
|
} Mouse;
|
||||||
|
|
||||||
typedef struct keyboard_t {
|
typedef struct keyboard_t {
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
const uint8_t *keys;
|
const uint8_t *keys;
|
||||||
} Keyboard;
|
} Keyboard;
|
||||||
|
@ -51,7 +51,7 @@ typedef union device_u {
|
||||||
|
|
||||||
#define MEMORY_SIZE 65536
|
#define MEMORY_SIZE 65536
|
||||||
#define CODE_SIZE 8192
|
#define CODE_SIZE 8192
|
||||||
#define FRAMES_SIZE 128
|
#define FRAMES_SIZE 128
|
||||||
#define STACK_SIZE 256
|
#define STACK_SIZE 256
|
||||||
#define DEVICES_SIZE 8
|
#define DEVICES_SIZE 8
|
||||||
typedef struct vm_s {
|
typedef struct vm_s {
|
||||||
|
@ -77,21 +77,21 @@ typedef struct vm_s {
|
||||||
} VM;
|
} VM;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OP_HALT, /* halt : terminate execution */
|
OP_HALT, /* halt : terminate execution */
|
||||||
OP_LOADI, /* lodi : dest = next memory location as int */
|
OP_LOADI, /* lodi : dest = next memory location as int */
|
||||||
OP_LOADU, /* lodu : dest = next memory location as uint */
|
OP_LOADU, /* lodu : dest = next memory location as uint */
|
||||||
OP_LOADF, /* lodf : dest = next memory location as float */
|
OP_LOADF, /* lodf : dest = next memory location as float */
|
||||||
OP_STOREI, /* stri : next memory location = src1 as int */
|
OP_STOREI, /* stri : next memory location = src1 as int */
|
||||||
OP_STOREU, /* stru : next memory location = src1 as uint */
|
OP_STOREU, /* stru : next memory location = src1 as uint */
|
||||||
OP_STOREF, /* strf : next memory location = src1 as float */
|
OP_STOREF, /* strf : next memory location = src1 as float */
|
||||||
OP_PUSHI, /* pshi : push int from register onto the stack */
|
OP_PUSHI, /* pshi : push int from register onto the stack */
|
||||||
OP_PUSHU, /* pshu : push uint 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_PUSHF, /* pshf : push float from register onto the stack */
|
||||||
OP_PUSHS, /* pshs : push str ref from register onto the stack and copy str */
|
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_POPI, /* popi : pop int from stack onto the register */
|
||||||
OP_POPU, /* popu : pop uint 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_POPF, /* popf : pop float from stack onto the register */
|
||||||
OP_POPS, /* pops : pop str ref from stack and move/copy to register */
|
OP_POPS, /* pops : pop str ref from stack and move/copy to register */
|
||||||
OP_ADD_INT, /* addi : dest = src1 + src2 */
|
OP_ADD_INT, /* addi : dest = src1 + src2 */
|
||||||
OP_SUB_INT, /* subi : dest = src1 - src2 */
|
OP_SUB_INT, /* subi : dest = src1 - src2 */
|
||||||
OP_MUL_INT, /* muli : 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_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_INT, /* rtoi : dest = src1 as int */
|
||||||
OP_REAL_TO_UINT, /* rtou : dest = src1 as uint */
|
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_JMP, /* jump : jump to address src1 unconditionally */
|
||||||
OP_CALL, /* call : creates a new frame */
|
OP_CALL, /* call : creates a new frame */
|
||||||
OP_RETURN, /* retn : returns from a frame to the parent 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_PRINT_STRING, /* puts : write src1 to stdout */
|
||||||
OP_CMP_STRING, /* cmps : dest = (str == src2) as bool */
|
OP_CMP_STRING, /* cmps : dest = (str == src2) as bool */
|
||||||
OP_NOT,
|
OP_NOT,
|
||||||
|
OP_MEM_SWAP,
|
||||||
|
OP_MEM_MOV,
|
||||||
|
OP_NEW_ARRAY,
|
||||||
|
OP_NEW_PLEX,
|
||||||
} Opcode;
|
} Opcode;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
48
src/vm.c
48
src/vm.c
|
@ -150,8 +150,16 @@ bool step_vm(VM *vm) {
|
||||||
vm->frames[vm->fp].registers[dest].f =
|
vm->frames[vm->fp].registers[dest].f =
|
||||||
(float)(vm->frames[vm->fp].registers[src1].u);
|
(float)(vm->frames[vm->fp].registers[src1].u);
|
||||||
return true;
|
return true;
|
||||||
case OP_MOV:
|
case OP_REG_SWAP:
|
||||||
vm->frames[vm->fp].registers[dest] = vm->frames[vm->fp].registers[src1];
|
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;
|
return true;
|
||||||
case OP_JMP:
|
case OP_JMP:
|
||||||
vm->pc = vm->frames[vm->fp].registers[dest].u; /* Jump to address */
|
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;
|
vm->memory[dest].u = equal;
|
||||||
return true;
|
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 */
|
return false; /* something bad happened */
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@ fn add(int a, int b) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
int sum = add(1, 1);
|
int sum = add(1, 1);
|
||||||
print(sum.toS());
|
print(sum.str);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
print("nuqheH 'u'?");
|
print("nuqneH 'u'?");
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
int sum = 1 + 2;
|
int sum = 1 + 2;
|
||||||
print(sum.toS());
|
print(sum.str);
|
||||||
|
|
Loading…
Reference in New Issue