Skip to content

Instantly share code, notes, and snippets.

@corecode
Created November 23, 2012 17:26
Show Gist options
  • Save corecode/4136563 to your computer and use it in GitHub Desktop.
Save corecode/4136563 to your computer and use it in GitHub Desktop.
class Mango
def initialize(source)
source.gsub!(/\/[*].*?[*]\//m, ' ') # remove comments
@toks = source.split(/\s+/)
@toks = @toks[1..-1] if @toks[0].empty?
@pc = 0
@vars = {}
@vec = []
@stack = []
@exit = false
parse_labels
end
def parse_labels
pos = 0
while pos < @toks.size
if /^(\w+):$/ === @toks[pos]
@vars[$1] = pos
@toks.slice! pos
else
pos += 1
end
end
end
def run
while !@exit
instr = @toks[@pc]
@pc += 1
# $stderr.puts "executing `#{instr}'"
val = case instr
when /\d+/ # integer literal
Integer(instr)
when /\w+/ # var, label, or opcode ref
if self.methods.include? "opc_#{instr}".to_sym
self.send('opc_' + instr)
else
{:sym => instr, :val => @vars[instr]}
end
end
# $stderr.puts " => #{val}"
@stack.push val unless val.nil?
# $stderr.puts "stack: #{@stack.reverse.map(&:to_s).join(' ')}"
end
end
def pop(literal=false)
val = @stack.pop
if Hash === val
val = if literal
val[:sym]
else
val[:val]
end
end
# $stderr.print " #{val}"
val
end
def opc_read_num
Integer($stdin.readline)
end
def opc_dup
val = pop
# $stderr.print " => #{val}"
@stack.push val
val
end
def opc_call
oldpc = @pc
@pc = pop
oldpc
end
def opc_exit
@exit = true
nil
end
def opc_add
pop + pop
end
def opc_sub
- pop + pop
end
def opc_mod
v1 = pop
v2 = pop
v2 % v1
end
def opc_xor
pop ^ pop
end
def opc_vstore
val = pop
loc = pop
@vec[loc] = val
nil
end
def opc_vload
@vec[pop]
end
def opc_jump
@pc = pop
nil
end
def opc_store
name = pop true
val = pop
@vars[name] = val
nil
end
def cond_helper
l_false = pop
l_true = pop
cond = yield pop
@pc = if cond
l_true
else
l_false
end
nil
end
def opc_ifz
cond_helper {|c| c == 0}
end
def opc_ifg
cond_helper {|c| c > 0}
end
def opc_print_byte
$stdout.putc pop
nil
end
def opc_print_num
$stdout.print pop
end
end
if __FILE__ == $0
source = File.read(ARGV[0])
m = Mango.new(source)
m.run
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment