;;; Consider the following grammar for a subset of Scheme: ;;; ExpressionList ~ { Expression } . ;;; Expression : Ident | Application | ;;; IfExpression | LambdaExpression | Assignment. ;;; IfExpression = "(if" Expression Expression ;;; [ Expression] ")". ;;; Application = "(" Expression ExpressionList ")". ;;; LambdaExpression = "(lambda" IdentList ;;; ExpressionList ")". ;;; IdentList ~ "(" {Ident} ")". ;;; Assignment = "(set" Ident Expression ")". ;;; ExpressionList ;;; An identifier occurs free if it occurs free ;;; in any element of the ExpressionList. (defmethod (ExpressionList :free-all) (id) (loop for exp in child collect (send exp ':free id))) (defmethod (ExpressionList :free) (id) (apply 'or (loop for exp in child collect (send exp ':free id)))) ;;; Ident ;;; An identifier occurs free when it is the same ;;; as the Ident under consideration. (defmethod (Ident :free) (id) (equal val id)) ;;; IfExpression ;;; An identifier occurs free if it occurs free ;;; in any component {test, then or else}. (defmethod (IfExpression :free) (id) (or (send testExp ':free id) (send thenExp ':free id) (if (null elseExp) nil (send elseExp ':free id)))) ;;; use explicit test for a ;;; (null elseExp) to return ;;; NIL from an omitted ;;; {optional} elseExp clause ;;; Assignment ;;; An identifier occurs free when it occurs free ;;; in either the Ident or the Expression component. (defmethod (Assignment :free) (id) (or (send Ident ':free id) (send Expression ':free id))) ;;; LambdaExpression ;;; An identifier occurs free when it does NOT appear among the formals ;;; {is not a member of the Identlist} and occurs free in the body. ;;; An auxiliary function which preserves "object-oriented" style (defmethod (Identlist :member) (id) (member id (loop for child in (send formals ':child) collect (send child ':val)))) ;;; The actual :free method for LambdaExpression (defmethod (LambdaExpression :free) (id) (and (not (send formals ':member id)) (send body ':free id))) ;;; Application ;;; An identifier occurs free when it occurs free ;;; in either the function or the actuals. (defmethod (Application :free) (id) (or (send function ':free id) (send actuals ':free id)))