Решение на Четвърта задача от Калоян Калудов

Обратно към всички решения

Към профила на Калоян Калудов

Резултати

  • 6 точки от тестове
  • 0 бонус точки
  • 6 точки общо
  • 8 успешни тест(а)
  • 0 неуспешни тест(а)

Код

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 name.to_s.start_with? 'j'
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 = {
je: :==,
jne: :!=,
jl: :<,
jle: :<=,
jg: :>,
jge: :>=,
jmp: nil,
mov: nil,
inc: nil,
dec: nil,
cmp: nil,
}.freeze
INSTRUCTIONS.keys.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
@registers.fetch value, @labels[value]
end
def execute_instruction(type, operand_1, operand_2)
case type
when :mov
@registers[operand_1] = get_value(operand_2)
when :inc
@registers[operand_1] += operand_2 ? get_value(operand_2) : 1
when :dec
@registers[operand_1] -= operand_2 ? get_value(operand_2) : 1
else#:cmp
@cmp_flag = get_value(operand_1) <=> get_value(operand_2)
end
end
def execute_jump(type, where)
if type != :jmp and not @cmp_flag.public_send INSTRUCTIONS[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

Лог от изпълнението

........

Finished in 0.00889 seconds
8 examples, 0 failures

История (2 версии и 1 коментар)

Калоян обнови решението на 11.01.2014 20:10 (преди почти 11 години)

+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, понеже връщаме стойност и конвенцията повелява.

Като цяло най-важното нещо ми си струва премахването на повторенията. Гарантирано ще научиш още неща, ако се опиташ да ги премахнеш.

Калоян обнови решението на 12.01.2014 14:01 (преди почти 11 години)

module Asm
class Evaluator
def initialize
@instructions = []
- @labels = {}
- @registers = {ax: 0, bx: 0, cx: 0, dx: 0}
- @cmp_flag = 0
+ @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
+ if name.to_s.start_with? 'j'
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 = {
+ je: :==,
+ jne: :!=,
+ jl: :<,
+ jle: :<=,
+ jg: :>,
+ jge: :>=,
+ jmp: nil,
+ mov: nil,
+ inc: nil,
+ dec: nil,
+ cmp: nil,
+ }.freeze
- INSTRUCTIONS.each do |instruction_name|
+ INSTRUCTIONS.keys.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
+ @registers.fetch value, @labels[value]
end
def execute_instruction(type, operand_1, operand_2)
- if type == :mov
- @registers[operand_1] = get_value(operand_2)
- elsif type == :inc
+ case type
+ when :mov
+ @registers[operand_1] = get_value(operand_2)
+ when :inc
@registers[operand_1] += operand_2 ? get_value(operand_2) : 1
- elsif type == :dec
+ when :dec
@registers[operand_1] -= operand_2 ? get_value(operand_2) : 1
- elsif type == :cmp
+ else#: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
+ if type != :jmp and not @cmp_flag.public_send INSTRUCTIONS[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