#!/usr/bin/ruby -w OPCODES = { "i" => 0x080, "acc=" => 0x000, "ladd" => 0x100, "store" => 0x200, "ifeq" => 0x300, "jmp" => 0x400, "ascii" => 0x500, "++acc" => 0xf01, "--acc" => 0xf02, "++idx" => 0xf04, "--idx" => 0xf08, "swap" => 0xf10, "idx" => 0xf20, "tx" => 0xf40, "halt" => 0xf80, } Line = Struct.new(:opcode, :refs, :code) $labels = {} $code = [] ARGF.each_line() do | line | line.chomp!() line.sub!(/^.*\/\/\s*/, "") next unless line =~ /\S/ op = 0x000 refs = [] line.scan(/\S+/).each() do | word | break if word =~ /^#/ if word =~ /^0(\d+)$/ op |= $1.to_i(8) elsif word =~ /^-0(\d+)$/ op |= 0x100 - $1.to_i(8) elsif word =~ /^(\d+)$/ op |= $1.to_i(10) elsif word =~ /^-(\d+)$/ op |= 0x100 - $1.to_i(10) elsif word =~ /^0x([0-9a-f]+)$/i op |= $1.to_i(16) elsif word =~ /^-0x([0-9a-f]+)$/i op |= 0x100 - $1.to_i(16) elsif OPCODES.key?(word) op |= OPCODES[word] elsif word =~ /^(.+):$/ $labels[$1] = $code.size() else refs << word end end $code << Line.new(op, refs, line) end $code.each_with_index() do | line, i | op = line.opcode line.refs.each() do | ref | if $labels.key?(ref) target = $labels[ref] - (i + 1) target += 0x100 if target < 0 op |= target else throw "I don't understand #{ref.inspect()}" end end $stdout.write("#{op.to_s(16).rjust(3, "0")} // #{line.code}\n") end