> But this interpreter does almost nothing. It draws mazes and prints text, and it only works in 80-char terminals.
That is part of the point, though: An interpreter does not need to be complex. Adding "instructions" that does more complicated things does not need to complicate the interpreter much.
Nor does the implementation language make much difference here - fundamentally the interpreter is only the part up to the definition of SubProg. Everything else is just implementation of specific instructions.
Don't get hung up on the use of assembler here - unless you need blazing speed from the interpreter itself, it's trivial to do in pretty much any language.
Conceptually, the interpreter is basically just a table of instructions, a bytecode buffer, and a loop that keeps fetching the next instruction, looks it up in the table, and calls it. The "SubProg" instruction could reasonable be considered part of the generic aspect of the interpreter, but the rest are the domain specific bits, no different
You can abstract out the instructions easily enough. E.g. here's a trivially dumb interpreter written in Ruby where the instructions are separate from the interpreter, that works conceptually not much differently to the linked assembler:
class Interpreter
attr_accessor :pc
def initialize program, instructions
@program = program
@instructions = instructions
@pc = 0
end
def getnext
n = @program[@pc]
@pc+=1
return n
end
def run
while i = getnext
@instructions[i].call(self)
end
end
end
# We could make this an array and insist on numeric instructions,
# but that's an implementation detail - the interpreter doesn't even need to know
# if you pass it a hash or an array.
instructions = {
:myarg => ->(interp) { puts "My argument is #{interp.getnext}" },
:helloworld => ->(interp) { puts "Hello World" }
}
program = [:myarg, 42, :helloworld, :myarg, 3]
Interpreter.new(program, instructions).run
Because the program counter is settable, "SubProg" can just as easily be implemented externally to the interpreter, btw.. Adding variables would really just be a matter of exposing another array or hash in the interpreter so that you could add instructions to read/write them.