summaryrefslogtreecommitdiff
path: root/asm.myr
blob: 5206f860cd226ba05ee62c138ce319284ef46b56 (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
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)
}