diff options
author | Nat Lasseter <user@4574.co.uk> | 2019-12-11 21:53:12 +0000 |
---|---|---|
committer | Nat Lasseter <user@4574.co.uk> | 2019-12-11 21:53:12 +0000 |
commit | 693130cae9bdb145af79ee2eb256b661003b6e45 (patch) | |
tree | fc4a450b012545c0f5599c667426d44451fbf71d /intcode/as | |
parent | 3bea5ec1373b842e6ad9f7cff050615e1f5ebde8 (diff) |
Wrote Intcode (dis-)assembler
Diffstat (limited to 'intcode/as')
-rwxr-xr-x | intcode/as | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/intcode/as b/intcode/as new file mode 100755 index 0000000..6a4aaa0 --- /dev/null +++ b/intcode/as @@ -0,0 +1,155 @@ +#!/usr/bin/env ruby + +exit 1 if ARGV.length != 1 + +source = ARGV.shift&.strip + +lines = File.readlines(source) + +class ProgramError < Exception ; end +class ParameterError < ProgramError ; end +class LabelError < ProgramError ; end + +class Program + def initialize + @memory = [] + @org = 0 + @labeldb = {} + end + + def parse(line) + case line[0] + when "@org" + @org = line[1].to_i + when "@dat" + line.shift + line.each do |d| + @memory[@org] = d.to_i + @org += 1 + end + when "add" + raise ParameterError, "Expected positional argument" unless line[3] =~ /\A@/ + @memory[@org] = Program.flag_digits(line[1..3]) + 1 + @memory[@org + 1] = Program.desigil(line[1]) + @memory[@org + 2] = Program.desigil(line[2]) + @memory[@org + 3] = Program.desigil(line[3]) + @org += 4 + when "mul" + raise ParameterError, "Expected positional argument" unless line[3] =~ /\A@/ + @memory[@org] = Program.flag_digits(line[1..3]) + 2 + @memory[@org + 1] = Program.desigil(line[1]) + @memory[@org + 2] = Program.desigil(line[2]) + @memory[@org + 3] = Program.desigil(line[3]) + @org += 4 + when "inp" + raise ParameterError, "Expected positional argument" unless line[1] =~ /\A@/ + @memory[@org] = 3 + @memory[@org + 1] = Program.desigil(line[1]) + @org += 2 + when "out" + @memory[@org] = Program.flag_digits(line[1..1]) + 4 + @memory[@org + 1] = Program.desigil(line[1]) + @org += 2 + when "jnz" + @memory[@org] = Program.flag_digits(line[1..2]) + 5 + @memory[@org + 1] = Program.desigil(line[1]) + @memory[@org + 2] = Program.desigil(line[2]) + @org += 3 + when "jez" + @memory[@org] = Program.flag_digits(line[1..2]) + 6 + @memory[@org + 1] = Program.desigil(line[1]) + @memory[@org + 2] = Program.desigil(line[2]) + @org += 3 + when "tlt" + raise ParameterError, "Expected positional argument" unless line[3] =~ /\A@/ + @memory[@org] = Program.flag_digits(line[1..3]) + 7 + @memory[@org + 1] = Program.desigil(line[1]) + @memory[@org + 2] = Program.desigil(line[2]) + @memory[@org + 3] = Program.desigil(line[3]) + @org += 4 + when "teq" + raise ParameterError, "Expected positional argument" unless line[3] =~ /\A@/ + @memory[@org] = Program.flag_digits(line[1..3]) + 8 + @memory[@org + 1] = Program.desigil(line[1]) + @memory[@org + 2] = Program.desigil(line[2]) + @memory[@org + 3] = Program.desigil(line[3]) + @org += 4 + when "arb" + @memory[@org] = Program.flag_digits(line[1..1]) + 9 + @memory[@org + 1] = Program.desigil(line[1]) + @org += 2 + when "hlt" + @memory[@org] = 99 + @org += 1 + when /(.*):/ + @labeldb[$1] = @org + end + end + + def dump + reify_nils + reify_labels + @memory.join(",") + end + + private + def reify_nils + @memory.map! do |x| + x.nil? ? 0 : x + end + end + + def reify_labels + @memory.map! do |x| + if x.is_a?(String) then + if @labeldb.has_key?(x) then + @labeldb[x] + else + raise LabelError, "Label not found" + end + else + x + end + end + end + + def self.flag_digits(args) + sig = 0 + until args.empty? do + a = args.pop + case a + when /\A@/ + when /\A&/ + sig += 2 + else + sig += 1 + end + sig *= 10 + end + sig * 10 + end + + def self.desigil(str) + case str + when /\A@/ + str[1..-1].to_i + when /\A&/ + str[1..-1].to_i + when /\A[+-0-9]/ + str.to_i + else + str + end + end +end + +p = Program.new + +lines.each do |line| + line = line.split(";")[0].strip + next if line.nil? || line.empty? + line = line.split(/\s*[,\s]\s*/) + p.parse(line) +end + +puts p.dump |