class Rips::Assembler

Public Class Methods

new(debug) click to toggle source

@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

<<(value) click to toggle source

Stores each new line of file

# File lib/rips/assembler.rb, line 141
def << (value)
  @input << value.strip
end
run(path = "progfile.dat") click to toggle source

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

argument_size?() click to toggle source

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
argument_syntax?() click to toggle source

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?() click to toggle source

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
find_instructions() click to toggle source

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
find_labels() click to toggle source

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(path) click to toggle source

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
get_instruction() click to toggle source

Obtain instruction's instance object

# File lib/rips/assembler.rb, line 76
def get_instruction
  Rips::Instructions.const_get("#{@cmd[:name].capitalize}").new
end
parse_input(line) click to toggle source

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
parse_label() click to toggle source

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
show(i) click to toggle source

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