(define stack ()) (define (push val) (set! stack (cons val stack))) (define (pop) (begin0 (top) (set! stack (cdr stack)))) (define (top) (car stack)) (define (second) (cadr stack)) (define (dup) (push (top))) (define (add) (push (+ (pop) (pop)))) (define (mul) (push (* (pop) (pop)))) (define (cons.) (let ((r (cons (second) (top)))) (pop) (pop) (push r))) (define (def name . params) ;; define a function ;; include environments.jl, put function bindings into lexical env 'todo) (define (print.) (format #t "=> ~s\n" (pop))) (define (dump) (print stack)) ;; (operator . number-of-operands) (define operators '((push . 1) (pop . 0) (dup . 0) (add . 0) (mul . 0) (cons. . 0) (print. . 0))) (define (read-eval-print program . args) ;; TODO recursive descent parser for L(vm)? ;; see ruby/cons for an example, lalr.cl, semantic.el ;; >>> try-out in parser.jl "basic interpreter loop: parse program and invoke vm-functions" (let-optionals* args ((debug #f)) (format #t "~s\n" program) (while (not (null? program)) (when debug (dump)) (unless (assoc (car program) operators) (error "unknown operator:" (car program))) (cond ((eq? (car program) 'push) (push (cadr program)) (set! program (cddr program))) (else (eval (car program) (current-module)) (set! program (cdr program))))))) (define (load-program file) "Return a list of tokens representing the program in FILE" ;; TODO load program-text from file and construct program list with (let ((program-text "push 6\npush 7\nmul\nprint.\n")) (read-from-string (string-append "(" program-text ")")))) ;; expression evaluation (read-eval-print '(push 3 push 4 push 5 dup mul mul add print.)) ;; creating a cons (read-eval-print '(push aap push noot cons. print.)) ;; creating a list (read-eval-print `(push aap push noot push mies push ,() cons. cons. cons. print.)) ;; unknown operator (with-error-handler (lambda (err) (format #t "as expected: ~s\n" err)) (lambda () (read-eval-print '(bork)))) ;; loading from a file (read-eval-print (load-program "foo.vm"))