commit 997f0e3e0aba1f2846dc01c3447058f887419411
parent fbc2832fa5316af243fffadaa57547ef91274f56
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Wed, 1 Jun 2022 13:51:40 -0400
Add branches, stype and string literal
We have the "Dusk OS" prompt.
Diffstat:
M | README.md | | | 1 | + |
M | asm.py | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ |
M | dusk.c | | | 28 | +++++++++++++++++++++++----- |
M | forth.txt | | | 6 | ++++-- |
M | ops.txt | | | 6 | ++++-- |
5 files changed, 117 insertions(+), 24 deletions(-)
diff --git a/README.md b/README.md
@@ -10,6 +10,7 @@ has a widened scope:
* Access, visualize and print images and PDFs.
* Compress and decompress files.
* Edit and compile C code. Possibly other languages too.
+* No focus on binary size (unlike Collapse OS, we have plenty here).
Additionally, it's worth mentioning that as a consequence of its laser sharp
focus on simplicity, Dusk OS is also defined by what it *doesn't* do:
diff --git a/asm.py b/asm.py
@@ -7,20 +7,35 @@ import struct
ops = open('ops.txt', 'rb').read().split(b',')
ops = [s.strip() for s in ops]
ops = {name:i for i, name in enumerate(ops)}
-tokens = open(sys.argv[1], 'rb').read().split()
-tokens = [s.strip() for s in reversed(tokens)]
+fp = open(sys.argv[1], 'rb')
outbuf = bytearray()
prevword = 0
words = {} # name:pc
labels = {} # name:pc
+ps = [] # PS for immediate words
def out(fmt, *args):
outbuf.extend(struct.pack(fmt, *args))
+def opwr(name):
+ if isinstance(name, str):
+ name = name.encode()
+ out('<b', ops[name])
+
+def intwr(n):
+ out('<i', n)
+
+def intset(offset, n):
+ outbuf[offset:offset+4] = struct.pack('<i', n)
+
+def litwr(n):
+ opwr('_i_')
+ intwr(n)
+
def pc():
return len(outbuf)
-def lit(s): # parse a literal
+def litparse(s):
if len(s) == 3 and s[0] == ord("'") and s[2] == ord("'"):
return s[1]
elif s.isdigit():
@@ -28,7 +43,14 @@ def lit(s): # parse a literal
return None
def nextt():
- return tokens.pop()
+ r = bytearray()
+ c = fp.read(1)
+ while c and c[0] <= 0x20:
+ c = fp.read(1)
+ while c and c[0] > 0x20:
+ r.append(c[0])
+ c = fp.read(1)
+ return bytes(r)
def newword():
global prevword
@@ -38,27 +60,75 @@ def newword():
prevword = pc()
words[name] = prevword
+def _if_():
+ opwr('_br_')
+ ps.append(pc())
+ intwr(0)
-while tokens:
- t = nextt()
+def _then_():
+ intset(ps.pop(), pc())
+
+def _begin_():
+ ps.append(pc())
+
+def _again_():
+ opwr('_br_')
+ intwr(ps.pop())
+
+def _until_():
+ opwr('_cbr_')
+ intwr(ps.pop())
+
+def _next_():
+ opwr('_next_')
+ intwr(ps.pop())
+
+def slitwr():
+ s = bytearray()
+ c = fp.read(1)
+ while c and c != b'"':
+ s.append(c[0])
+ c = fp.read(1)
+ _if_()
+ spc = pc()
+ outbuf.extend(s)
+ _then_()
+ litwr(spc)
+ litwr(len(s))
+
+special = {
+ b':': newword,
+ b'S"': slitwr,
+ b'if': _if_,
+ b'then': _then_,
+ b'begin': _begin_,
+ b'again': _again_,
+ b'until': _until_,
+ b'next': _next_,
+}
+
+t = nextt()
+while t:
if t in ops:
- out('b', ops[t])
+ opwr(t)
elif t in words:
- out('<bi', ops[b'CALLi'], words[t])
- elif t == b':':
- newword()
+ opwr('_call_')
+ intwr(words[t])
+ elif t in special:
+ special[t]()
elif t.startswith(b'lbl'):
labels[t] = pc()
- out('<i', 0)
+ intwr(0)
else:
- n = lit(t)
+ n = litparse(t)
if n is None:
t = t.decode()
print(f"invalid token {t}", file=sys.stderr)
sys.exit(1)
else:
- out('<bi', ops[b'PUSHi'], n)
+ litwr(n)
+ t = nextt()
-n = labels[b'lblboot']
-outbuf[n:n+4] = struct.pack('<i', words[b'BOOT'])
+fp.close()
+intset(labels[b'lblboot'], words[b'BOOT'])
sys.stdout.buffer.write(outbuf)
diff --git a/dusk.c b/dusk.c
@@ -1,6 +1,7 @@
#include <inttypes.h>
#include <stdio.h>
+#define CSIZE 4
#define MEMSIZE 0x10000
#define STACKSIZE 0x100
@@ -41,23 +42,40 @@ static cell pop() { return stack_pop(&ps); }
static void push(cell x) { stack_push(&ps, x); }
static cell popRS() { return stack_pop(&rs); }
static void pushRS(cell x) { stack_push(&rs, x); }
-static cell pc32() { cell n = gc(pc); pc+=4; return n; }
+static cell pc32() { cell n = gc(pc); pc+=CSIZE; return n; }
/* Native words */
/* stack */
-static void PUSHi() { push(pc32()); }
+static void _i_() { push(pc32()); }
+static void dup() { push(peek()); }
+static void swap() { cell a = pop(); cell b = pop(); push(a); push(b); }
+static void p2r() { pushRS(pop()); }
+static void r2p() { push(popRS()); }
/* flow */
-static void JMPi() { pc = gc(pc); }
-static void CALLi() { pushRS(pc+4); JMPi(); }
+static void _br_() { pc = gc(pc); }
+static void _cbr_() { if (pop()) { pc+=CSIZE; } else { _br_(); } }
+static void _next_() {
+ cell n = popRS()-1;
+ if (n) { pushRS(n); _br_(); }
+ else { pc+=CSIZE; }
+}
+static void _call_() { pushRS(pc+CSIZE); _br_(); }
static void exit() { pc = popRS(); }
static void bye() { running = 0; }
+/* memory */
+static void cfetch() { cell a = pop(); push(mem[a]); }
+
+/* arithmetic */
+static void inc() { push(pop()+1); }
+static void dec() { push(pop()-1); }
+
/* I/O */
static void emit() { putchar(pop()); }
static void key() { push(getchar()); }
-static void (*ops[7])() = {
+static void (*ops[16])() = {
#include "ops.txt"
};
diff --git a/forth.txt b/forth.txt
@@ -1,3 +1,5 @@
-JMPi lblboot
-: foo 'f' emit 'o' emit 'o' emit exit
+_br_ lblboot
+: c@+ dup inc swap cfetch exit
+: stype p2r begin c@+ emit next exit
+: foo S" Dusk OS" stype exit
: BOOT foo bye
diff --git a/ops.txt b/ops.txt
@@ -1,3 +1,5 @@
-PUSHi,
-JMPi, CALLi, exit, bye,
+_i_, dup, swap, p2r, r2p,
+_br_, _cbr_, _next_, _call_, exit, bye,
+cfetch,
+inc, dec,
emit, key