Skip to content

Instantly share code, notes, and snippets.

@ybakos
Created October 22, 2014 21:26
Show Gist options
  • Save ybakos/890bd8d098ee8d04b7ba to your computer and use it in GitHub Desktop.
Save ybakos/890bd8d098ee8d04b7ba to your computer and use it in GitHub Desktop.
An almost-working assembler for Hack.
require_relative './code'
class String
def is_numeric?
true if Float(self) rescue false
end
end
puts "Hack Assembler!"
def args_valid?
ARGV[0] && ARGV[0].end_with?(".asm") && File.file?(ARGV[0])
end
abort("Usage: ruby assembler.rb filename.asm") unless args_valid?
class Assembler
attr_accessor :instructions
def initialize(asm_commands)
@asm_commands = asm_commands
@instructions = []
@symbol_table = {}
end
def assemble!
symbolize_labels
p @symbol_table
translate_commands
end
def symbolize_labels
@asm_commands.each_with_index do |command, index|
if command.start_with?('(')
label_name = command[/\((.*)\)/, 1]
@symbol_table[label_name] = index
@asm_commands.delete(command)
end
end
end
def translate_commands
@asm_commands.each do |command|
if is_a_command?(command)
assemble_a_command(command)
else
assemble_c_command(command)
end
end
end
def assemble_c_command(command)
dest = command[/(.*)=/, 1]
comp = command[/=(.*)(;)/, 1] || command[/(.*);/, 1] || command[/=(.*)/, 1]
jump = command[/;(.*)/, 1]
c_instruction = "111#{Code.comp(comp)}#{Code.dest(dest)}#{Code.jump(jump)}"
@instructions << c_instruction
end
def is_a_command?(command)
command.start_with?("@")
end
def assemble_a_command(command)
mnemonic = command[/@(.*)/, 1]
instruction = "0"
if (mnemonic.is_numeric?)
instruction << "%015b" % mnemonic
elsif (@symbol_table.has_key?(mnemonic))
instruction << "%015b" % @symbol_table[mnemonic]
end
@instructions << instruction
end
end
asm_file = File.open(ARGV[0])
asm_commands = asm_file.readlines.reject { |l| l.start_with?("//") || l == "\r\n" }
asm_commands.each do |c|
c.lstrip!
c.gsub!(/\/\/.*/, '')
c.rstrip!
c.chomp!
end
# asm_commands = asm_file.read.scan /@\S*|\S+=\S+|\S.*;\S*|\(\S*\)/
p asm_commands
hack_filename = ARGV[0].gsub(/.asm/, ".mine.hack")
assembler = Assembler.new(asm_commands)
assembler.assemble!
File.open(hack_filename, 'w') do |file|
assembler.instructions.each do |i|
file << i << "\n"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment