; ; Following are a few macro definitions which implement constructs in other ; LISPs. They are not intended to be fully compatible to COMMON LISP or any ; other dialect, but are included as examples of how other constructs may ; be implemented, and how Scheme itself can be extended. Note also that the ; examples lack sufficient error checking - feel free to modify, extend, ; and add to any or all of macros for your own purposes. ; ; ; CATCH/THROW - A catch form evaluates some subforms in such a way that, if ; a throw is executed during such evaluation, the evaluation is aborted at ; that point and the catch form returns a value specified by the throw. The ; catch/throw mechanism works even if the throw form is not within the lexical ; scope of the catch. ; ; The tags used for this implementation of catch/throw can be either symbols, ; strings, or numbers. Note the use of fluids and continuations in this ; implementation. ; (macro catch ;(catch tag expression) (lambda (e) (let ((tag (cadr e)) (form (caddr e))) (cond ((string? tag) (set! tag (string->symbol tag))) ((number? tag) (set! tag (implode (explode tag)))) ((and (pair? tag) (eq? (car tag) 'quote)) (set! tag (cadr tag))) ) `(call/cc (fluid-lambda (,tag) ,form))))) (macro throw ;(throw tag value) (lambda (e) (let ((tag (cadr e)) (value (caddr e))) (cond ((string? tag) (set! tag (string->symbol tag))) ((number? tag) (set! tag (implode (explode tag)))) ((and (pair? tag) (eq? (car tag) 'quote)) (set! tag (cadr tag))) ) `(if (and (fluid-bound? ,tag) (continuation? (fluid ,tag))) ((fluid ,tag) ,value) (error "Bad tag on throw" ,tag))))) ; ; PROG - The prog construct allows one to write in a statement-oriented style ; (ala FORTRAN), using go statements that can refer to tags in the body of the ; prog. Modern LISP programming tends to use prog infrequently, however the ; following exercise is a good example of how Scheme may be extended to take ; on characteristics of other LISPs. ; (macro go (lambda (form) (if (integer? (cadr form)) `(implode (explode ,(cadr form))) ;else (cdr form)))) (macro prog (lambda (form) (letrec ((tagstart '()) (buildvars (lambda (proglist varlist) (if (null? proglist) varlist ;else (buildvars (cdr proglist) (if (pair? (car proglist)) `(,(car proglist) ,@varlist) ;else `( (,(car proglist) '()) ,@varlist)))))) (buildtags (lambda (tbodys) (if (null? tagstart) tbodys ;else (buildtags `( ( ,(car tagstart) (lambda () ,@(getbody (cdr tagstart) '()))) ,@tbodys))))) (getbody (lambda (exprs body) (cond ((null? exprs) (set! tagstart '()) (reverse! `((return ()) ,@body))) ((or (symbol? (car exprs)) (integer? (car exprs))) (set! tagstart (if (integer? (car exprs)) `(,(implode (explode (car exprs))) ,@(cdr exprs)) ;else exprs)) (reverse! `( (,(car tagstart)) ,@body))) (else (getbody (cdr exprs) `(,(car exprs) ,@body))))))) (let ((letrec_body (getbody (cddr form) '())) (letrec_vars (reverse! (buildtags (buildvars (cadr form) '()))))) `(call/cc (lambda (return) (letrec ,letrec_vars ,@letrec_body)))) )))