1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
#!/usr/bin/ruby -w
OPCODES = {
"acc=" => 0x000,
"load" => 0x100,
"store" => 0x200,
"ifeq" => 0x300,
"jmp" => 0x400,
"++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 |
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
|