repos / gbc

GBC - Go B Compiler
git clone https://github.com/xplshn/gbc.git

gbc / lib / b
xplshn  ·  2025-08-13

uxn.b

B
  1/* Standard Library for the Uxn target */
  2
  3fputc(c, fd) {
  4    extrn uxn_deo;
  5    uxn_deo(fd + 0x18, c); /* 0x18 - Console/write,
  6                              0x19 - Console/error */
  7}
  8
  9putchar(c) {
 10    fputc(c, 0);
 11}
 12
 13exit(code) {
 14    extrn uxn_deo;
 15    uxn_deo(0x0f, code | 0x80); /* System/state */
 16}
 17
 18abort() {
 19    extrn printf;
 20    printf("Aborted\n");
 21    exit(1);
 22}
 23
 24_udiv(a, b) {
 25    extrn uxn_div2;
 26    return (uxn_div2(a, b));
 27}
 28
 29// TODO: `b` has to be <32768, because of `*`
 30_urem(a, b) {
 31    return (a - _udiv(a, b) * b);
 32}
 33
 34/* loosely based on the original code by Ken Thompson */
 35
 36_fprintn(n, b, fd) {
 37    auto a, c;
 38
 39    if(a=_udiv(n,b)) /* assignment, not test for equality */
 40        _fprintn(a, b, fd); /* recursive */
 41    c = _urem(n,b) + '0';
 42    if (c > '9') c += 7;
 43    fputc(c, fd);
 44}
 45
 46printn(n, b) _fprintn(n, b, 0);
 47
 48/* doesn't support fancy features like padding, but neither did the original in B */
 49
 50/* TODO: Consider adding support for negative numbers to Uxn's printf. */
 51/* TODO: Consider adding support for %ul to Uxn's printf. */
 52fprintf(fd, string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
 53    extrn char;
 54    auto i, j, c, arg;
 55    i = 0;
 56    j = 0;
 57    c = char(string, i);
 58    arg = &x1;
 59    while (c != 0) {
 60        if (c == '%') {
 61            i += 1;
 62            c = char(string, i);
 63            if (c == 0) {
 64                return;
 65            } else if (c == 'x') {
 66                _fprintn(*arg, 16, fd);
 67            } else if (c == 'd') {
 68                if (*arg < 0) {
 69                    fputc('-', fd);
 70                    *arg = -*arg;
 71                }
 72                _fprintn(*arg, 10, fd);
 73            } else if (c == 'u') {
 74                _fprintn(*arg, 10, fd);
 75            } else if (c == 'o') {
 76                _fprintn(*arg, 8, fd);
 77            } else if (c == 'c') {
 78                fputc(*arg, fd);
 79            } else if (c == 's') { /* clobbers `c`, the last one */
 80                while (c = char(*arg, j++)) {
 81                    fputc(c, fd);
 82                }
 83            } else if (c == 'l' | c == 'z') {
 84                c = '%';
 85                goto continue;
 86            } else {
 87                fputc('%', fd);
 88                arg += 2; /* word size */
 89            }
 90            arg -= 2; /* word size */
 91        } else {
 92            fputc(c, fd);
 93        }
 94        i += 1;
 95        c = char(string, i);
 96        continue:;
 97    }
 98}
 99
100printf(string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) {
101    fprintf(0, string, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12);
102}
103
104// TODO: doesn't skip whitespace, doesn't handle negative numbers
105atoi(s) {
106    extrn char;
107    auto i, result, c;
108    i = 0;
109    while (1) {
110        c = char(s, i++);
111        if (c < '0' | c > '9') {
112            goto out;
113        }
114        result = result * 10 + (c - '0');
115    }
116out:
117    return (result);
118}
119
120/* simple bump allocator */
121
122__alloc_ptr;
123
124malloc(size) {
125    auto ret;
126    if (__alloc_ptr == 0) {
127        __alloc_ptr = 0x8000; /* provide __heap_base by the compiler? */
128    }
129    ret = __alloc_ptr;
130    __alloc_ptr += size;
131    return (ret);
132}
133
134memset(addr, val, size) {
135    extrn lchar;
136    auto i;
137    i = 0;
138    while (i < size) {
139        lchar(addr, i, val);
140        i += 1;
141    }
142}
143
144stdout; stderr;
145
146_args_count;
147_args_items;
148_prog_name;
149
150_start_with_arguments() {
151    extrn uxn_dei, uxn_deo2, lchar, main;
152    auto type, c;
153    type = uxn_dei(0x17); /* Console/type */
154    c = uxn_dei(0x12);
155    if (type == 2) { /* argument */
156        lchar(__alloc_ptr++, 0, c);
157    } else if (type == 3) { /* argument spacer */
158        lchar(__alloc_ptr++, 0, 0);
159        *(_args_items + (_args_count++)*2) = __alloc_ptr;
160    } else if (type == 4) { /* arguments end */
161        lchar(__alloc_ptr++, 0, 0);
162        uxn_deo2(0x10, 0);
163        exit(main(_args_count, _args_items));
164    }
165}
166
167_start() {
168    extrn main, uxn_dei, uxn_deo2;
169    __alloc_ptr = 0x8000;
170    _args_items = 0x7f00; /* 128 arguments ought to be enough for everyone */
171    stdout = 0;
172    stderr = 1;
173    _prog_name = "-"; /* we don't have access to it */
174    *_args_items = _prog_name;
175    _args_count = 1;
176    if (uxn_dei(0x17) != 0) {
177        *(_args_items + (_args_count++)*2) = __alloc_ptr;
178        uxn_deo2(0x10, &_start_with_arguments);
179    } else {
180        exit(main(_args_count, _args_items));
181    }
182}
183
184strlen(s) {
185    auto n;
186    n = 0;
187    while (*s++) n++;
188    return (n);
189}
190
191toupper(c) {
192    if ('a' <= c & c <= 'z') return (c - 'a' + 'A');
193    return (c);
194}