timesynk/test/vm.c

207 lines
6.7 KiB
C

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "vm.h"
// TODO: properly handle RETURN.
// TODO: calling other functions in function
/*
================================
vm_doOp(struct vm_Operation *op, int *orign_pos)
Takes a vm_Operation and does the appropriate ops! Also takes an integer pointer(which indicates operation id) and: increments it for normal ops, double increments it if a conditional op is failed(to a JUMP), or a negative value for RETURN. Probably will change this.
================================
*/
int vm_doOp(struct vm_Operation *op, int *orig_pos) {
int op_pos = *orig_pos;
//printf("0x%X: %d\n", op->pos_a, op->op);
int val;
switch(op->op) {
case ASS_INT:
memcpy(op->stack_a+op->pos_a, op->stack_b+op->pos_b, sizeof(int));
op_pos++; // move to next line
break;
case MIN_INT:
val = *(int*)&(op->stack_a[op->pos_a]) - *(int*)&(op->stack_b[op->pos_b]);
memcpy(op->stack_a+op->pos_a, &val, sizeof(int));
op_pos++;
break;
case ADD_INT:
val = *(int*)&(op->stack_a[op->pos_a]) + *(int*)&(op->stack_b[op->pos_b]);
memcpy(op->stack_a+op->pos_a, &val, sizeof(int));
op_pos++;
break;
case MUL_INT:
val = *(int*)&(op->stack_a[op->pos_a]) * *(int*)&(op->stack_b[op->pos_b]);
memcpy(op->stack_a+op->pos_a, &val, sizeof(int));
op_pos++;
break;
case DIV_INT:
val = *(int*)&(op->stack_a[op->pos_a]) / *(int*)&(op->stack_b[op->pos_b]);
memcpy(op->stack_a+op->pos_a, &val, sizeof(int));
op_pos++;
break;
case EQ_INT:
if (*(int*)&(op->stack_a[op->pos_a]) == *(int*)&(op->stack_b[op->pos_b])) {
op_pos += 2; // if true, we jump past the next op(which WILL be a jump)
} else {
op_pos++; // if false, move to next position which is a JUMP.
}
break;
case LT_INT:
if (*(int*)&(op->stack_a[op->pos_a]) < *(int*)&(op->stack_b[op->pos_b])) {
op_pos += 2; // if true, we jump past the next op(which WILL be a jump)
} else {
op_pos++; // if false, move to next position which is a JUMP.
}
break;
case LE_INT:
if (*(int*)&(op->stack_a[op->pos_a]) <= *(int*)&(op->stack_b[op->pos_b])) {
op_pos += 2; // if true, we jump past the next op(which WILL be a jump)
} else {
op_pos++; // if false, move to next position which is a JUMP.
}
break;
case GT_INT:
if (*(int*)&(op->stack_a[op->pos_a]) > *(int*)&(op->stack_b[op->pos_b])) {
op_pos += 2; // if true, we jump past the next op(which WILL be a jump)
} else {
op_pos++; // if false, move to next position which is a JUMP.
}
break;
case GE_INT:
if (*(int*)&(op->stack_a[op->pos_a]) >= *(int*)&(op->stack_b[op->pos_b])) {
op_pos += 2; // if true, we jump past the next op(which WILL be a jump)
} else {
op_pos++; // if false, move to next position which is a JUMP.
}
break;
case JUMP:
op_pos = (op->pos_a);
break;
case RETURN:
printf("returning %d\n", *(int*)&op->stack_a[op->pos_a]);
//op_pos = test_function.op_size;
op_pos = -1;
*orig_pos = op_pos;
return (*(int*)&op->stack_a[op->pos_a]);
break;
default:
// ERR
break;
}
*orig_pos = op_pos;
return 0;
}
/*
================================
vm_copyMem(struct vm_Stack *stack, int pos, void *from, int bytes)
Copies /bytes/ from void pointer /from/ into memory offset /pos/ in /stack/. Used to avoid writing beyond the memory of the stack.
================================
*/
void vm_copyMem(struct vm_Stack *stack, int pos, void *from, int bytes) {
if (pos+bytes > stack->bytes) {
printf("ERR: would overflow, not vm_copying\n");
} else {
memcpy(stack->memory+pos, from, bytes);
}
}
int main(int argc, char *argv[]) {
struct vm_Function test_function;
test_function.p_stack.memory = malloc(4); // 1 int parameter
test_function.p_stack.bytes = 4;
// allocate main stack (space for all variables - "var = 32" (var))
test_function.stack.memory = malloc(32); // 32 byte stack size
test_function.stack.bytes = 32;
// set up internal stack for right-hand ops such as "var = 32" (32)
test_function.v_stack.memory = malloc(32);
test_function.v_stack.bytes = 32;
// we got 17 ops (not really)
test_function.op_size = 17;
test_function.ops = malloc(sizeof(struct vm_Operation)*17);
// set our single parameters manually - this would be done in function call
int num = 1;
vm_copyMem(&test_function.p_stack, 0x00, &num, sizeof(int));
// manually set v_stack by copying num into 0x00
num = 2373;
vm_copyMem(&test_function.v_stack, 0x00, &num, sizeof(int));
// copy v_stack[0x00] to stack[0x00] :)
struct vm_Operation *set_op = &test_function.ops[0];
set_op->op = ASS_INT;
set_op->stack_a = test_function.stack.memory;
set_op->pos_a = 0x00;
set_op->stack_b = test_function.v_stack.memory;
set_op->pos_b = 0x00;
num = 1;
vm_copyMem(&test_function.v_stack, 0x04, &num, sizeof(int));
set_op = &test_function.ops[1];
set_op->op = ASS_INT;
set_op->stack_a = test_function.stack.memory;
set_op->pos_a = 0x04;
set_op->stack_b = test_function.v_stack.memory;
set_op->pos_b = 0x04;
// begin while (0x04 < 0x00) {
set_op = &test_function.ops[2];
set_op->op = LT_INT;
set_op->stack_a = test_function.stack.memory;
set_op->pos_a = 0x04;
set_op->stack_b = test_function.stack.memory;
set_op->pos_b = 0x00;
// if not, jump to OP 6
set_op = &test_function.ops[3];
set_op->op = JUMP;
set_op->stack_a = test_function.stack.memory;
set_op->pos_a = 6;
// otherwise, add parameter 2
set_op = &test_function.ops[4];
set_op->op = ADD_INT;
set_op->stack_a = test_function.stack.memory;
set_op->pos_a = 0x04;
set_op->stack_b = test_function.p_stack.memory;
set_op->pos_b = 0x00;
// loop back to OP 2 (less than comparison)
set_op = &test_function.ops[5];
set_op->op = JUMP;
set_op->stack_a = test_function.stack.memory;
set_op->pos_a = 2;
// done with loop! return 0x04 :)
set_op = &test_function.ops[6];
set_op->op = RETURN;
set_op->stack_a = test_function.stack.memory;
set_op->pos_a = 0x04;
// Okay, this is where we actually run the above program
int op_pos = 0;
while(op_pos < test_function.op_size) {
vm_doOp(&test_function.ops[op_pos], &op_pos);
if (op_pos == -1) // return
op_pos = test_function.op_size;
}
// dump stack memory :)
int offset = 0;
while(offset < test_function.stack.bytes) {
printf("0x%X\n", offset);
printf("\tint: %d, float: %f, char: %c\n", *(int*)(test_function.stack.memory+offset), *(float*)(test_function.stack.memory+offset), test_function.stack.memory[offset]);
offset++;
}
return 0;
}