58 — Compiler tier: a tiny bytecode runner
Guide 29 translated source text into Python and ran it; 49 split lines into tokens and dispatched them. The next step is bytecode: instructions already compiled into small data steps. A runner — a tiny virtual machine — walks them with a program counter, the way Python runs its code.
Steps
A compiled program is data: a list of instructions, each a list whose first element is the operation and the rest its arguments:
run it →program = [ ["set", "x", "0"], ["add", "x", "2"], ["add", "x", "3"], ["show", "x"], ]set x 0stores 0 into a variable namedx;add x 2adds 2. No line runs yet — this is a description of steps.The runner steps through with a
pc(program counter) and avarsdict, the machine's memory. Each loop turn fetches the instruction atpc, does it, and movespcforward.jnzjumps to anotherpcwhile a variable is not zero — that is how a bytecode loop is built. The full runner, saved asbytecode.nme:
run it →# bytecode.nme — a tiny bytecode runner, a mini virtual machine. # Run: nme r bytecode # Each instruction is a list; run() steps through with a program counter. def run(program): vars = {} pc = 0 step = 0 while pc < len(program): instr = program[pc] op = instr[0] step = step + 1 if op == "set": vars[instr[1]] = int(instr[2]) elif op == "add": vars[instr[1]] = vars[instr[1]] + int(instr[2]) elif op == "sub": vars[instr[1]] = vars[instr[1]] - int(instr[2]) elif op == "show": show f"step {step} pc {pc}: {instr[1]} = {vars[instr[1]]}" elif op == "jnz": if vars[instr[1]] != 0: pc = int(instr[2]) continue pc = pc + 1 show f"program finished in {step} steps" countdown = [ ["set", "x", "0"], ["add", "x", "2"], ["add", "x", "3"], ["show", "x"], ] show "first program:" run(countdown) show "loop with a jump:" loop = [ ["set", "n", "3"], ["show", "n"], ["sub", "n", "1"], ["jnz", "n", "1"], ] run(loop) show "done"stepcounts every fetched instruction;showreports the currentpc. In the loop,pcreturns to 1 whilenis not zero, then falls off the end whennreaches 0.Run it:
nme r bytecodefirst program: step 4 pc 3: x = 5 program finished in 4 steps loop with a jump: step 2 pc 1: n = 3 step 5 pc 1: n = 2 step 8 pc 1: n = 1 program finished in 10 steps doneThe first program ran four steps: set, add, add, show. The loop ran ten:
jnzsent the machine back topc1 three times, then let it fall through.
Try it yourself
Add a cmp (compare) instruction that stores 1 or 0, then a jz that jumps
when a variable is zero.
What you learned
- Bytecode is source already compiled into a list of small data steps.
- A program counter (
pc) says which instruction the machine runs next. vars, a dict, is the machine's memory; each op reads and writes it.jnzjumps by changingpc, which is how loops work inside a virtual machine.