;;-------------------------------------------------------------------------- ;; Solution for hw2, problem 1. ;; ;; This solution is suggested by David Christian Lutterkort. ;;-------------------------------------------------------------------------- ;;-------------------------------------------------------------------------- ;; README written by David Christian Lutterkort ;; ;; The lexical-address function scans through an expression, exploiting ;; the recursive definition of the syntax for expressions; the real work ;; is done by a function (lex-addr EXP CTXT) which gets the expression ;; and a variable context as parameters. The context is a list of ;; lists. Every time we run across a lambda - expression, the variable ;; list gets tacked onto the front of the context; if we want to replace ;; a varref by the lex. addr. of that varref, we walk through the CTXT = ;; (c_1 c_2 ... c_n) list, searching the varref in each of its element lists ;; c_i. Then the depth of a symbol is given by the index i of the first ;; c_i that contains the varref, and its position by the list-index of ;; the varref in that c_i. ;; ;; There's only one problem left: how do we deal with free variables ? We ;; have to make sure that each free variable gets a unique lex. addr., ;; i.e. we have to assign position numbers to the free variables. ;; My solution to this was to write a function (free-vars EXP) which ;; scans an expression EXP (recursively, following the syntax of the ;; simple language) and records any variable occurences that are not ;; covered by any preceding lambda statement. It returns a list of the ;; free symbols (containing each free symbol once); this list is passed ;; to lex-addr as the initial context. This has the same effect as ;; enclosing the EXP for lex-addr by a (lambda (free_vars) EXP). ;;; ;;-------------------------------------------------------------------------- ;; SOURCE CODE ;; ;;; ;;; IMPORTANT: before you can run these routines, you have to define ;;; the functions list-index and atom? by loading some appropriate ;;; files. list-index was on homework 1, atom? is provided by comlist.scm ;;; ;;; (free-vars EXP) ;;; ;;; scans an EXP of the form ;;; ::= ;;; | (if ) ;;; | (lambda (*) ) ;;; | (+) ;;; and returns a list of the free variables in that expression. ;;; The list won't contain any repetitions of the same symbol. (define free-vars (lambda (exp) (letrec ((fv-int (lambda (exp context free) (cond ((null? exp) free) ((atom? exp) ;; EXP must be a varref (if (eq? (list-index exp context) -1) ; EXP is unbound var (if (eq? (list-index exp free) -1) (append free (list exp)) ;; EXP not in free yet free) free)) ((eq? (car exp) 'lambda) ;; EXP is lambda expression (let ((l (cadr exp)) (e (caddr exp))) (fv-int e (append context l) free))) ((eq? (car exp) 'if) ;; EXP is if clause (let ((test (cadr exp)) (then (caddr exp)) (other (cadddr exp))) (fv-int other context (fv-int then context (fv-int test context free))))) (else ;; EXP is of the form (+) (fv-int (cdr exp) context (fv-int (car exp) context free))))))) (fv-int exp '() '())))) ;;; ;;; ;;; (lexical-address EXP) ;;; ;;; replace variable names by their lexical address in expressions ;;; of the above form ;;; uses: list-index, atom? (define lexical-address (lambda (exp) (letrec ((varref ;;; (varref VARREF CONTEXT) finds the lexical address ;;; in the context list CONTEXT and returns ;;; (v : d p) where d and p are the lexical address of ;;; v ;;; USES: list-index from hw1 (lambda (v d context) (if (null? context) ;;; v is free reference ;;; that shouldn't happen (error "encountered free variable") (let ((p (list-index v (car context)))) (if (eq? p -1) (varref v (+ d 1) (cdr context)) (list v ': d p)))))) (lex-addr ;;; (lex-addr EXP CTXT) does all the work for ;;; lexical-address. EXP is the expression in which lexical ;;; addresses are to be inserted. ;;; CTXT is a list of all the variable contexts ;;; that were encountered so far. ;;; each (lambda l e) causes CTXT to be replaced by ;;; (cons l CTXT) in the processing of e (lambda (exp ctxt) (cond ((atom? exp) (varref exp 0 ctxt)) ;; EXP is varref ((eq? (car exp) 'lambda) ;; EXP is lambda expression (let ((l (cadr exp)) (e (caddr exp))) (list 'lambda l (lex-addr e (cons l ctxt))))) ((eq? (car exp) 'if) ;; EXP is if clause (let ((test (lex-addr (cadr exp) ctxt)) (then (lex-addr (caddr exp) ctxt)) (other (lex-addr (cadddr exp) ctxt))) (list 'if test then other))) (else ;; EXP must be of the form (+) (let ((rescar (lex-addr (car exp) ctxt))) (if (null? (cdr exp)) (list rescar) (cons rescar (lex-addr (cdr exp) ctxt))))))))) (lex-addr exp (cons (free-vars exp) '()))))) ;;-------------------------------------------------------------------------- ;; Solution for hw2, problem 2. ;; ;; This solution is suggested by Lizhen Chen ;;-------------------------------------------------------------------------- ;;-------------------------------------------------------------------------- ;; SOURCE CODES : translator ;; (define process (lambda (lst) (if (null? lst) '() (let ((item (car lst)) (next (cdr lst))) (if (list? item) (append (process item) (process next)) (case item ((+) (append (process next) '(add))) ((-) (append (process next) '(sub))) ((*) (append (process next) '(mul))) ((/) (append (process next) '(div))) (else (if (number? item) (append (cons 'push (list item)) (process next)) (error 'processor "unknown item ~s" item))))))))) (define translator (lambda (lst) (append (process lst) '(halt)))) ;;-------------------------------------------------------------------------- ;; SOURCE CODES : modified stack machine ;; ;;; Grammar for action representation ;;; a ::= (halt) | (incr . a) | (push v . a) ;;; | (add . a) | (read . a) | (zero? a1 . a2) (define apply-action (lambda (action stack) (let ((instruction (car action))) (case instruction ((halt) (car stack)) ((incr) (let ((next-action (cdr action))) (apply-action next-action (cons (+ (car stack) 1) (cdr stack))))) ((push) (let ((v (cadr action)) (next-action (cddr action))) (apply-action next-action (cons v stack)))) ((add) (let ((next-action (cdr action))) (apply-action next-action (cons (+ (car stack) (cadr stack)) (cddr stack))))) ((sub) (let ((next-action (cdr action))) (apply-action next-action (cons (- (cadr stack) (car stack)) (cddr stack))))) ((mul) (let ((next-action (cdr action))) (apply-action next-action (cons (* (car stack) (cadr stack)) (cddr stack))))) ((div) (let ((next-action (cdr action))) (apply-action next-action (cons (/ (cadr stack) (car stack)) (cddr stack))))) ((read) (let ((v (prompt-read "machine>")) (next-action (cdr action))) (apply-action next-action (cons v stack)))) ((zero?) (let ((true-action (cadr action)) (false-action (cddr action))) (if (zero? (car stack)) (apply-action true-action stack) (apply-action false-action stack)))) (else (error 'apply-action "unknown instruction ~s" instruction)))))) (define start (lambda (action) (apply-action action '()))) (define prompt-read (lambda (prompt) (display prompt) (display " ") (read))) ;;-------------------------------------------------------------------------- ;; Solution for hw2, problem 3. ;; ;; Suggested by ;;-------------------------------------------------------------------------- ;;-------------------------------------------------------------------------- ;; README written by Nitin Garg ;; ;; Two kind of repetitive loops have been implemented: repeat and while. ;; ;; repeat has the following format: repeat n ;; It repeats the stack-machine commands in the list 'n' times. It does ;; that by modifying the action stack to add n times. ;; Therefore, ;; (push 3 repeat 4 (push 4 add) halt) ;; looks like ;; (push 3 push 4 add push 4 add push 4 add push 4 add halt) ;; ;; while has the following format: while (condition) ;; The condition is tested against the top of the stack to see if it is ;; satisfied. If not the list is repeated until the condition is satisfied. ;; (condition) is of the form (=? 75) or (>? 10) etc. It is tested against ;; the top of the stack using eval command. while has been implemented using ;; letrec and the recursive function called is loop. Both apply-action and loop ;; are called recursively to get the desired output. ;; ;;-------------------------------------------------------------------------- ;; SOURCE CODES ;; (define apply-action (lambda (action stack) (if (null? action) stack (let ((instruction (car action))) (case instruction ((halt) (car stack)) ((incr) (let ((next-action (cdr action))) (apply-action next-action (cons (+ (car stack) 1) (cdr stack))))) ((push) (let ((v (cadr action)) (next-action (cddr action))) (apply-action next-action (cons v stack)))) ((add) (let ((next-action (cdr action))) (apply-action next-action (cons (+ (car stack) (cadr stack)) (cddr stack))))) ((sub) (let ((next-action (cdr action))) (apply-action next-action (cons (- (cadr stack) (car stack)) (cddr stack))))) ((mult) (let ((next-action (cdr action))) (apply-action next-action (cons (* (car stack) (cadr stack)) (cddr stack))))) ((div) (let ((next-action (cdr action))) (apply-action next-action (cons (/ (cadr stack) (car stack)) (cddr stack))))) ;; ;; repeat command ;; ((repeat) (letrec ((n (cadr action)) (rest-action (cdddr action)) (repeat-action (caddr action)) (loop (lambda (n) (if (eqv? n 0) '() (append repeat-action (loop (- n 1))))))) (apply-action (append (loop n) rest-action) stack))) ;; ;; while command ;; ((while) (letrec ((condition (cadr action)) (repeat-action (caddr action)) (rest-action (cdddr action)) (loop (lambda (stack) (if (eval (append condition (list (car stack)))) stack (loop (apply-action repeat-action stack)))))) (apply-action rest-action (loop stack)))) ((read) (let ((v (prompt-read "machine>")) (next-action (cdr action))) (apply-action next-action (cons v stack)))) ((zero?) (let ((true-action (cadr action)) (false-action (cddr action))) (if (zero? (car stack)) (apply-action true-action stack) (apply-action false-action stack)))) (else (error 'apply-action "unknown instruction ~s" instruction))))))) (define start (lambda (action) (apply-action action '()))) (define prompt-read (lambda (prompt) (display prompt) (display " ") (read)))