#lang scheme/base
(require
"mem.ss"
"eforth-tools.ss"
scheme/control
(for-syntax scheme/base))
(define *SP* #x0000) (define *RP* #x0001) (define *IP* #x0002)
(define (stack-push sp-addr val)
(notrace
(let ((sp (sub1 (mem@ sp-addr))))
(mem! sp val)
(mem! sp-addr sp))))
(define (stack-pop sp-addr)
(notrace
(let* ((sp (mem@ sp-addr))
(val (mem@ sp)))
(mem! sp-addr (add1 sp))
val)))
(define (lit . ns) (for ((n ns)) (stack-push *SP* n)))
(define (pop) (stack-pop *SP*))
(define (top) (notrace (mem@ (mem@ *SP*))))
(define-syntax locals
(lambda (stx)
(syntax-case stx ()
((_ formals . body)
(syntax-case (reverse (syntax->list #'formals)) ()
((rf ...)
#`(let* ((rf (pop)) ...) . body)))))))
(define (.S [n 10])
(notrace
(for ((val (reverse
(for/list ((i (in-range n)))
(mem@ (+ (mem@ *SP*) i))))))
(printf " ~a" val))
(newline)))
(define (not-implemented name) (error 'not-implemented "~a" name))
(define-syntax CODE
(syntax-rules ()
((_ name) (CODE name (not-implemented 'name)))
((_ name . body) (define name (lambda () . body)))))
(CODE @ (locals (addr) (lit (mem@ addr))) ($NEXT))
(CODE ! (locals (val addr) (mem! addr val)) ($NEXT))
(define C! !)
(define C@ @)
(CODE DROP (pop) ($NEXT))
(CODE SWAP (locals (a b) (lit b a)) ($NEXT))
(CODE DUP (locals (a) (lit a a)) ($NEXT))
(CODE OVER (locals (a b) (lit a b a)) ($NEXT))
(CODE SP@ (lit (mem@ *SP*)) ($NEXT))
(CODE RP@ (lit (mem@ *RP*)) ($NEXT))
(CODE SP! (mem! *SP* (pop)) ($NEXT))
(CODE RP! (mem! *RP* (pop)) ($NEXT))
(define (binop op) (locals (a b) (lit (op a b))))
(CODE AND (binop bitwise-and) ($NEXT))
(CODE OR (binop bitwise-ior) ($NEXT))
(CODE XOR (binop bitwise-xor) ($NEXT))
(CODE UM+ (locals (a b)
(let ((sum (+ a b)))
(lit sum
(arithmetic-shift sum (- word-size)))))
($NEXT))
(CODE R> (lit (stack-pop *RP*)) ($NEXT))
(CODE R@ (lit (mem@ *RP*)) ($NEXT))
(CODE >R (stack-push *RP* (pop)) ($NEXT))
(CODE 0< (locals (a) (lit (if (< a 0) -1 0))) ($NEXT))
(CODE BYE (printf "BYE\n") (abort (void)))
(CODE ?RX (let ((c (read-char)))
(if (eof-object? c)
(lit 0)
(lit (char->integer c) -1)))
($NEXT))
(CODE TX! (write-char (integer->char (pop))) ($NEXT))
(CODE !IO ($NEXT))
(define (*IP++) (stack-pop *IP*))
(define (IP! ip) (mem! *IP* ip))
(CODE doLIT (lit (*IP++)) ($NEXT))
(CODE doLIST (locals (addr)
(stack-push *RP* (mem@ *IP*))
(mem! *IP* addr))
($NEXT))
(CODE EXIT (mem! *IP* (stack-pop *RP*)) ($NEXT))
(define (goto xt) (continue (mem@ xt)))
(define ($NEXT) (goto (*IP++)))
(CODE EXECUTE (goto (pop)))
(CODE branch (let ((xt (*IP++))) (mem! *IP* xt)) ($NEXT))
(CODE ?branch (locals (flag) (let ((ip (*IP++))) (when (zero? flag) (IP! ip)))) ($NEXT))
(CODE next (let*
((ip (*IP++))
(count (sub1 (stack-pop *RP*))))
(unless (zero? count)
(IP! ip)
(stack-push *RP* count)))
($NEXT))
(CODE D$)
(CODE $USER)
(CODE $COLON)
(CODE $CODE)
(define instruction-table
(list->vector
(list
BYE ?RX TX! !IO doLIT doLIST EXIT EXECUTE next ?branch branch ! @
C! C@ RP@ RP! R> R@ >R SP@ SP! DROP DUP SWAP OVER 0< AND OR XOR UM+
D$ $USER $COLON $CODE)))
(define (continue ins)
(let ((primitive (vector-ref instruction-table ins)))
(primitive)))
(define *DICT* #x100)
(define (instruction->xt ins)
(+ *DICT*
(prompt
(for ((i (in-range (vector-length instruction-table)))
(p instruction-table))
(when (eq? ins p) (abort i)))
0)))
(define (compile: . lst)
(for/list ((ins lst))
(if (number? ins)
ins (instruction->xt ins))))
(define (hello)
(append
(compile: doLIT 3 >R)
(apply append (for/list ((c "Staapl eForth 1.0\n"))
(compile: doLIT (char->integer c) TX!)))
(compile: next #x1003)
(compile: BYE)
))
(define (boot)
(newline)
(mem! *SP* #x0000) (mem! *RP* #xFF00) (mem! *IP* #x1000)
(apply mem! *DICT*
(for/list ((i (in-range
(vector-length instruction-table))))
i))
(apply mem! #x1000 (hello))
(prompt ($NEXT)))
(boot)