From 8696d5bfe7092359b085e4399061c4791e55a31b Mon Sep 17 00:00:00 2001 From: samsonium Date: Sun, 11 Oct 2026 03:12:35 +0300 Subject: [PATCH] feat: implement math in vm --- exl/base_math.fzs | 2 +- include/compiler/utils/fzl_const_pool.h | 8 +- src/compiler/fzl_walker.c | 1 + src/vm/fzl_vm.c | 123 ++++++++++++++++++++++-- 4 files changed, 126 insertions(+), 8 deletions(-) diff --git a/exl/base_math.fzs b/exl/base_math.fzs index e02d17c..b5e368c 100644 --- a/exl/base_math.fzs +++ b/exl/base_math.fzs @@ -1,7 +1,7 @@ -printline(2 + 2) printline(2 + 2 * 2) printline(-1 + 1) printline(2 ^ 2) printline(1 + 1 * 1 / 1) printline(4 % 2) +printline(10 / 2) diff --git a/include/compiler/utils/fzl_const_pool.h b/include/compiler/utils/fzl_const_pool.h index 402a934..0d1b128 100644 --- a/include/compiler/utils/fzl_const_pool.h +++ b/include/compiler/utils/fzl_const_pool.h @@ -8,7 +8,8 @@ // Constant types typedef enum { - FZL_CONSTTYPE_STRING + FZL_CONSTTYPE_STRING, + FZL_CONSTTYPE_NUMBER } fzl_consttype_t; // Constant descriptor @@ -23,6 +24,11 @@ typedef struct const char *chars; size_t length; } string; + + struct + { + uint64_t value; + } num; } as; } fzl_const_t; diff --git a/src/compiler/fzl_walker.c b/src/compiler/fzl_walker.c index f26726b..8b20abf 100644 --- a/src/compiler/fzl_walker.c +++ b/src/compiler/fzl_walker.c @@ -193,6 +193,7 @@ bool walk(fzl_walker_t *walker, fzl_node_t *node) if (!walk(walker, node->unary_op.operand)) return false; + push_op(walker, FZL_OPCODE_PUSHARG); push_op(walker, FZL_OPCODE_NEG); break; } diff --git a/src/vm/fzl_vm.c b/src/vm/fzl_vm.c index defbf98..dd4c14f 100644 --- a/src/vm/fzl_vm.c +++ b/src/vm/fzl_vm.c @@ -1,6 +1,6 @@ -#include "common/fzl_builtins.h" -#include "common/fzl_opcodes.h" -#include "compiler/utils/fzl_const_pool.h" +#include +#include +#include #include #include #include @@ -111,7 +111,7 @@ int fzl_vm_run(fzl_vm_t *vm) vm->ip = 0; while (vm->ip < vm->ops_count) { - uint64_t opcode = vm->ops[vm->ip]; + fzl_opcode_t opcode = vm->ops[vm->ip]; switch (opcode) { @@ -120,7 +120,10 @@ int fzl_vm_run(fzl_vm_t *vm) if (fn_id == FZL_BUILTIN_PRINTLINE) { fzl_const_t arg = vm->arg_stack[--vm->arg_top]; - printf("%s\n", arg.as.string.chars); + if (arg.type == FZL_CONSTTYPE_STRING) + printf("%s\n", arg.as.string.chars); + else if (arg.type == FZL_CONSTTYPE_NUMBER) + printf("%lu\n", arg.as.num.value); } else { @@ -152,8 +155,116 @@ int fzl_vm_run(fzl_vm_t *vm) vm->arg_stack[vm->arg_top++] = vm->stack[--vm->stack_top]; break; + case FZL_OPCODE_ADD: + if (vm->arg_top < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in argstack"); + return -1; + } + fzl_const_t add1 = vm->arg_stack[--vm->arg_top]; + fzl_const_t add2 = vm->arg_stack[--vm->arg_top]; + vm->stack[vm->stack_top++] = + (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, + .as.num.value = add1.as.num.value + add2.as.num.value}; + break; + + case FZL_OPCODE_SUB: + if (vm->arg_top < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in argstack"); + return -1; + } + fzl_const_t sub1 = vm->arg_stack[--vm->arg_top]; + fzl_const_t sub2 = vm->arg_stack[--vm->arg_top]; + vm->stack[vm->stack_top++] = + (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, + .as.num.value = sub1.as.num.value - sub2.as.num.value}; + break; + + case FZL_OPCODE_MUL: + if (vm->arg_top < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in argstack"); + return -1; + } + fzl_const_t mul1 = vm->arg_stack[--vm->arg_top]; + fzl_const_t mul2 = vm->arg_stack[--vm->arg_top]; + vm->stack[vm->stack_top++] = + (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, + .as.num.value = mul1.as.num.value * mul2.as.num.value}; + break; + + case FZL_OPCODE_DIV: + if (vm->arg_top < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in argstack"); + return -1; + } + fzl_const_t div1 = vm->arg_stack[--vm->arg_top]; + fzl_const_t div2 = vm->arg_stack[--vm->arg_top]; + vm->stack[vm->stack_top++] = + (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, + .as.num.value = div2.as.num.value / div1.as.num.value}; + break; + + case FZL_OPCODE_POW: + if (vm->arg_top < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in argstack"); + return -1; + } + fzl_const_t pow1 = vm->arg_stack[--vm->arg_top]; + fzl_const_t pow2 = vm->arg_stack[--vm->arg_top]; + + uint64_t pow_n = pow1.as.num.value; + uint64_t pow_res = pow_n; + uint64_t pow_times = pow2.as.num.value; + for (size_t i = 1; i < pow_times; i++) + pow_res *= pow_n; + + vm->stack[vm->stack_top++] = + (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, .as.num.value = pow_res}; + break; + + case FZL_OPCODE_MOD: + if (vm->arg_top < 2) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected 2 values in argstack"); + return -1; + } + fzl_const_t mod1 = vm->arg_stack[--vm->arg_top]; + fzl_const_t mod2 = vm->arg_stack[--vm->arg_top]; + vm->stack[vm->stack_top++] = + (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, + .as.num.value = mod2.as.num.value % mod1.as.num.value}; + break; + + case FZL_OPCODE_NEG: + if (vm->arg_top < 1) + { + snprintf(last_err, sizeof(last_err), + "runtime error - expected value in argstack"); + return -1; + } + fzl_const_t neg_n = vm->arg_stack[--vm->arg_top]; + vm->stack[vm->stack_top++] = (fzl_const_t){ + .type = FZL_CONSTTYPE_NUMBER, .as.num.value = -neg_n.as.num.value}; + break; + + case FZL_OPCODE_PUSHNUM: + uint64_t push_n = vm->ops[++vm->ip]; + vm->stack[vm->stack_top++] = + (fzl_const_t){.type = FZL_CONSTTYPE_NUMBER, .as.num.value = push_n}; + break; + default: - snprintf(last_err, sizeof(last_err), "runtime error - unknown opcode %lu", + snprintf(last_err, sizeof(last_err), "runtime error - unknown opcode %u", opcode); return -1; }