ans/ans.ss
#lang scheme/base

;; I've been looking for a long time to find a solution to writing a
;; frontend that's ANS Forth compatible.  I'm still not sure wheter it
;; is really useful at this point, but if it is not too difficult, it
;; might be a nice addition that enables the inclusion of Staapl into
;; a more traditional Forth based project. 

;; The problem in itself isn't very difficult: Find a Forth written in
;; Forth + a small set of primitives and implement the primitives.
;; However, I'd like to do it in a way that enables some more
;; flexibility.

;; After pondering this for a while, I think this might be an
;; interesting approach: Write a simulated Forth, use it to generate a
;; memory image, and translate the compiled threaded code to run on
;; top of Scat's Forth / Coma.

;; Doing this in a way that enables gradual offloading to the target
;; is not that simple.  Wanting more control over dictionary format
;; and execution model (i'd like to use STC primitives) makes things
;; quite challenging.



;; -----

(require
 "../scat.ss"
 (for-syntax
  scheme/base
  "../scat-tx.ss"))

;; In contrast to Coma, the ANS Forth frontend is implemented using
;; mutable state. This state is stored in parameters to keep it local.

(define ans-dictionary '())
(define-struct ans-link (name mode code))
(define ans-input-stream (make-parameter #f))
(define ans-output-stream (make-parameter #f))

;; I'm curious if memory needs to be an array. This probably depends
;; on the implementation of fetch and store only..
(define ans-memory (make-parameter (make-vector 100)))

(define (ans-fetch addr)     (vector-ref  (ans-memory) addr))
(define (ans-store val addr) (vector-set! (ans-memory) addr val))

(snarf as-void (ans) ((val addr) ((! ans-store))))
(snarf as-push (ans) ((addr)     ((@ ans-fetch))))

(define-syntax-rule (scat-snarf id ...)
  (begin (define-ns (ans) id (ns (scat) id)) ...))

(scat-snarf * + - 2/ 2*)
 

;; Primitive ANS words
(compositions
 (ans) scat:
 

)

(define-syntax (ans: stx)
  (syntax-case stx ()
    ((_ . code)
     (with-scat-syntax
      (lambda ()
        (parameterize
            ((rpn-map-identifier (lambda (id) (ns-prefixed #'(ans) id))))
          (rpn-compile #'code)))))))

(compositions
 (ans) ans:
 
 

 )
;; http://lars.nocrew.org/dpans/dpans.htm
;; core wordset:

;; !  # #> #S ' ( * */ */MOD + +!  +LOOP , - .  ."  / /MOD 0< 0= 1+ 1- 2!
;; 2* 2/ 2@ 2DROP 2DUP 2OVER 2SWAP : ; < <# = > >BODY >IN >NUMBER >R ?DUP
;; @ ABORT ABORT" ABS ACCEPT ALIGN ALIGNED ALLOT AND BASE BEGIN BL C!  C,
;; C@ CELL+ CELLS CHAR CHAR+ CHARS CONSTANT COUNT CR CREATE DECIMAL DEPTH
;; DO DOES> DROP DUP ELSE EMIT ENVIRONMENT?  EVALUATE EXECUTE EXIT FILL
;; FIND FM/MOD HERE HOLD I IF IMMEDIATE INVERT J KEY LEAVE LITERAL LOOP
;; LSHIFT M* MAX MIN MOD MOVE NEGATE OR OVER POSTPONE QUIT R> R@ RECURSE
;; REPEAT ROT RSHIFT S" S>D SIGN SM/REM SOURCE SPACE SPACES STATE SWAP
;; THEN TYPE U.  U< UM* UM/MOD UNLOOP UNTIL VARIABLE WHILE WORD XOR [ [']
;; [CHAR] ]


;; The problem with implementing this in a way that it can be
;; simulated on the host and moved to the target lies in 3 parts:

;;   * INPUT:       ACCEPT

;;   * DICTIONARY:  FIND WORD VARIABLE CONSTANT CREATE POSTPONE

;;   * THREADING: