class Rips::Assembler
Public Class Methods
@debug: switch to show trace in console @input: array with assembly instructions @output: array with coded instructions @cmd: line split on tokens (name + arguments) @instruction: instruction instance @instructions: array with line for each instruction @labels: name and number line of label @line: number of file's line
# File lib/rips/assembler.rb, line 22 def initialize (debug) @debug = debug @input = [] @output = [] @cmd = {} @instruction @instructions = [] @labels = {} @line = 1 end
Public Instance Methods
Stores each new line of file
# File lib/rips/assembler.rb, line 141 def << (value) @input << value.strip end
Analyze and translate each instruction
# File lib/rips/assembler.rb, line 146 def run (path = "progfile.dat") find_instructions find_labels @input.each do |line| if (line.instruction?) || (line.comment?) parse_input(line) @instruction = nil # If it's a comment -> show but not work with it if line.instruction? exists_instruction? parse_label argument_size? argument_syntax? @instruction.set_arguments(@cmd[:arguments]) @output << @instruction.code end show(@output.size-1) if @debug end @line += 1 end generate(path) end
Private Instance Methods
Check number of arguments given with expected by instruction
# File lib/rips/assembler.rb, line 101 def argument_size? if @cmd[:arguments].size != @instruction.args_number Error::message( 5, @line, @cmd[:name], @cmd[:arguments].size, @instruction.args_number ) end end
Check if arguments are the same variable type of instruction
# File lib/rips/assembler.rb, line 112 def argument_syntax? @instruction.variables.each_with_index do |var,i| if var.valid_syntax? @cmd[:arguments][i] @cmd[:arguments][i] = @cmd[:arguments][i].arg_to_i else Error::message(6, @line, var.error(@cmd[:arguments][i]) ) end end end
Exists instruction in Instruction Set?
# File lib/rips/assembler.rb, line 81 def exists_instruction? if Instructions::SET.include? (@cmd[:name]) @instruction = get_instruction else Error::message(4, @line, @cmd[:name] ) end end
Store number line for each instruction
# File lib/rips/assembler.rb, line 36 def find_instructions @input.each_with_index do |line,i| if line.instruction? @instructions << i+1 end end end
Store labels and number line
# File lib/rips/assembler.rb, line 45 def find_labels @input.each_with_index do |line, i| if line.label?(i) label = line.split(":")[0] if !@labels.include?(label) @labels[label] = [*@instructions.each_with_index].search{|x, _| x >= i}.last else Error::message(7, i+1, line) end end end end
Generate output in “progfile.dat”
# File lib/rips/assembler.rb, line 130 def generate (path) File.open(path, "w") do |f| @output.each do |line| f.puts line end end end
Obtain instruction's instance object
# File lib/rips/assembler.rb, line 76 def get_instruction Rips::Instructions.const_get("#{@cmd[:name].capitalize}").new end
Split on tokens
# File lib/rips/assembler.rb, line 59 def parse_input (line) if line.comment? @cmd[:comments] = line else @cmd[:name] = line.instruction_name if (@cmd[:name] == "jr") || (@cmd[:name] == "nop") @cmd[:arguments] = [] else @cmd[:arguments] = line.instruction_arguments(@cmd[:name]) end @cmd[:comments] = line.instruction_comments @cmd[:comments].insert(0,"#") if !@cmd[:comments].empty? end end
Translate label's name to instruction's number
# File lib/rips/assembler.rb, line 90 def parse_label if (@instruction.is_a? Rips::Instructions::Beqz) || (@instruction.is_a? Rips::Instructions::Bnez) || (@instruction.is_a? Rips::Instructions::J) || (@instruction.is_a? Rips::Instructions::Jal) @cmd[:arguments] = [@labels[@cmd[:arguments].first].to_s] end end
Codification log of instruction
# File lib/rips/assembler.rb, line 123 def show (i) puts "@#{@line}:" \ "\t#{@output[i].scan(/.{4}|.+/).join("_") unless @instruction.nil?}" \ "\t#{@cmd[:comments]}" end