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
66
67
68
69
70
|
#!/usr/bin/ruby -w
OPCODES = {
"i" => 0x080,
"acc=" => 0x100,
"ladd" => 0x200,
"store" => 0x300,
"ifeq" => 0x400,
"jmp" => 0x500,
"ascii" => 0x600,
"cla" => 0x001,
"++acc" => 0x002,
"--acc" => 0x004,
"tx" => 0x040,
"rx" => 0x080,
"halt" => 0x000,
}
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 ref =~ /^@(.+)$/ and $labels.key?($1)
op |= $labels[$1]
elsif $labels.key?(ref)
target = $labels[ref] - (i + 1)
throw "Jump too far forward" if target > 0x7f
target += 0x80 if target < 0
throw "Jump too far backward" 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
|