finish runtime instrs

This commit is contained in:
SimonFJ20 2024-11-11 15:31:54 +01:00
parent f077a16939
commit 161ea947d7
5 changed files with 287 additions and 77 deletions

View File

@ -10,28 +10,27 @@ enum class Op : uint32_t {
Nop = 0,
PushNull = 1,
PushInt = 2,
PushString = 3,
PushArray = 4,
PushStruct = 5,
PushPtr = 6,
Pop = 7,
LoadLocal = 8,
StoreLocal = 9,
Call = 10,
Return = 11,
Jump = 12,
JumpIfNotZero = 13,
Add = 14,
Subtract = 15,
Multiply = 16,
Divide = 17,
Remainder = 18,
Equal = 19,
LessThan = 20,
And = 21,
Or = 22,
Xor = 23,
Not = 24,
PushBool = 3,
PushString = 4,
PushPtr = 5,
Pop = 6,
LoadLocal = 7,
StoreLocal = 8,
Call = 9,
Return = 10,
Jump = 11,
JumpIfFalse = 12,
Add = 13,
Subtract = 14,
Multiply = 15,
Divide = 16,
Remainder = 17,
Equal = 18,
LessThan = 19,
And = 20,
Or = 21,
Xor = 22,
Not = 23,
};
}

View File

@ -18,7 +18,7 @@ class Values;
struct Null { };
struct Int {
uint32_t value;
int32_t value;
};
struct Bool {
bool value;

View File

@ -1,14 +1,18 @@
#include "vm.hpp"
#include "arch.hpp"
#include <cstdint>
#include <cstdlib>
#include <format>
#include <iostream>
#include <utility>
#include <vector>
using namespace sliger;
void VM::run()
{
while (!done()) {
auto op = eat_as_op();
auto op = eat_op();
switch (op) {
case Op::Nop:
// nothing
@ -16,35 +20,184 @@ void VM::run()
case Op::PushNull:
this->stack.push_back(Null {});
break;
case Op::PushInt:
if (done()) {
std::cerr
<< std::format("program malformed: missing int value");
}
this->stack.push_back(Null {});
case Op::PushInt: {
assert_program_has(1);
auto value = eat_int32();
this->stack.push_back(Int { value });
break;
case Op::PushString:
case Op::PushArray:
case Op::PushStruct:
case Op::PushPtr:
case Op::Pop:
case Op::LoadLocal:
case Op::StoreLocal:
case Op::Call:
case Op::Return:
case Op::Jump:
case Op::JumpIfNotZero:
case Op::Add:
case Op::Subtract:
case Op::Multiply:
case Op::Divide:
case Op::Remainder:
case Op::Equal:
case Op::LessThan:
case Op::And:
case Op::Or:
case Op::Xor:
}
case Op::PushBool: {
assert_program_has(1);
auto value = eat_int32();
this->stack.push_back(Bool { .value = value != 0 });
break;
}
case Op::PushString: {
assert_program_has(1);
auto string_length = eat_uint32();
assert_program_has(string_length);
auto value = std::string();
for (uint32_t i = 0; i < string_length; ++i) {
auto ch = eat_uint32();
value.push_back(static_cast<char>(ch));
}
stack_push(String { .value = std::move(value) });
break;
}
case Op::PushPtr: {
assert_program_has(1);
auto value = eat_uint32();
this->stack.push_back(Ptr { value });
break;
}
case Op::Pop: {
assert_stack_has(1);
this->stack.pop_back();
break;
}
case Op::LoadLocal: {
auto loc = eat_uint32();
assert_fn_stack_has(loc);
auto value = fn_stack_at(loc);
stack_push(value);
break;
}
case Op::StoreLocal: {
auto loc = eat_uint32();
assert_fn_stack_has(loc + 1);
auto value = stack_pop();
fn_stack_at(loc) = value;
break;
}
case Op::Call: {
assert_program_has(1);
auto arg_count = eat_uint32();
assert_stack_has(arg_count + 1);
auto fn_ptr = stack_pop();
auto arguments = std::vector<Value>();
for (uint32_t i = 0; i < arg_count; ++i) {
auto argument = stack_pop();
arguments.push_back(argument);
}
stack_push(Ptr { .value = this->pc });
stack_push(Ptr { .value = this->bp });
for (auto i = arguments.size(); i >= 0; --i) {
auto argument = std::move(arguments.at(i));
arguments.pop_back();
stack_push(argument);
}
this->pc = fn_ptr.as_ptr().value;
break;
}
case Op::Return: {
assert_stack_has(3);
auto ret_val = stack_pop();
auto bp_val = stack_pop();
auto pc_val = stack_pop();
this->bp = bp_val.as_ptr().value;
stack_push(ret_val);
this->pc = pc_val.as_ptr().value;
break;
}
case Op::Jump: {
assert_stack_has(1);
auto addr = stack_pop();
this->pc = addr.as_ptr().value;
break;
}
case Op::JumpIfFalse: {
assert_stack_has(2);
auto cond = stack_pop();
auto addr = stack_pop();
if (cond.as_bool().value) {
this->pc = addr.as_ptr().value;
}
break;
}
case Op::Add: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left + right;
stack_push(Int { .value = value });
break;
}
case Op::Subtract: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left - right;
stack_push(Int { .value = value });
break;
}
case Op::Multiply: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left * right;
stack_push(Int { .value = value });
break;
}
case Op::Divide: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left / right;
stack_push(Int { .value = value });
break;
}
case Op::Remainder: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left % right;
stack_push(Int { .value = value });
break;
}
case Op::Equal: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left == right;
stack_push(Bool { .value = value });
break;
}
case Op::LessThan: {
assert_stack_has(2);
auto right = stack_pop().as_int().value;
auto left = stack_pop().as_int().value;
auto value = left < right;
stack_push(Bool { .value = value });
break;
}
case Op::And: {
assert_stack_has(2);
auto right = stack_pop().as_bool().value;
auto left = stack_pop().as_bool().value;
auto value = left && right;
stack_push(Bool { .value = value });
break;
}
case Op::Or: {
assert_stack_has(2);
auto right = stack_pop().as_bool().value;
auto left = stack_pop().as_bool().value;
auto value = left || right;
stack_push(Bool { .value = value });
break;
}
case Op::Xor: {
assert_stack_has(2);
auto right = stack_pop().as_bool().value;
auto left = stack_pop().as_bool().value;
auto value = (left || !right) || (!left && right);
stack_push(Bool { .value = value });
break;
}
case Op::Not:
assert_stack_has(1);
auto value = !stack_pop().as_bool().value;
stack_push(Bool { .value = value });
break;
}
}

