#include "parser.h" #include typedef enum { OP_PUSH_INT, OP_PUSH_FLOAT, OP_PUSH_STRING, OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_PRINT, OP_HALT } OPcode; typedef struct { OPcode op; double num; char *strlit; } instruct; typedef enum { VAL_INT, VAL_FLOAT, VAL_STRING, } ValueType; typedef struct { ValueType type; union { long i; double f; char *s; }; } Value; typedef struct { instruct *program; size_t inst_p; size_t program_size; Value stack[256]; size_t st_p; bool running; } VM; instruct *rpn_to_bytecode(Token *rpn, size_t *out){ size_t cap = 64; size_t size = 0; instruct *prog = malloc(sizeof(instruct) * cap); for (size_t i=0; isize; ++i){ symbols t = rpn->type[i]; const char *text = rpn->text[i]; instruct ins = {0}; switch (t){ case TOKEN_INTEGER: ins.op = OP_PUSH_INT; ins.num = atof(text); break; case TOKEN_FLOAT: ins.op = OP_PUSH_FLOAT; ins.num = atof(text); break; case TOKEN_STRING: ins.op = OP_PUSH_STRING; ins.strlit = strdup(text); break; case TOKEN_PLUS: ins.op = OP_ADD; break; case TOKEN_MINUS: ins.op = OP_SUB; break; case TOKEN_MUL: ins.op = OP_MUL; break; case TOKEN_DIV: ins.op = OP_DIV; break; case TOKEN_IDENTIFIER: if (strcmp(text, "print") == 0) { ins.op = OP_PRINT; } else { printf("[WARNING] Uknown Identifier '%s'\n", text); } break; //TODO: unhardcode this case TOKEN_EOF: ins.op = OP_HALT; break; default: continue; } if (size >= cap){ cap*=2; prog = realloc(prog, sizeof(instruct)*cap); } prog[size++] = ins; } *out = size; return prog; } void vm_run(VM *vm) { vm->running = true; vm->inst_p = 0; vm->st_p = 0; while (vm->running && vm->inst_p < vm->program_size) { instruct ins = vm->program[vm->inst_p++]; switch (ins.op) { case OP_PUSH_INT: { Value v = { .type = VAL_INT, .i = ins.num }; vm->stack[vm->st_p++] = v; } break; case OP_PUSH_FLOAT: { Value v = { .type = VAL_FLOAT, .f = ins.num }; vm->stack[vm->st_p++] = v; } break; case OP_PUSH_STRING: { Value v = { .type = VAL_STRING, .s = strdup(ins.strlit) }; vm->stack[vm->st_p++] = v; } break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: { if (vm->st_p < 2) { fprintf(stderr, "not enough values on stack.\n"); vm->running = false; break; } Value b = vm->stack[--vm->st_p]; Value a = vm->stack[--vm->st_p]; double av = (a.type == VAL_INT) ? a.i : a.f; double bv = (b.type == VAL_INT) ? b.i : b.f; double result = 0; switch (ins.op) { case OP_ADD: result = av + bv; break; case OP_SUB: result = av - bv; break; case OP_MUL: result = av * bv; break; case OP_DIV: if (bv == 0) { fprintf(stderr, "division by zero.\n"); vm->running = false; } else result = av / bv; break; default: break; } Value v = { .type = VAL_FLOAT, .f = result }; vm->stack[vm->st_p++] = v; } break; case OP_PRINT: { if (vm->st_p == 0) { fprintf(stderr, "cant print an empty stack\n"); vm->running = false; break; } Value v = vm->stack[--vm->st_p]; switch (v.type) { case VAL_INT: printf("%ld\n", v.i); break; case VAL_FLOAT: printf("%g\n", v.f); break; case VAL_STRING: printf("%s\n", v.s); free(v.s); break; } } break; case OP_HALT: vm->running = false; break; default: fprintf(stderr, "unknown opcode %d\n", ins.op); vm->running = false; break; } } } char *op_to_str(OPcode o){ switch (o){ case OP_ADD: return "OP_ADD"; break; case OP_SUB: return "OP_SUB"; break; case OP_MUL: return "OP_MUL"; break; case OP_DIV: return "OP_DIV"; break; case OP_PRINT: return "OP_PRINT"; break; case OP_HALT: return "OP_HALT"; break; default: break; } return NULL; } void emit_bytecode(VM *v){ size_t i =0; while (i < v->program_size){ if (v->program[i].op == OP_PUSH_INT) printf("OP_PUSH_INT(%f)\n", v->program[i].num); else if (v->program[i].op == OP_PUSH_FLOAT) printf("OP_PUSH_FLOAT(%f)\n", v->program[i].num); else if (v->program[i].op == OP_PUSH_STRING) printf("OP_PUSH_STRING(\"%s\")\n", v->program[i].strlit); else printf("%s\n", op_to_str(v->program[i].op)); i++; } printf("\n"); }