;; This is a denotational interpreter for PostFix ;; Built on Wed Sep 7 12:45:14 EDT 1994 ;; Includes: ;; pf-syntax.scm ;; repl.scm ;; pf-den-interp.scm ;;--------------------------------------------------- ;; pf-syntax.scm ;;;---------------------------------------------------------------------------- ;;; PF-SYNTAX.SCM ;;; ;;; Postfix syntax and parsing ;;;---------------------------------------------------------------------------- ;;;--------------------------------------------------------------------------- ;;; Datatypes (define-datatype program ($prog (listof command))) (define-datatype command ($int int) ($seq (listof command)) ($pop) ($swap) ($dup) ($sel) ($exec) ($arithop (-> (int int) int)) ($relop (-> (int int) bool)) ) ;;;---------------------------------------------------------------------------- ;;; Parsing (define (pf-program sexp) (match sexp ((list->sexp lst) ($prog (pf-sequence lst))) (_ (error "Ill-formed program")))) (define (pf-sequence lst) (map pf-command lst)) (define (pf-command sexp) (match sexp ( (int->sexp n) ($int n) ) ( (list->sexp lst) ($seq (pf-sequence lst)) ) ( 'pop ($pop) ) ( 'swap ($swap) ) ( 'exec ($exec) ) ( 'sel ($sel) ) ( 'dup ($dup) ) ;; Below, arithop and relop operations are functions, not symbols! ( 'add ($arithop +) ) ( 'sub ($arithop -) ) ( 'mul ($arithop *) ) ( 'div ($arithop quotient) ) ; integer division ( 'lt ($relop <) ) ( 'eq ($relop =) ) ( 'gt ($relop >) ) ( _ (error "Unrecognized command" sexp) ) )) ;;--------------------------------------------------- ;; repl.scm (define (make-repl evaluator prompt parser unparser) (lambda () (let loop () (display "\n\n") (display prompt) (display " ") (let ((sexp (read))) (if (eq? sexp 'quit) (display "\nGoodbye!\n") (begin (display "\n") (display (unparser (evaluator (parser sexp)))) (loop))))))) ;;--------------------------------------------------- ;; pf-den-interp.scm ;;;---------------------------------------------------------------------------- ;;; PF-DEN-INTERP.SCM ;;; ;;; A PostFix interpreter based on the denotational semantics for PostFix. ;;; This is a "curried version" in which stacks are passed in a curried ;;; style. This corresponds directly to the denotational semantics. ;;; Uses Scheme's ERROR instead of error-stack to model errors. ;;; ;;; EXERCISES: ;;; * Model errors explicitly (don't forget divide-by-zero). ;;; * Write in terms of WITH-INT&STACK; WITH-ERROR ;;; * Add DUP. ;;; * Modify so that EVAL-COMMAND and EVAL-COMMANDS are take stack in ;;; uncurried fashion. ;;; ;;;---------------------------------------------------------------------------- ;;;--------------------------------------------------------------------------- ;;; Evaluation (define-datatype den-val (int->den-val int) (xform->den-val (-> (stack) stack))) ;; eval-program: (-> (program) den-val) (define (eval-program pgm) (match pgm (($prog seq) (top ((eval-commands seq) (empty-stack)))) )) ;; eval-commands: (-> ((listof command)) (-> (stack) stack)) (define (eval-commands seq) (match seq ((null) identity) ((cons com coms) (o (eval-commands coms) (eval-command com))) )) ;; eval-command: (-> (command) (-> (stack) stack)) (define (eval-command cmd) (match cmd ( ($int i) (push (int->den-val i)) ) ( ($seq s) (push (xform->den-val (eval-commands s))) ) ( ($pop) pop ) ( ($swap) (with-value (lambda (v1) (with-value (lambda (v2) (o (push v2) (push v1)))))) ) ( ($sel) (with-value (lambda (else) (with-value (lambda (then) (with-integer (lambda (test) (if (= test 0) (push else) (push then)))))))) ) ( ($exec) (with-transform identity) ) ( ($arithop op) (with-integer (lambda (i1) (with-integer (lambda (i2) (push (int->den-val (op i2 i1))))))) ) ( ($relop op) (with-integer (lambda (i1) (with-integer (lambda (i2) (push (int->den-val (if (op i2 i1) 1 0))))))) ) )) ;;;------------------------------------------------------------------------- ;;; Auxiliary Functions (define (empty-stack) '()) (define (push val) (lambda (stack) (cons val stack))) (define (with-value proc) (lambda (stack) (match stack ((null) (error "Empty stack")) ((cons v s) ((proc v) s))))) (define top (with-value (lambda (top) (lambda (rest) top)))) (define pop (with-value (lambda (top) (lambda (rest) rest)))) (define (with-integer proc) (with-value (lambda (v) (match v ((int->den-val i) (proc i)) (_ (error "Transform where integer expected")))))) (define (with-transform proc) (with-value (lambda (v) (match v ((xform->den-val t) (proc t)) (_ (error "Integer where transform expected")))))) (define (identity x) x) (define (o f g) ;; Function composition (lambda (x) (f (g x)))) ;;;--------------------------------------------------------------------------- ;;; Top-level (define (unparse-value value) (match value ((int->den-val i) (int->sexp i)) ((xform->den-val s) 'executable) )) (define pf-den-repl (make-repl eval-program 'pf-den> pf-program unparse-value))