(define (pop stack)
(let ((var (car stack))
(ret-stack (cdr stack)))
(values var ret-stack)))
(define (push var stack)
(append (list var) stack))
(define (dup stack)
(let ((head (car stack)))
(append (list head) stack)))
(define (fact x)
(define (fact-iter n current)
(if (= n 1)
current
(fact-iter (- n 1) (* n current))))
(fact-iter x 1))
(define (rpn-func func stack)
(let*-values (((var1 stack) (pop stack))
((var2 stack) (pop stack)))
(push (func var1 var2) stack)))
(let loop ((input (read)) (stack '()))
(cond
((number? input) (loop (read) (push input stack)))
((eq? '+ input) (loop (read) (rpn-func + stack)))
((eq? '- input) (loop (read) (rpn-func - stack)))
((eq? '* input) (loop (read) (rpn-func * stack)))
((eq? '/ input) (loop (read) (rpn-func / stack)))
((eq? '% input) (loop (read) (rpn-func modulo stack)))
((eq? '! input) (loop (read)
(let-values (((var stack) (pop stack)))
(push (fact var) stack))))
((eq? '$ input) (loop (read)
(let-values (((var stack) (pop stack)))
(display var)
(newline)
stack)))
((eq? 'dup input) (loop (read) (dup stack)))
(else (begin
(display "ERROR not valid input: ")
(display input)
(newline)
(loop (read) stack)))))