;; Forth reader — whitespace-delimited tokens. (define forth-whitespace? (fn (ch) (or (= ch " ") (or (= ch "\t") (or (= ch "\n") (= ch "\r")))))) (define forth-tokens-loop (fn (src n i buf out) (if (>= i n) (if (> (len buf) 0) (concat out (list buf)) out) (let ((ch (char-at src i))) (if (forth-whitespace? ch) (if (> (len buf) 0) (forth-tokens-loop src n (+ i 1) "" (concat out (list buf))) (forth-tokens-loop src n (+ i 1) buf out)) (forth-tokens-loop src n (+ i 1) (str buf ch) out)))))) (define forth-tokens (fn (src) (forth-tokens-loop src (len src) 0 "" (list)))) (define forth-digit-value (fn (ch base) (let ((code (char-code ch)) (cc (char-code (downcase ch)))) (let ((v (if (and (>= code 48) (<= code 57)) (- code 48) (if (and (>= cc 97) (<= cc 122)) (+ 10 (- cc 97)) -1)))) (if (and (>= v 0) (< v base)) v nil))))) (define forth-parse-digits-loop (fn (src n i base acc) (if (>= i n) acc (let ((d (forth-digit-value (char-at src i) base))) (if (nil? d) nil (forth-parse-digits-loop src n (+ i 1) base (+ (* acc base) d))))))) (define forth-parse-digits (fn (src base) (if (= (len src) 0) nil (forth-parse-digits-loop src (len src) 0 base 0)))) (define forth-strip-prefix (fn (s) (if (<= (len s) 1) (list s 0) (let ((c (char-at s 0))) (if (= c "$") (list (substring s 1 (len s)) 16) (if (= c "%") (list (substring s 1 (len s)) 2) (if (= c "#") (list (substring s 1 (len s)) 10) (list s 0)))))))) (define forth-parse-number (fn (tok base) (let ((n (len tok))) (if (= n 0) nil (if (and (= n 3) (and (= (char-at tok 0) "'") (= (char-at tok 2) "'"))) (char-code (char-at tok 1)) (let ((neg? (and (> n 1) (= (char-at tok 0) "-")))) (let ((s1 (if neg? (substring tok 1 n) tok))) (let ((pair (forth-strip-prefix s1))) (let ((s (first pair)) (b-override (nth pair 1))) (let ((b (if (= b-override 0) base b-override))) (let ((v (forth-parse-digits s b))) (if (nil? v) nil (if neg? (- 0 v) v)))))))))))))