Калоян обнови решението на 11.01.2014 20:10 (преди почти 12 години)
+module Asm
+  class Evaluator
+    def initialize
+      @instructions = []
+      @labels = {}
+      @registers = {ax: 0, bx: 0, cx: 0, dx: 0}
+      @cmp_flag = 0
+      @instruction_pointer = 0
+    end
+
+    def run
+      while @instruction_pointer < @instructions.size
+
+        name = @instructions[@instruction_pointer].name
+
+        operand_1 = @instructions[@instruction_pointer].operand_1
+        operand_2 = @instructions[@instruction_pointer].operand_2
+
+        if [:jmp, :je, :jne, :jl, :jle, :jg, :jge].include? name
+          execute_jump name, operand_1
+        else
+          execute_instruction name, operand_1, operand_2
+          @instruction_pointer += 1
+        end
+      end
+    end
+
+    def state
+      @registers.values
+    end
+
+    private
+
+    Instruction = Struct.new(:name, :operand_1, :operand_2)
+
+    INSTRUCTIONS = [:mov, :inc, :dec, :cmp, :jmp, :je, :jne, :jl, :jle, :jg, :jge]
+
+    INSTRUCTIONS.each do |instruction_name|
+      define_method instruction_name do |*arguments|
+        @instructions << Instruction.new(instruction_name, *arguments)
+      end
+    end
+
+    def method_missing(name)
+      name.to_sym
+    end
+
+    def label(label_name)
+      @labels[label_name] = @instructions.size
+    end
+
+    def get_value(value)
+      return value unless value.instance_of? Symbol
+
+      if @registers.has_key? value
+        @registers[value]
+      else
+        @labels[value]
+      end
+    end
+
+    def execute_instruction(type, operand_1, operand_2)
+      if type == :mov
+        @registers[operand_1] = get_value(operand_2)
+      elsif type == :inc
+          @registers[operand_1] += operand_2 ? get_value(operand_2) : 1
+      elsif type == :dec
+          @registers[operand_1] -= operand_2 ? get_value(operand_2) : 1
+      elsif type == :cmp
+          @cmp_flag = get_value(operand_1) <=> get_value(operand_2)
+      end
+    end
+
+    JUMP_CONDITIONS = { je:  :==,
+                        jne: :!=,
+                        jl:  :<,
+                        jle: :<=,
+                        jg:  :>,
+                        jge: :>=
+                      }.freeze
+
+    def execute_jump(type, where)
+      if type != :jmp and not @cmp_flag.public_send JUMP_CONDITIONS[type], 0
+        return @instruction_pointer += 1
+      end
+
+      @instruction_pointer = get_value(where)
+    end
+  end
+
+  def self.asm(&block)
+    evaluator = Evaluator.new
+    evaluator.instance_eval(&block)
+    evaluator.run
+    evaluator.state
+  end
+end
Дотук добре. Има какво да се пипне, обаче:
- На няколко места повтаряш имената на инструкциите: в Evaluator#run, вINSTRUCTIONS, вexecute_instructionи вJUMP_CONDITIONS. Това е в разрез с DRY принципа. Помисли как можеш да избегнеш повторенията.
- 
JUMP_CONDITIONSизглежда по-добре така:JUMP_CONDITIONS = { je: :==, # etc. }
- Може би execute_instructionще изглежда по-добре сcase.
- 
if-а вget_valueможе да се замести сHash#fetch.
- Празен ред над последния ред в Asm.asm, понеже връщаме стойност и конвенцията повелява.
Като цяло най-важното нещо ми си струва премахването на повторенията. Гарантирано ще научиш още неща, ако се опиташ да ги премахнеш.
