data-structures · advanced · ~50 min
Dispatch loop; fixed-size stack; opcode encoding.
Execute a sequence of opcodes against a stack. Opcodes:
PUSH x — push integer x.ADD — pop b, pop a, push a+b.MUL — pop b, pop a, push a*b.NEG — pop a, push -a.HALT — stop.Represent the program as a flat int array where each opcode is a number; PUSH is followed by its argument. Use these constants:
enum { OP_PUSH=1, OP_ADD=2, OP_MUL=3, OP_NEG=4, OP_HALT=5 };
Implement int vm_run(const int *code, size_t n, int *out) returning 1 on success (with the final top-of-stack in *out), or 0 on stack underflow / overflow / bad opcode.
A stack VM is the simplest possible interpreter and the model behind the JVM, CPython, and WebAssembly. Building one teaches dispatch loops and the elegance of postfix evaluation.
code of n ints. Stack capacity 256.
*out set on success. Return 1/0.
No malloc. Stack fixed at 256 ints.
#include <stddef.h>
enum { OP_PUSH=1, OP_ADD=2, OP_MUL=3, OP_NEG=4, OP_HALT=5 };
int vm_run(const int *code, size_t n, int *out) { /* TODO */ return 0; }
Popping in the wrong order (ADD/MUL are commutative; NEG is not); reading past n on a malformed program; forgetting the IP++ for PUSH's argument.
Empty program — no HALT means error. PUSH at end with no argument — error. Stack underflow on bare ADD.
O(n) per instruction stream.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.