#| -*- Mode:LISP; Fonts:(cptfontb); Base:10 -*- Pascal-macros.Lisp Useful macros, particulary Pascal-like iterative constructs. |# (DEFMACRO UNTIL (PRED &REST BODY) "(UNTIL pred { form1 form2 ... } ) => (DO (pred) (PROGN form1 form2 ...)) UNTIL loops repeatedly, evaluating the predicate 'pred' -- if the result is NIL, the body 'forms' are executed, and then back to the test, and so on. Normally the value returned is the last 'form' in the body. Because UNTIL is expanded into an equivalent DO form, (RETURN values...) may be used to force an exit and return values from the loop." `(DO ($UNTIL$) (,PRED $UNTIL$) (SETQ $UNTIL$ (PROGN . ,BODY)))) (DEFMACRO WHILE (PRED &REST BODY) "(WHILE pred { form1 form2 ... } ) => (DO ((NOT pred)) (PROGN form1 form2 ...)) WHILE loops repeatedly, evaluating the predicate 'pred' -- if the result is non-NIL, the body 'forms' are executed, and then back to the predicate, and so on. Normally the value returned is the last 'form' in the body. Because WHILE is expanded into an equivalent DO form, (RETURN values...) may be used to force an exit and return values from the loop." `(DO ($WHILE$) ((NOT ,PRED) $WHILE$) (SETQ $WHILE$ (PROGN . ,BODY)))) ;;; ;;; DO-FOR and DO-FOR-DOWNTO are CommonLisp versions of the ;;; Pascal forms, 'FOR ... TO' and 'DOWNTO', respectively. (DEFMACRO DO-FOR ((VAR LOWER UPPER RESULTFORM) &BODY BODY) "Iterate BODY with VAR bound to successive integers from LOWER to UPPER, inclusive. This is a Pascal-style FOR loop, based on the standard form DO. LOWER and UPPER are evaluated only once. When it is reached, RESULTFORM is evaluated and returned. RETURN and GO can be used inside the BODY." (IF (FIXNUMP UPPER) `(DO ((,VAR ,LOWER (1+ ,VAR))) ((> ,VAR ,UPPER) ,RESULTFORM) . ,BODY) (LET ((ITERATION-VAR (GENSYM))) `(DO ((,VAR ,LOWER (1+ ,VAR)) (,ITERATION-VAR ,UPPER)) ((> ,VAR ,ITERATION-VAR) ,RESULTFORM) . ,BODY)))) (DEFMACRO DO-FOR-DOWNTO ((VAR UPPER LOWER RESULTFORM) &BODY BODY) "Iterate BODY with VAR bound to successive integers from UPPER to LOWER, inclusive. This is a Pascal-style FOR loop, based on the standard form DO. UPPER and LOWER are evaluated only once. When it is reached, RESULTFORM is evaluated and returned. RETURN and GO can be used inside the BODY." (IF (FIXNUMP LOWER) `(DO ((,VAR ,UPPER (1- ,VAR))) ((< ,VAR ,LOWER) ,RESULTFORM) . ,BODY) (LET ((ITERATION-VAR (GENSYM))) `(DO ((,VAR ,UPPER (1- ,VAR)) (,ITERATION-VAR ,LOWER)) ((< ,VAR ,ITERATION-VAR) ,RESULTFORM) . ,BODY))))