View File

@ -4,13 +4,15 @@
#include "value.hpp"
#include <cstddef>
#include <cstdint>
#include <format>
#include <iostream>
#include <vector>
namespace sliger {
class VM {
public:
VM(const std::vector<Op>& program)
VM(const std::vector<uint32_t>& program)
: program(program.data())
, program_size(program.size())
{
@ -19,23 +21,80 @@ public:
inline void step() { this->pc += 1; }
inline auto eat_as_op() -> Op
inline auto eat_op() -> Op
{
auto value = curr_as_op();
step();
return value;
}
inline auto curr_as_op() const -> Op
{
return static_cast<Op>(this->program[this->pc]);
}
inline auto eat_int32() -> int32_t
{
auto value = curr_as_int32();
step();
return value;
}
inline auto curr_as_int32() const -> int32_t
{
return static_cast<int32_t>(this->program[this->pc]);
}
inline auto eat_uint32() -> uint32_t
{
auto value = curr_as_uint32();
step();
return value;
}
inline auto curr_as_uint32() const -> uint32_t
{
return this->program[this->pc];
}
inline auto done() const -> bool { return this->pc >= this->program_size; }
inline auto fn_stack_at(size_t idx) -> Value&
{
return this->stack.at(this->bp + idx);
}
inline void assert_fn_stack_has(size_t count)
{
if (this->stack.size() - this->bp < count) {
std::cerr << std::format("stack underflow");
std::exit(1);
}
}
inline void assert_stack_has(size_t count)
{
if (this->stack.size() < count) {
std::cerr << std::format("stack underflow");
std::exit(1);
}
}
inline void stack_push(Value&& value) { this->stack.push_back(value); }
inline void stack_push(Value& value) { this->stack.push_back(value); }
inline auto stack_pop() -> Value
{
auto value = this->stack.at(this->stack.size() - 1);
this->stack.pop_back();
return value;
}
inline auto assert_program_has(size_t count)
{
if (this->pc + count >= program_size) {
std::cerr << std::format("stack underflow");
std::exit(1);
}
}
private:
uint32_t pc = 0;
const Op* program;
uint32_t bp = 0;
const uint32_t* program;
size_t program_size;
std::vector<Value> stack;
std::vector<Value> pool_heap;

View File

@ -8,26 +8,25 @@ export const Ops = {
Nop: 0,
PushNull: 1,
PushInt: 2,
PushString: 3,
PushArray: 4,
PushStruct: 5,
PushPtr: 6,
Pop: 7,
LoadLocal: 8,
StoreLocal: 9,
Call: 10,
Return: 11,
Jump: 12,
JumpIfNotZero: 13,
Add: 14,
Subtract: 15,
Multiply: 16,
Divide: 17,
Remainder: 18,
Equal: 19,
LessThan: 20,
And: 21,
Or: 22,
Xor: 23,
Not: 24,
PushBool: 3,
PushString: 4,
PushPtr: 5,
Pop: 6,
LoadLocal: 7,
StoreLocal: 8,
Call: 9,
Return: 10,
Jump: 11,
JumpIfTrue: 12,
Add: 13,
Subtract: 14,
Multiply: 15,
Divide: 16,
Remainder: 17,
Equal: 18,
LessThan: 19,
And: 20,
Or: 21,
Xor: 22,
Not: 23,
} as const;