aboutsummaryrefslogtreecommitdiff
path: root/intcode/as
diff options
context:
space:
mode:
authorNat Lasseter <user@4574.co.uk>2019-12-11 21:53:12 +0000
committerNat Lasseter <user@4574.co.uk>2019-12-11 21:53:12 +0000
commit693130cae9bdb145af79ee2eb256b661003b6e45 (patch)
treefc4a450b012545c0f5599c667426d44451fbf71d /intcode/as
parent3bea5ec1373b842e6ad9f7cff050615e1f5ebde8 (diff)
Wrote Intcode (dis-)assembler
Diffstat (limited to 'intcode/as')
-rwxr-xr-xintcode/as155
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