Build the whole machine
Put it all together: read real assembly text — with labels instead of addresses and ; comments — and run it on a machine with four registers, a stack and subroutines (CALL saves where to come back to; RET returns there). This is exactly how emulators for old consoles work.
Two passes: assemble, then run
Labels let programs say JNZ C loop instead of counting addresses. An assembler resolves them in a first pass: strip comments and blank lines, record each label's instruction index, and keep the instructions. The second pass replaces label names in operands with those indexes. Only then does the machine run, with plain numeric jump targets.
// source → instructions // start: (start = 0) // LOAD C 3 0: LOAD C 3 // loop: (loop = 1) // OUT C 1: OUT C // DEC C 2: DEC C // JNZ C loop 3: JNZ C 1 // HALT ; done 4: HALT
Report unknown labels and unknown instructions with the line number. Good error messages are part of a good tool.