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) }