PostFix PostFix is a stack-based mini-language that will be our first foray A PostFix Interpreter in Racket into the study of metalanguages = programs that manipulate programs. It’s not a real language, but a “toy” mini-language used for studying programming language semanCcs and implementaCon. It is inspired by real stack-based languages like PostScript, Forth, and HP calculators. CS251 Programming For the syntax and semanCcs of PostFix, see these notes: Languages hGp://cs.wellesley.edu/~cs251/notes/dcpl-introducCon.pdf Spring 2019, Lyn Turbak Here’s an example PostFix program Department of Computer Science Wellesley College (postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec) PosMix 2 PostFix command semanCcs (except exec) PostFix Syntax number of expected Stack Before Command Stack After commands arguments integer N ( N …) (…) ( v1 …) pop (…) (postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec) ( v1 v2 …) ( v2 v1 …) swap ( v1 v2 …) ( N …) where N is v2 – v1 sub executable executable (other arithops similar) sequence sequence ( v1 v2 …) ( N …) where N is 1 if v2 < v1 command lt command (other relops similar) and N is 0 otherwise A PostFix command C is one of: ( i v1 … vk ) ( vi v1 … vk ) if 1 ≤ i ≤ k nget and vi is an integer • An integer • One of pop , swap , nget , sel , exec , ( velse vthen vtest …) ( vthen …) if vtest ⧧ 0 sel ( velse …) if vtest = 0 add , mul , sub , div , rem , ; arithops lt , eq , gt ; relops • An executable sequence of the form (C1 … Cn) PosMix 3 PosMix 4
PostFix command semanCcs: exec Your turn: PostFix program example Stack Before Commands Before Commands After Consider this posMix program: (( C1 … Cn ) rest-of-stack ) ( exec rest-of-cmds ) ( C1 … Cn rest-of-cmds ) '(postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec) What is the result of running it on these arguments? • '(3 5) • '(3 -5) PosMix 5 PosMix 6 PostFix Syntax AbstracCons in Racket TesCng membership with memq / member ( define (postfix-program? sexp) > (member 'c '(a b c d e)) ( and (list? sexp) '(c d e) ; returns sublist beginning with found item (>= (length sexp) 2) (eq? (first sexp) 'postfix) > (member 'x '(a b c d e)) (integer? (second sexp)) #f ; returns #f if item not found (postfix-command-sequence? (rest (rest sexp))))) ( define (postfix-command-sequence? sexp) > (define L '(a b)) ( and (list? sexp) (forall? postfix-command? sexp))) > (memq L (list '(c d) L '(e f))) '((a b) (e f)) ( define (postfix-command? sexp) ( or (integer? sexp) > (memq L (list '(c d) '(a b) '(e f))) (memq sexp '(pop swap nget sel exec #f ; not found because new list '(a b) not eq? to L add mul sub div rem ; arithops lt eq gt)) ; relops ;; member is to memq what equal? is to eq? (postfix-command-sequence? sexp))) > (member L (list '(c d) '(a b) '(e f))) ( define (postfix-numargs pgm) (second pgm)) '((a b) (e f)) ( define (postfix-commands pgm) (rest (rest pgm))) PosMix 7 PosMix 8
postfix-config-tail-starter.rkt MulCple versions of the PostFix interpreter ;; Run the given PostFix program on argument values, We will study three different approaches to implemenCng a PostFix interpreter. ;; which form the initial stack ( define (postfix-run pgm args) 1. postfix-config-tail : uses tail recursion to perform iteraCve (postfix-exec-config-tail (postfix-commands pgm) args)) execuCon of PostFix state configuraCons = duples (2-element list) of commands and stack. ;; Use tail recursion to loop over a configuration state consisting ;; of (1) list of commands and (2) list of stack values 2. postfix-config-iterate : uses tail recursion to perform iteraCve ( define (postfix-exec-config-tail cmds stk) execuCon of PostFix state configuraCons. ( cond ((null? cmds) 'flesh-this-out ) ; Return top of stack at end ((eq? (first cmds) 'exec) 3. postfix-transform : uses foldl on command sequence to transform ; Continue iteration with next configuration 'flesh-this-out ) iniCal stack to final stack. Treats exec as a stack transformer. ; Continue iteration with next configuration There are two flavors of each of these three interpreters: ( else (postfix-exec-config-tail (rest cmds) o simple : limited error handling, straighMorward arithops/relops, no tracing (postfix-exec-command (first cmds) stk))))) o Fancy: ;; Execute a non-exec command on a stack to yield a new stack. ;; So each command can be viewed as a "stack transformer" • appropriate handling of all error cases; ( define (postfix-exec-command cmd stk) …) • the ability to trace step-by-step execuCon; • a general, extensible way to handle arithops and relops PosMix 9 PosMix 10 postfix-exec-command Skeleton postfix-exec-config-tail Fleshed Out ;; Initially simplify things by ignoring errors ( define (postfix-exec-command cmd stk) ;; Use tail recursion to loop over a configuration state consisting ( cond ((integer? cmd) 'flesh-this-out ) ;; of (1) list of commands and (2) list of stack values ((eq? cmd 'pop) 'flesh-this-out ) ( define (postfix-exec-config-tail cmds stk) ( cond ((null? cmds) (first stk) ) ; Return top of stack at end ((eq? cmd 'swap) 'flesh-this-out ) ((eq? (first cmds) 'exec) ((eq? cmd 'sub) 'flesh-this-out ) ; Continue iteration with next configuration ; other arithops similar (postfix-exec-config-tail (append (first stk) (rest cmds)) ((eq? cmd 'lt) 'flesh-this-out ) (rest stk))) ; other relops similar ; Continue iteration with next configuration ((eq? cmd 'sel) 'flesh-this-out ) ( else (postfix-exec-config-tail ((postfix-command-sequence? cmd) 'flesh-this-out ) (rest cmds) (else (error "unrecognized command" cmd)))) (postfix-exec-command (first cmds) stk))))) PosMix 11 PosMix 12
postfix-exec-command Fleshed Out Side Effects and Sequencing: printf and begin ;; Initially simplify things by ignoring errors > (begin (printf "~a + ~a is ~a\n" 1 2 (+ 1 2)) ( define (postfix-exec-command cmd stk) ( cond ((integer? cmd) (cons cmd stk) ) (printf "~a * ~a is ~a\n" 3 4 (* 3 4))) ((eq? cmd 'pop) (rest stk) ) 1 + 2 is 3 ((eq? cmd 'swap) 3 * 4 is 12 (cons (second stk) (cons (first stk) (rest (rest stk)))) ) ((eq? cmd 'sub) (define (print-and-return val) (cons (- (second stk) (first stk)) (rest (rest stk))) ) (begin (printf "~a\n" val) val)) ; other arithops similar ((eq? cmd 'lt) > (* (print-and-return 3) (cons (if (< (second stk) (first stk)) 1 0) (rest (rest stk))) ) (print-and-return (+ (print-and-return 4) ; other relops similar (print-and-return 5)))) ((eq? cmd 'nget) 3 ; printed (cons (list-ref stk (first stk)) (rest stk)) ) 4 ; printed ((eq? cmd 'sel) (cons (if (= (third stk) 0) (first stk) (second stk)) 5 ; printed (rest (rest (rest stk)))) ) 9 ; printed ((postfix-command-sequence? cmd) (cons cmd stk) ) 27 ; returned ( else (error "unrecognized command" cmd))) ) PosMix 13 PosMix 14 begin is just syntacCc sugar! postfix-exec-config-tail with tracing (begin e) desugars to e ;; Set this to #t to turn on printing of intermediate stacks; ;; #f to turn it off (begin e1 e2 …) ( define display-steps? #t) desugars to (let ((id1 e1)) ; id1 is fresh ( define (postfix-exec-config-tail cmds stk) (begin e2 …)) (begin (if display-steps? ; Only print intermediate stack ;if display-steps? is #t (printf "Commands: ~a\n Stack: ~a\n" cmds stk) 'do-nothing) ( cond …))) PosMix 15 PosMix 16
Recommend
More recommend