From: Daniel Sheppard Date: 2005-10-24T16:02:45+09:00 Subject: Re: Bit of fun II Here's my refactored version to make it a bit more "ruby". Hope this helps you learn some more of the idiosyncracies of ruby. Some things I did are: - getting rid of all those indexes into arrays... learn to love each,collect & friends - made the assembler into an object (ASM) and exposed the assembly functions as methods - rewrote the assemble and execute methods to take advantage of send() - stuff ----------- def compile(pgm) outs = pgm.collect do |line| line.strip.chomp.split.collect do |token| case token when '+' ["pop 1","pop 2","addr 1,2","push 1"] when 'p' ["pop 1","print 1"] when '',nil [] else ["loadr 1,#{token}","push 1"] end end end return outs.join("\n") end class ASM def initialize() @registry = [] @stack = [] end #executes assembled code def execute(mem) asm = ASM.new() until mem.empty? cidx = mem.shift return if cidx == 0 m = method(self.class.asm_methods[cidx-1]) args = [] m.arity.times { args << mem.shift } m.call(*args) end end def self.assemble(program) commands = ASM.asm_methods mem = [] program.each do |line| command, tokens = /(\w*) (\d+(,\d+)*)/.match(line.strip)[1..2] tokens =tokens.split(',').map {|t| t.to_i } #error checking - wasn't there before raise "#{tokens.size} tokens passed to #{command}" unless (instance_method(command).arity) == tokens.size mem << commands.index(command.intern)+1 mem.concat(tokens) end mem.push(0) return mem end #because assembly is pretty pointless, this just executes the commands straight off def execute_program(program) program.each do |line| command, tokens = /(\w*) (\d+(,\d+)*)/.match(line.strip)[1..2] tokens =tokens.split(',').map {|t| t.to_i } send(command, *tokens) end end #because instance_methods doesn't guarantee order... @@methods = [] def self.method_added(m) super @@methods << m unless m =~ /^__/ end def self.asm_methods() @@methods end #methods should be in order of their address locations for assembly to work def loadr(x,y) @registry[x] = y end def addr(x,y) @registry[x] += @registry[y] end def print(x) puts "#{@registry[x]}" end def push(x) @stack.push(@registry[x]) end def pop(x) @registry[x] = @stack.pop end end aapgm = compile("12 10 + 14 + p") code = ASM.assemble(aapgm) ASM.new.execute(code) ASM.new.execute_program(aapgm) ##################################################################################### This email has been scanned by MailMarshal, an email content filter. #####################################################################################