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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
use bio
use std
const strdup = {s
var buf = std.slalloc(s.len)
std.slcp(buf, s)
-> buf
}
const upcase = {s
var i
var buf = std.mksb()
for i = 0; i < s.len; i++
std.sbputc(buf, std.toupper((s[i] : char)))
;;
-> std.sbfin(buf)
}
const readline = {line
var cmt = std.strfind(line, ";")
match cmt
| `std.Some (pos): line = line[:pos]
| `std.None:
;;
if line.len == 0
-> (`std.None, [][:])
;;
var parts = std.strtok(line)
if std.isspace((line[0] : char))
-> (`std.None, parts)
else
-> (`std.Some(parts[0]), parts[1:])
;;
}
const parsehex = {s
if s[0] == ('#' : byte)
-> std.intparsebase((s[1:] : byte[:]), 16)
else
-> `std.None
;;
}
const emitinstr = {p
var b = `std.None
var mark = `std.None
if p.len < 1
-> `std.Ok(b, mark)
;;
match upcase(p[0])
| "CLS":
b = `std.Some([0x00, 0xe0])
| "SYS":
if p.len < 2
-> `std.Err("SYS missing subroutine address")
;;
match parsehex(p[1])
| `std.Some(n): b = `std.Some([0x20 | (n & 0x0f00), (n & 0xff)])
| `std.None: b = `std.Some([0x20, 0x00])
mark = `std.Some(strdup(p[1]))
;;
| _:
-> `std.Err("unrecognized instruction")
;;
-> `std.Ok((b, mark))
}
const main = {
var fd = bio.mkfile(std.In, bio.Rd)
var src = bio.byline(fd)
var lc = 0
var offset = 0
var queue = [][:]
var buf = [][:]
var labels = std.mkht()
var res
for line : src ;
match readline(line)
| (`std.None, i): res = emitinstr(i)
| (`std.Some (label), i): res = emitinstr(i)
std.htput(labels, strdup(label), offset)
;;
match res
| `std.Err(msg): std.die(std.fmt("{} on line {}\n", msg, lc))
| `std.Ok((bytes, marker)):
match marker
| `std.Some(label): queue = std.slpush(&queue, (label, offset, lc))
| `std.None:
;;
match bytes
| `std.Some(arr): buf = std.sljoin(&buf, arr[:])
offset += 2
| `std.None:
;;
;;
lc++
;;
for replacement : queue ;
match replacement
| (l, buf_pos, src_pos):
match std.htget(labels, l)
| `std.None: std.die(std.fmt("reference to undefined label '{}' on line {}\n", l, src_pos))
| `std.Some(addr): buf[buf_pos] |= addr & 0x0f00
buf[buf_pos + 1] |= addr & 0xff
;;
;;
;;
std.write(std.Out, buf)
bio.free(fd)
}
|