Last active
May 12, 2016 16:06
-
-
Save fowlmouth/1edf02cde1952b4866ea4ab252221329 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# run some assembly code like | |
code = <<-eof | |
# stack | |
push 1 # [1] | |
push 2 # [1, 2] | |
add # [3] | |
print # [] | |
push 2 # [2] | |
cond: | |
dup | |
push 3 | |
equals? | |
if-true-jump ret | |
push 3 | |
goto cond | |
ret: | |
eof | |
class AsmParser | |
attr_accessor :instr | |
def initialize | |
@instr = [] | |
end | |
def parse str | |
labels = {} | |
unresolved_labels = {} | |
get_label = proc do|l| | |
labels[l] || ((unresolved_labels[l] ||= []) << instr.size; nil) | |
end | |
iter = str.each_line | |
loop do | |
l = iter.next | |
case l | |
when /push (\d+)/i | |
instr << :push | |
instr << $1.to_i | |
when /add/i | |
instr << :add | |
when /print/i | |
instr << :print | |
when /equals\?/i | |
instr << :equals? | |
when /pop/i | |
instr << :pop | |
when /dup/i | |
instr << :dup | |
when /if-true-jump (\S+)/i | |
instr << :iftrue | |
instr << get_label[$1] | |
when /if-false-jump (\S+)/i | |
instr << :iffalse | |
instr << get_label[$1] | |
when /(\S+):/i | |
labels[$1] = instr.size | |
when /goto (\S+)/i, /jump (\S+)/i | |
instr << :jump | |
instr << get_label[$1] | |
else | |
puts "unrecognized line: #{l}" | |
end | |
end | |
unresolved_labels.each do |k,v| | |
loc = labels[k] | |
v.each do |idx| | |
instr[idx] = loc | |
end | |
end | |
instr | |
end | |
end | |
class VM | |
attr_accessor :instr | |
def load instrs | |
@instr = instrs | |
self | |
end | |
def run | |
ip = 0 | |
stack = [] | |
while ip < @instr.size | |
op = @instr[ip] | |
ip += 1 | |
case op | |
when :push | |
stack << instr[ip] | |
ip += 1 | |
when :dup | |
stack << stack.last | |
when :add | |
stack << (stack.pop + stack.pop) | |
when :print | |
puts stack.pop | |
when :jump | |
ip = instr[ip] | |
when :equals? | |
stack << (stack.pop == stack.pop) | |
when :pop | |
stack.pop | |
when :iftrue | |
jumpto = instr[ip] | |
if stack.pop | |
ip = jumpto | |
else | |
ip += 1 | |
end | |
when :iffalse | |
jumpto = instr[ip] | |
if stack.pop | |
ip += 1 | |
else | |
ip = jumpto | |
end | |
when :nop | |
else | |
puts "error: not understand this much" | |
return | |
end | |
end | |
end | |
end | |
VM.new | |
.load(AsmParser.new.parse(code)) | |
.run |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment