Иван обнови решението на 13.01.2014 01:42 (преди почти 11 години)
+class Asm
+ attr_reader :operations, :labels
+ [:ax, :bx, :cx, :dx].each {|x| define_method x do x.to_s end}
+
+ def initialize
+ @line = -1
+ @labels = {}
+ @operations = []
+ end
+
+ def label(name)
+ @labels[name] = @lines + 1
+ end
+
+ def method_missing(name, *args)
+ @line += 1
+ @operations << [name, *args]
+ end
+
+ class Evaluator
+ attr_accessor :ax, :bx, :cx, :dx
+
+ def initialize(operations, labels)
+ @ax, @bx, @cx, @dx = 0, 0, 0, 0
+ @operations = operations
+ @last_cmp = 0
+ @line_number = -1
+ @labels = labels
+ end
+
+ def mov(register, source)
+ send "#{register}=", value_of(source)
+ end
+
+ def inc(register, source = 1)
+ send "#{register}=", value_of(register) + value_of(source)
+ end
+
+ def dec(register, source = 1)
+ inc register, -value_of(source)
+ end
+
+ def cmp(register, source)
+ value_of(register) <=> value_of(source)
+ end
+
+ def execute_operations
+ @operations.each do |command|
+ send(command.shift, *command)
+ end
+ [@ax, @bx, @cx, @dx]
+ end
+
+ private
+
+ def value_of(var)
+ (var.class == Fixnum ? var : instance_variable_get("@#{var}"))
+ end
+
+ def increment_line
+ @line_number += 1
+ end
+ end
+
+ def Asm.asm(&block)
+ assembler = Asm.new
+ assembler.instance_eval &block
+ e = Evaluator.new assembler.operations, assembler.labels
+ e.execute_operations
+ end
+end
Дотук добре. Само трябва да се добавят jump-овете. Освен това:
-
def Asm.asm
->def self.asm
. Не е добра идея да повтаряш името на модула. Това е малък пример за нарушение на DRY принципа. Този принцип обхваща не само повторението на код, но и повторението на имена. Вярно е, че във всички редактори има search&replace, но избягването на повторения винаги е от полза. -
execute_operations
не спазма style guide-а. Последният ред трябва да е отделен с празен ред, ако се връща стойност.