module MIPS
  class MIPSSyntaxError < StandardError
    def initialize(msg)
      @msg = msg
    end

    def to_s
      msg
    end
  end

  # Assembly MIPS codes into machine codes.
  class Assembler
    attr_reader :symbol_table, :current_addr

    def initialize
      @symbol_table = {}
      @current_addr = 0x0
    end

    def assembly(line)
      line.sub!(/#*/, "")  # Remove comments.
      line.strip!

      line = read_tag(line)
      return if line.empty?  # Tag line, @current_addr stays the same.

    end

    def self.assembly(line)
      new.assembly(line)
    end

    private

    def read_tag(line)
      return unless /^(?<tag>[a-zA-Z]\w*)\s*:\s*(?<rest>.*)/ =~ line

      if @symbol_table.include? tag
        fail MIPSSyntaxError, "Redeclaration of tag `#{tag}`"
      else
        @symbol_table[tag] = @current_addr
        rest
      end
    end
  end
end

module MIPS
  SYNTAX = /^\s*((?<tag>[a-zA-Z]\w*)\s*:\s*)?((?<cmd>[a-z]+)\s*((?<arg1>\$?\w+)\s*(,\s*((?<arg2>\$?\w+)|((?<offset>\d+)\(\s*(?<arg2>\$\w+)\s*\)))\s*(,\s*(?<arg3>\$?\w+)\s*)?)?)?)?(#.*)?$/

  # Represent a MIPS syntax error
  class MIPSSyntaxError < StandardError
  end

  # Assembly MIPS codes into machine codes.
  class Assembler
    attr_reader :symbol_table, :current_addr

    def initialize
      @symbol_table = {}
      @current_addr = 0x0
    end

    def assembly(src)
      src.each_line do |line|
        fail MIPSSyntaxError, "#{line}: Syntax error." unless SYNTAX =~ line
        read_tag tag
      end
    end

    def self.assembly(src)
      new.assembly(src)
    end

    private

    def read_tag(tag)
      return if tag.nil?  # No tag.

      if @symbol_table.include? tag
        fail MIPSSyntaxError, "Redeclaration of tag `#{tag}`"
      else
        @symbol_table[tag] = @current_addr
      end
    end

    def parse_register
    end

    def parse_tag
    end
  end
end

Use regex to define syntax
Use regex to define syntax
