mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Began writing Toy_VM, read more
Toy_VM and Toy_Stack are both considered WIP, and neither has any tests yet.
This commit is contained in:
@@ -86,7 +86,7 @@ static void writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) {
|
|||||||
EMIT_FLOAT(rt, code, TOY_VALUE_AS_FLOAT(ast.value));
|
EMIT_FLOAT(rt, code, TOY_VALUE_AS_FLOAT(ast.value));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown value type\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST type found: Unknown value type\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ static void writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) {
|
|||||||
EMIT_BYTE(rt, 0);
|
EMIT_BYTE(rt, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, TOY_CC_ERROR "Invalid AST unary flag found\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST unary flag found\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +196,7 @@ static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) {
|
|||||||
EMIT_BYTE(rt, TOY_OPCODE_OR);
|
EMIT_BYTE(rt, TOY_OPCODE_OR);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, TOY_CC_ERROR "Invalid AST binary flag found\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST binary flag found\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,24 +237,24 @@ static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
|
|||||||
|
|
||||||
//other disallowed instructions
|
//other disallowed instructions
|
||||||
case TOY_AST_GROUP:
|
case TOY_AST_GROUP:
|
||||||
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Group shouldn't be used\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST type found: Group shouldn't be used\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_AST_PASS:
|
case TOY_AST_PASS:
|
||||||
//NOTE: this should be disallowed, but for now it's required for testing
|
//NOTE: this should be disallowed, but for now it's required for testing
|
||||||
// fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown pass\n" TOY_CC_RESET);
|
// fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST type found: Unknown pass\n" TOY_CC_RESET);
|
||||||
// exit(-1);
|
// exit(-1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//meta instructions are disallowed
|
//meta instructions are disallowed
|
||||||
case TOY_AST_ERROR:
|
case TOY_AST_ERROR:
|
||||||
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown error\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST type found: Unknown error\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOY_AST_END:
|
case TOY_AST_END:
|
||||||
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown end\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST type found: Unknown end\n" TOY_CC_RESET);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
72
source/toy_stack.c
Normal file
72
source/toy_stack.c
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#include "toy_stack.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
|
#include "toy_memory.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//a good chunk of space
|
||||||
|
#define MIN_SIZE 64
|
||||||
|
|
||||||
|
TOY_API void Toy_initStack(Toy_Stack* stack) {
|
||||||
|
stack->ptr = NULL;
|
||||||
|
stack->capacity = 0;
|
||||||
|
stack->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_preallocateStack(Toy_Stack* stack) {
|
||||||
|
stack->capacity = MIN_SIZE;
|
||||||
|
stack->count = 0;
|
||||||
|
|
||||||
|
stack->ptr = TOY_ALLOCATE(Toy_Value, stack->capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_freeStack(Toy_Stack* stack) {
|
||||||
|
//TODO: slip in a call to free the complex values here
|
||||||
|
|
||||||
|
TOY_FREE_ARRAY(Toy_Value, stack->ptr, stack->capacity);
|
||||||
|
|
||||||
|
Toy_initStack(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_pushStack(Toy_Stack* stack, Toy_Value value) {
|
||||||
|
//don't go overboard - limit to 1mb
|
||||||
|
if (stack->count >= 1024 * 1024 / sizeof(Toy_Value)) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack overflow, exiting\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//expand the capacity if needed
|
||||||
|
if (stack->count + 1 > stack->capacity) {
|
||||||
|
int oldCapacity = stack->capacity;
|
||||||
|
stack->capacity = TOY_GROW_CAPACITY(stack->capacity);
|
||||||
|
stack->ptr = TOY_GROW_ARRAY(Toy_Value, stack->ptr, oldCapacity, stack->capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
stack->ptr[stack->count++] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Value Toy_peekStack(Toy_Stack* stack) {
|
||||||
|
if (stack->count <= 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow, exiting\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack->ptr[stack->count - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Value Toy_popStack(Toy_Stack* stack) {
|
||||||
|
if (stack->count <= 0) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Stack underflow, exiting\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//shrink if possible
|
||||||
|
if (stack->count > MIN_SIZE && stack->count < stack->capacity / 4) {
|
||||||
|
stack->ptr = TOY_SHRINK_ARRAY(Toy_Value, stack->ptr, stack->capacity, stack->capacity / 2);
|
||||||
|
stack->capacity /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack->ptr[--stack->count];
|
||||||
|
}
|
||||||
18
source/toy_stack.h
Normal file
18
source/toy_stack.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "toy_common.h"
|
||||||
|
#include "toy_value.h"
|
||||||
|
|
||||||
|
typedef struct Toy_Stack {
|
||||||
|
Toy_Value* ptr;
|
||||||
|
int capacity;
|
||||||
|
int count;
|
||||||
|
} Toy_Stack;
|
||||||
|
|
||||||
|
TOY_API void Toy_initStack(Toy_Stack* stack); //null memory
|
||||||
|
TOY_API void Toy_preallocateStack(Toy_Stack* stack); //non-null memory, ready to go
|
||||||
|
TOY_API void Toy_freeStack(Toy_Stack* stack);
|
||||||
|
|
||||||
|
TOY_API void Toy_pushStack(Toy_Stack* stack, Toy_Value value);
|
||||||
|
TOY_API Toy_Value Toy_peekStack(Toy_Stack* stack);
|
||||||
|
TOY_API Toy_Value Toy_popStack(Toy_Stack* stack);
|
||||||
@@ -28,7 +28,7 @@ typedef struct Toy_Value {
|
|||||||
} as; //4
|
} as; //4
|
||||||
|
|
||||||
Toy_ValueType type; //4
|
Toy_ValueType type; //4
|
||||||
} Toy_Value;
|
} Toy_Value; //8
|
||||||
|
|
||||||
#define TOY_VALUE_IS_NULL(value) ((value).type == TOY_VALUE_NULL)
|
#define TOY_VALUE_IS_NULL(value) ((value).type == TOY_VALUE_NULL)
|
||||||
#define TOY_VALUE_IS_BOOLEAN(value) ((value).type == TOY_VALUE_BOOLEAN)
|
#define TOY_VALUE_IS_BOOLEAN(value) ((value).type == TOY_VALUE_BOOLEAN)
|
||||||
|
|||||||
303
source/toy_vm.c
Normal file
303
source/toy_vm.c
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
#include "toy_vm.h"
|
||||||
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
|
#include "toy_memory.h"
|
||||||
|
#include "toy_opcodes.h"
|
||||||
|
#include "toy_value.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//utilities
|
||||||
|
#define READ_BYTE(vm) \
|
||||||
|
vm->program[vm->programCounter++]
|
||||||
|
|
||||||
|
#define READ_INT(vm) \
|
||||||
|
*((int*)(vm->program + _read_postfix(&(vm->programCounter), 4)))
|
||||||
|
|
||||||
|
#define READ_FLOAT(vm) \
|
||||||
|
*((float*)(vm->program + _read_postfix(&(vm->programCounter), 4)))
|
||||||
|
|
||||||
|
static inline int _read_postfix(int* ptr, int amount) {
|
||||||
|
int ret = *ptr;
|
||||||
|
*ptr += amount;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void fix_alignment(Toy_VM* vm) {
|
||||||
|
if (vm->programCounter % 4 != 0) {
|
||||||
|
vm->programCounter = (4 - vm->programCounter % 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//instruction handlers
|
||||||
|
static void processRead(Toy_VM* vm) {
|
||||||
|
Toy_ValueType type = READ_BYTE(vm);
|
||||||
|
|
||||||
|
Toy_Value value = TOY_VALUE_TO_NULL();
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case TOY_VALUE_NULL: {
|
||||||
|
//No-op
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOY_VALUE_BOOLEAN: {
|
||||||
|
value = TOY_VALUE_TO_BOOLEAN((bool)READ_BYTE(vm));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOY_VALUE_INTEGER: {
|
||||||
|
fix_alignment(vm);
|
||||||
|
value = TOY_VALUE_TO_INTEGER(READ_INT(vm));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOY_VALUE_FLOAT: {
|
||||||
|
fix_alignment(vm);
|
||||||
|
value = TOY_VALUE_TO_FLOAT(READ_FLOAT(vm));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOY_VALUE_STRING: {
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOY_VALUE_ARRAY: {
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOY_VALUE_DICTIONARY: {
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOY_VALUE_FUNCTION: {
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOY_VALUE_OPAQUE: {
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid value type %d found, exiting\n" TOY_CC_RESET, type);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//push onto the stack
|
||||||
|
Toy_pushStack(&vm->stack, value);
|
||||||
|
|
||||||
|
//leave the counter in a good spot
|
||||||
|
fix_alignment(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
|
||||||
|
Toy_Value right = Toy_popStack(&vm->stack);
|
||||||
|
Toy_Value left = Toy_popStack(&vm->stack);
|
||||||
|
|
||||||
|
//check types
|
||||||
|
if ((!TOY_VALUE_IS_INTEGER(left) && !TOY_VALUE_IS_FLOAT(left)) || (!TOY_VALUE_IS_INTEGER(right) && !TOY_VALUE_IS_FLOAT(right))) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid types %d and %d passed to processArithmetic, exiting\n" TOY_CC_RESET, left.type, right.type);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//check for divide by zero
|
||||||
|
if (opcode == TOY_OPCODE_DIVIDE || opcode == TOY_OPCODE_MODULO) {
|
||||||
|
if ((TOY_VALUE_IS_INTEGER(right) && TOY_VALUE_AS_INTEGER(right) == 0) || (TOY_VALUE_IS_FLOAT(right) && TOY_VALUE_AS_FLOAT(right) == 0)) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't divide by zero, exiting\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//check for modulo by a float
|
||||||
|
if (opcode == TOY_OPCODE_MODULO && TOY_VALUE_IS_FLOAT(right)) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Can't modulo by a float, exiting\n" TOY_CC_RESET);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//coerce ints into floats if needed
|
||||||
|
if (TOY_VALUE_IS_INTEGER(left) && TOY_VALUE_IS_FLOAT(right)) {
|
||||||
|
left = TOY_VALUE_TO_FLOAT( (float)TOY_VALUE_AS_INTEGER(left) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (TOY_VALUE_IS_FLOAT(left) && TOY_VALUE_IS_INTEGER(right)) {
|
||||||
|
right = TOY_VALUE_TO_FLOAT( (float)TOY_VALUE_AS_INTEGER(right) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//apply operation
|
||||||
|
Toy_Value result = TOY_VALUE_TO_NULL();
|
||||||
|
|
||||||
|
if (opcode == TOY_OPCODE_ADD) {
|
||||||
|
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_TO_FLOAT( TOY_VALUE_AS_FLOAT(left) + TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) + TOY_VALUE_AS_INTEGER(right) );
|
||||||
|
}
|
||||||
|
else if (opcode == TOY_OPCODE_SUBTRACT) {
|
||||||
|
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_TO_FLOAT( TOY_VALUE_AS_FLOAT(left) - TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) - TOY_VALUE_AS_INTEGER(right) );
|
||||||
|
}
|
||||||
|
else if (opcode == TOY_OPCODE_MULTIPLY) {
|
||||||
|
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_TO_FLOAT( TOY_VALUE_AS_FLOAT(left) * TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) * TOY_VALUE_AS_INTEGER(right) );
|
||||||
|
}
|
||||||
|
else if (opcode == TOY_OPCODE_DIVIDE) {
|
||||||
|
result = TOY_VALUE_IS_FLOAT(left) ? TOY_VALUE_TO_FLOAT( TOY_VALUE_AS_FLOAT(left) / TOY_VALUE_AS_FLOAT(right)) : TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) / TOY_VALUE_AS_INTEGER(right) );
|
||||||
|
}
|
||||||
|
else if (opcode == TOY_OPCODE_MODULO) {
|
||||||
|
result = TOY_VALUE_TO_INTEGER( TOY_VALUE_AS_INTEGER(left) % TOY_VALUE_AS_INTEGER(right) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid opcode %d passed to processArithmetic, exiting\n" TOY_CC_RESET, opcode);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//finally
|
||||||
|
Toy_pushStack(&vm->stack, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process(Toy_VM* vm) {
|
||||||
|
Toy_OpcodeType opcode = READ_BYTE(vm);
|
||||||
|
|
||||||
|
switch(opcode) {
|
||||||
|
case TOY_OPCODE_READ:
|
||||||
|
processRead(vm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_ADD:
|
||||||
|
case TOY_OPCODE_SUBTRACT:
|
||||||
|
case TOY_OPCODE_MULTIPLY:
|
||||||
|
case TOY_OPCODE_DIVIDE:
|
||||||
|
case TOY_OPCODE_MODULO:
|
||||||
|
processArithmetic(vm, opcode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_COMPARE_EQUAL:
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_COMPARE_LESS:
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_COMPARE_LESS_EQUAL:
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_COMPARE_GREATER:
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_COMPARE_GREATER_EQUAL:
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_AND:
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_OR:
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_TRUTHY:
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_NEGATE: //TODO: squeeze into !=
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case TOY_OPCODE_LOAD:
|
||||||
|
case TOY_OPCODE_LOAD_LONG:
|
||||||
|
case TOY_OPCODE_DECLARE:
|
||||||
|
case TOY_OPCODE_ASSIGN:
|
||||||
|
case TOY_OPCODE_ACCESS:
|
||||||
|
case TOY_OPCODE_PASS:
|
||||||
|
case TOY_OPCODE_ERROR:
|
||||||
|
case TOY_OPCODE_EOF:
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid opcode %d found, exiting\n" TOY_CC_RESET, opcode);
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
case TOY_OPCODE_RETURN: //temp terminator, temp position
|
||||||
|
//
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//exposed functions
|
||||||
|
void Toy_initVM(Toy_VM* vm) {
|
||||||
|
vm->program = NULL;
|
||||||
|
vm->programSize = 0;
|
||||||
|
|
||||||
|
vm->paramCount = 0;
|
||||||
|
vm->jumpsCount = 0;
|
||||||
|
vm->dataCount = 0;
|
||||||
|
vm->subsCount = 0;
|
||||||
|
|
||||||
|
vm->paramAddr = 0;
|
||||||
|
vm->codeAddr = 0;
|
||||||
|
vm->jumpsAddr = 0;
|
||||||
|
vm->dataAddr = 0;
|
||||||
|
vm->subsAddr = 0;
|
||||||
|
|
||||||
|
vm->programCounter = 0;
|
||||||
|
|
||||||
|
//init the scope & stack
|
||||||
|
Toy_initStack(&vm->stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_bindVM(Toy_VM* vm, unsigned char* program) {
|
||||||
|
vm->program = program;
|
||||||
|
|
||||||
|
//read the header metadata
|
||||||
|
vm->programSize = READ_INT(vm);
|
||||||
|
vm->paramCount = READ_INT(vm);
|
||||||
|
vm->jumpsCount = READ_INT(vm);
|
||||||
|
vm->dataCount = READ_INT(vm);
|
||||||
|
vm->subsCount = READ_INT(vm);
|
||||||
|
|
||||||
|
//read the header addresses
|
||||||
|
if (vm->paramCount > 0) {
|
||||||
|
vm->paramAddr = READ_INT(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
vm->codeAddr = READ_INT(vm);
|
||||||
|
|
||||||
|
if (vm->jumpsCount > 0) {
|
||||||
|
vm->jumpsAddr = READ_INT(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm->dataCount > 0) {
|
||||||
|
vm->dataAddr = READ_INT(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm->subsCount > 0) {
|
||||||
|
vm->subsAddr = READ_INT(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
//preallocate the scope & stack
|
||||||
|
Toy_preallocateStack(&vm->stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_runVM(Toy_VM* vm) {
|
||||||
|
//TODO: read params into scope
|
||||||
|
|
||||||
|
//prep the program counter for execution
|
||||||
|
vm->programCounter = vm->codeAddr;
|
||||||
|
|
||||||
|
//begin
|
||||||
|
process(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_freeVM(Toy_VM* vm) {
|
||||||
|
//clear the stack
|
||||||
|
Toy_freeStack(&vm->stack);
|
||||||
|
|
||||||
|
//TODO: clear the scope
|
||||||
|
|
||||||
|
//free the bytecode
|
||||||
|
TOY_FREE_ARRAY(unsigned char, vm->program, vm->programSize);
|
||||||
|
Toy_initVM(vm);
|
||||||
|
}
|
||||||
36
source/toy_vm.h
Normal file
36
source/toy_vm.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "toy_common.h"
|
||||||
|
|
||||||
|
#include "toy_stack.h"
|
||||||
|
|
||||||
|
typedef struct Toy_VM {
|
||||||
|
//bytecode - raw instructions that are being executed
|
||||||
|
unsigned char* program;
|
||||||
|
int programSize;
|
||||||
|
|
||||||
|
int paramCount;
|
||||||
|
int jumpsCount;
|
||||||
|
int dataCount;
|
||||||
|
int subsCount;
|
||||||
|
|
||||||
|
int paramAddr;
|
||||||
|
int codeAddr;
|
||||||
|
int jumpsAddr;
|
||||||
|
int dataAddr;
|
||||||
|
int subsAddr;
|
||||||
|
|
||||||
|
int programCounter;
|
||||||
|
|
||||||
|
//scope - block-level key/value pairs
|
||||||
|
|
||||||
|
//stack - immediate-level values only
|
||||||
|
Toy_Stack stack;
|
||||||
|
} Toy_VM;
|
||||||
|
|
||||||
|
TOY_API void Toy_initVM(Toy_VM* vm);
|
||||||
|
TOY_API void Toy_bindVM(Toy_VM* vm, unsigned char* program);
|
||||||
|
TOY_API void Toy_runVM(Toy_VM* vm);
|
||||||
|
TOY_API void Toy_freeVM(Toy_VM* vm);
|
||||||
|
|
||||||
|
//TODO: inject extra data
|
||||||
Reference in New Issue
Block a user