summaryrefslogtreecommitdiff
path: root/asm.myr
blob: f8689d5be220d71e5ae3f713287036c476deac6b (plain)
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
use bio
use std

const readline = {line
        var cmt = std.strfind(line, ";")

        match cmt
        | `std.Some (pos): line = line[:pos]
        | `std.None:
        ;;

        var parts = std.strtok(line)
        if std.isspace((line[0] : char))
                -> (`std.None, parts)
        else
                -> (`std.Some(parts[0]), parts[1:])
        ;;
}

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 parsehex = {s
        if s[0] == ('#' : byte)
                -> std.intparsebase((s[1:] : byte[:]), 16)
        else
                -> `std.None
        ;;
}

const emitinstr = {p
        var b
        var mark = `std.None

        if p.len < 1
                -> `std.Ok([][:], mark)
        ;;

        match upcase(p[0])
        | "CLS":
                b = [0x00, 0xe0][:]
        | "SYS":
                if p.len < 2
                        -> `std.Err("SYS missing subroutine address")
                ;;
                match parsehex(p[1])
                | `std.Some(n): b = [0x20 | (n & 0x0f00), (n & 0xff)][:]
                | `std.None: b = [0x2f, 0xff][:]
                        mark = `std.Some(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, label, offset)
                ;;

                match res
                | `std.Err(msg): std.die(std.fmt("{} at {}", msg, lc))
                | `std.Ok((bytes, marker)): buf = std.sljoin(&buf, bytes)
                        offset += bytes.len
                        match marker
                        | `std.Some(label): queue = std.slpush(&queue, label)
                        | `std.None:
                        ;;
                ;;

                lc++
        ;;
        std.put("{}", buf)

        bio.free(fd)
}