Николай обнови решението на 15.01.2014 01:51 (преди почти 11 години)
+module Asm
+ class Register
+
+ attr_reader :value
+
+ def initialize
+ @value = 0
+ end
+
+ def add(other)
+ @value += (other.respond_to? :value) ? other.value : other
+ end
+
+ def subtract(other)
+ @value -= (other.respond_to? :value) ? other.value : other
+ end
+
+ def set(other)
+ @value = (other.respond_to? :value) ? other.value : other
+ end
+
+ def compare(other)
+ @value <=> ((other.respond_to? :value) ? other.value : other)
+ end
+ end
+
+ class SimulatorX86
+
+ attr_reader :ax, :bx, :cx, :dx, :cmp_result
+
+ def mov(destination_register, source)
+ destination_register.set(source)
+ end
+
+ def inc(destination_register, value = 1)
+ destination_register.add(value)
+ end
+
+ def dec(destination_register, value = 1)
+ destination_register.subtract(value)
+ end
+
+ def cmp(register, value)
+ @cmp_result = register.compare value
+ end
+
+ def initialize
+ @ax, @bx, @cx, @dx = Array.new(4) { |i| Register.new }
+ end
+
+ def registers_values
+ [@ax.value, @bx.value, @cx.value, @dx.value]
+ end
+ end
+
+ class InstructionsProxy
+
+ @@allowed = [:inc, :dec, :mov, :label, :jmp, :cmp, :je, :jne, :jl, :jle, :jg, :jge]
+
+ @@jumps = {
+ 'je' => :==,
+ 'jne' => :!=,
+ 'jl' => :<,
+ 'jle' => :<=,
+ 'jg' => :>,
+ 'jge' => :>=
+ }
+
+ attr_reader :instructions, :labels
+
+ def initialize
+ @simulator = SimulatorX86.new
+ @instructions = []
+ @labels = {}
+ end
+
+ def method_missing(method, *args, &block)
+ if @@allowed.include? method
+ if method == :label
+ @labels[*args] = @instructions.size
+ else
+ @instructions << method.to_s + ' ' + args.join(', ')
+ end
+ else
+ method.to_s
+ end
+ end
+
+ def run_instuctions
+ counter = 0
+ while counter < @instructions.size
+ if is_jump_instruction @instructions[counter]
+ instrcution, label = @instructions[counter].split
+ counter = get_next_instruction(instrcution, label, counter)
+ else
+ @simulator.instance_eval(@instructions[counter])
+ counter += 1
+ end
+ end
+ end
+
+ def registers_values
+ @simulator.registers_values
+ end
+
+ private
+ def get_next_instruction(instrcution, label, counter)
+ next_instruction = (@labels.has_key? label) ? @labels[label] : label.to_i
+
+ if instrcution == 'jmp' or @simulator.cmp_result.send @@jumps[instrcution], 0
+ next_instruction
+ else
+ counter + 1
+ end
+ end
+
+ def is_jump_instruction(instrcution)
+ instrcution.start_with? 'j'
+ end
+ end
+
+ def self.asm(&block)
+ evaluator = InstructionsProxy.new
+ evaluator.instance_eval &block
+ evaluator.run_instuctions
+ evaluator.registers_values
+ end
+end