Наталия обнови решението на 15.01.2014 12:59 (преди почти 11 години)
+module Asm
+
+ module CommonInstructions
+ def move(destination_register, source)
+ @registers[destination_register] = get_value(source)
+ end
+
+ def increment(destination_register, value = 1)
+ @registers[destination_register] += get_value(value)
+ end
+
+ def decrement(destination_register, value = 1)
+ @registers[destination_register] -= get_value(value)
+ end
+
+ def compare(destination_register, value)
+ @flag = @registers[destination_register] - get_value(value)
+ end
+
+ def add_label (label_name)
+ label_name
+ end
+
+ private
+
+ def get_value(value)
+ value = @registers.key?(value) ? @registers[value] : value
+ end
+ end
+
+ module JumpInstructions
+ def jump(filter, where)
+ filter.call(@flag) ? where : -1
+ end
+ end
+
+ module CommonInstructionsInterpreter
+ include CommonInstructions
+
+ def mov(destination_register, source)
+ @instructions << {name: :move, parameters: [destination_register, source]}
+ end
+
+ def inc(destination_register, value = 1)
+ @instructions << {name: :increment, parameters: [destination_register, value]}
+ end
+
+ def dec(destination_register, value = 1)
+ @instructions << {name: :decrement, parameters: [destination_register, value]}
+ end
+
+ def cmp(destination_register, value)
+ @instructions << {name: :compare, parameters: [destination_register, value]}
+ end
+
+ def label(label_name)
+ @labels[label_name.to_sym] = @instructions.count
+ end
+ end
+
+ module JumpInstructionsInterpreter
+ include JumpInstructions
+
+ @@jumps = {
+ jump: proc { |x| x == x },
+ jump_equal: proc { |x| x == 0 },
+ jump_not_equal: proc { |x| x != 0 },
+ jump_less: proc { |x| x < 0 },
+ jump_less_equal: proc { |x| x <= 0 },
+ jump_greater: proc { |x| x > 0 },
+ jump_greater_equal: proc { |x| x >= 0 }
+ }
+
+ def jmp(where)
+ @instructions << {name: :jump, parameters: [@@jumps[:jump], where]}
+ end
+
+ def je(where)
+ @instructions << {name: :jump, parameters: [@@jumps[:jump_equal], where]}
+ end
+
+ def jne(where)
+ @instructions << {name: :jump, parameters: [@@jumps[:jump_not_equal], where]}
+ end
+
+ def jl(where)
+ @instructions << {name: :jump, parameters: [@@jumps[:jump_less], where]}
+ end
+
+ def jle(where)
+ @instructions << {name: :jump, parameters: [@@jumps[:jump_less_equal], where]}
+ end
+
+ def jg(where)
+ @instructions << {name: :jump, parameters: [@@jumps[:jump_greater], where]}
+ end
+
+ def jge(where)
+ @instructions << {name: :jump, parameters: [@@jumps[:jump_greater_equal], where]}
+ end
+ end
+
+ class AsmDSLInterpreter
+ include CommonInstructionsInterpreter
+ include JumpInstructionsInterpreter
+
+ def initialize
+ @registers = {ax: 0, bx: 0, cx: 0, dx: 0}
+ @instructions = []
+ @labels = {}
+ @flag = 0
+ end
+
+ def interpret
+ next_index = 0
+ while next_index < @instructions.size do
+ next_index = execute_instruction(@instructions[next_index], next_index)
+ end
+ @registers.values
+ end
+
+ def execute_instruction(current_instruction, current_index)
+ next_index = current_index + 1
+ result = public_send current_instruction[:name], *current_instruction[:parameters]
+ if current_instruction[:name] == :jump and result != -1
+ next_index = @labels.key?(result) ? @labels[result] : result
+ end
+
+ next_index
+ end
+
+ def method_missing (method_name, *args, &block)
+ method_name
+ end
+ end
+
+ def self.asm(&block)
+ interpreter = AsmDSLInterpreter.new
+ interpreter.instance_eval &block
+ interpreter.interpret
+ end
+end