darrelj@sdcrdcf.UUCP (Darrel VanBuer) (01/08/88)
Here is limited documentation on, and code for a commonlisp iteration macro which we developed for compatibility with an Interlisp code port. Darrel J. Van Buer, PhD; unisys; 2400 Colorado Ave; Santa Monica, CA 90406 (213)829-7511 x5449 KI6VY darrel@CAM.UNISYS.COM or ...{allegra,burdvax,cbosgd,hplabs,ihnp4}!sdcrdcf!darrelj Extracted from: A Common Lisp Translation Scheme for the Core of the Flexible Deductive Engine by Richard Fritzson, Donald P. McKay and Darrel J. Van Buer Technical Memo Number 44' Logic-Based Systems Paoli Research Center and West Coast Research Center Unisys Corporation December, 1986 Revised March, 1987 Unisys - Paoli Research Center P.O. Box 517 Paoli, PA 19301 3. The Support Functions A few Interlisp functions were not translated, but were instead defined in the Common Lisp environment so that they could be ported with little or no change. The primary reason for doing this was that there were no comparable functions in Common Lisp, and the translations were difficult to read. The most important example of these is the Interlisp iteration constructs. hese allow the Interlisp programmer to specify both simple and complex iterative statements in a perspicuous manner. If these were translated into Common Lisp, they would result in a divergent collection of MAP functions, DO forms, PROG forms and GOTO expressions, nearly all of which are far more difficult to read than the original expressions. A second reason for redefining these expressions is that this allows their continued use in Common Lisp programming. The Interlisp iterative statements have proven themselves to be invaluable in LISP programming; it would be a shame to give them up now in a move forward to Common Lisp. 3.1 The Unisys Common Lisp FOR Macro The Unisys Common Lisp FOR macro is modeled after the Interlisp iterative statement and a significant subset of the Interlisp version's functionality with only a small amount of incompatability. For this reason, it is not described in detail here. The reader is referred to Section 9.8 of the Interlisp Reference Manual[1] for a detailed description of its use and capabilities. This section describes the differences between the Unisys Common Lisp version and the XEROX Interlisp version. The internal documentation of the FOR macro is in the file that contains the code. Since it may still undergo further change, that is the best place to look for up to date information about how to extend or modify it. 3.1.1 Differences between the Interlisp and Unisys iteration operators In the Unisys FOR macro, 1) The car of the form must be FOR. The other operators work inside the form, but FOR is the Common Lisp macro that triggers the translation. It is perfectly acceptable to write e.g. (FOR WHILE (< I 0) ... 2) DO not use FROM without TO. The appropriate defaults will not be provided. FROM and TO function as a unit and must be provided together. 3) WHEN and UNLESS completely skip the the rest of the iteration including the other generators that follow. In Interlisp, all of the generators are evaluated, even when WHEN (and UNLESS) fail (or succeed). 4) BIND uses a PROG syntax instead of the Interlisp assignment syntax. That is, you write (FOR ... BIND (A B (C 0) D) ... instead of (FOR ... BIND A B (C _ 0) D ... 5) None of the OLD froms (FOR OLD, IN OLD , ON OLD) are supported. 6) INSIDE and OUTOF are not supported. 7) DECLARE, DECLARE: and ORIGINAL are also not supported. 8) The Unisys iteration package also supports MAX, MIN, and UNION operators. 3.1.2 List of operators that are supported in the Unisys FOR macro DO FOR WHEN COLLECT FOR var UNLESS JOIN FOR (varlist) WHILE SUM BIND (varlist) UNTIL COUNT IN REPEATWHILE ALWAYS ON REPEATUNTIL NEVER FROM FIRST THEREIS TO FINALLY LARGEST BY EACHTIME SMALLEST AS MAX INSIDE MIN UNION ------------------------------------------------------------------------ ;;; -*- Mode: LISP; Syntax: Common-lisp; Package: USER; Base: 10 -*- ;;; File converted 7-Jan-88 14:14:25 from source FORMACRO ;;; Original source {DSK}<XAVIER>FORMACRO.;10 created 22-Sep-87 13:17:50 (EXPORT 'FOR) (DEFUN EVLIST (L) (NREVERSE (MAPCAR #'EVAL L))) (DEFMACRO FOR (&BODY X) (SDC-FOR X)) (DEFUN FROMTOTEST (IV FROM TO BY BYVAR TOVAR) (LET ((BYVAL (SYMBOL-VALUE BY))) (IF (CONSTANTP BYVAL) (IF (AND (NUMBERP FROM) (NUMBERP TO) (< TO FROM) (= BYVAL 1)) (PROGN ; BY was probably a default +1 so ; silently force to -1 before the ; incrementer gets expanded (SET BY -1) `(IF (< ,IV ,TO) (GO $$OUT))) `(IF (,(IF (MINUSP BYVAL) '< '>) ,IV ,(IF (CONSTANTP TO) TO TOVAR)) (GO $$OUT))) `(IF (AND ,BYVAR (OR (= 0 ,BYVAR) (IF (MINUSP ,BYVAR) (< ,IV ,(IF (CONSTANTP TO) TO TOVAR)) (> ,IV ,(IF (CONSTANTP TO) TO TOVAR))))) (GO $$OUT))))) (DEFUN ISOPRP (X) (IF (SYMBOLP X) (GET (INTERN (STRING-UPCASE X) "USER") 'FORWORD))) (DEFUN SDC-FOR (X) (DECLARE (SPECIAL X)) (PROG (VARLIST IV IV1 IOV INITS EACHS PRETESTS BODYS POSTTESTS UPDATES FINALS OP (INCCNT 0) $$INC0 $$INC1 $$INC2 $$INC3 $$INC4 $$INC5 $$INC6 $$INCVAR0 $$INCVAR1 $$INCVAR2 $$INCVAR3 $$INCVAR4 $$INCVAR5 $$INCVAR6 $$INIT0 $$INIT1 $$INIT2 $$INIT3 $$INIT4 $$INIT5 $$INIT6 $$END0 $$END1 $$END2 $$END3 $$END4 $$END5 $$END6) (DECLARE (SPECIAL VARLIST IV IV1 IOV INITS EACHS PRETESTS BODYS POSTTESTS UPDATES FINALS INCCNT $$INC0 $$INC1 $$INC2 $$INC3 $$INC4 $$INC5 $$INC6 $$INCVAR0 $$INCVAR1 $$INCVAR2 $$INCVAR3 $$INCVAR4 $$INCVAR5 $$INCVAR6 $$INIT0 $$INIT1 $$INIT2 $$INIT3 $$INIT4 $$INIT5 $$INIT6 $$END0 $$END1 $$END2 $$END3 $$END4 $$END5 $$END6)) (PUSH '$$VAL VARLIST) (COND ((CONSP (CAR X)) (COND ((CONSP (CAAR X)) ; (FOR ((VAR "...") "...") "...") (SETQ IOV (SETQ IV1 (SETQ IV (CAAAR X))))) (T ; (FOR (VAR "...") "...") (SETQ IV1 (SETQ IV (CAAR X))))) (SETQ VARLIST (NCONC (REVERSE (CAR X)) VARLIST)) (SETQ X (CDR X))) ((AND (SYMBOLP (CAR X)) (NOT (ISOPRP (CAR X)))) ; (FOR VAR "...") (SETQ IOV (SETQ IV1 (SETQ IV (CAR X)))) (PUSH (LIST (CAR X) 1) VARLIST) (SETQ X (CDR X))) (T ; E.G. (FOR DO "...") (SETQ IOV (SETQ IV1 (SETQ IV '$$ITER))) (PUSH '($$ITER 1) VARLIST))) TOP (IF (NULL X) (RETURN `(PROG ,(NREVERSE VARLIST) ,@(EVLIST INITS) $$LP ,@(EVLIST EACHS) ,@(EVLIST PRETESTS) ,@(EVLIST BODYS) $$ITERATE ,@(EVLIST POSTTESTS) ,@(EVLIST UPDATES) (GO $$LP) $$OUT ,@(EVLIST FINALS) (RETURN $$VAL)))) (COND ((SETQ OP (ISOPRP (CAR X))) (EVAL OP) (COND ((AND (CDDR X) (NOT (ISOPRP (CADDR X))) (NOT (EQL 'DO (INTERN (STRING-UPCASE (CAR X)) "USER")))) (PRINT (LIST "Warning, no implicit PROGN in Unisys FOR macro:" X) T))) (SETQ X (CDDR X))) (T (PUSH (LIST 'QUOTE (CAR X)) BODYS) (SETQ X (CDR X)))) (GO TOP))) (DEFMACRO XCL-USER::SELECTC (XCL-USER::SELECTOR &REST XCL-USER::CASES) `(CASE ,XCL-USER::SELECTOR ,@(FOR CASE XCL-USER::ON XCL-USER::CASES XCL-USER::WHILE (CDR CASE) XCL-USER::COLLECT (CONS (EVAL (CAAR CASE)) (CDAR CASE))) (OTHERWISE ,(CAR (LAST XCL-USER::CASES))))) (DEFMACRO TESTFOR (L . BODY) (PROG (X) (SETQ X (SDC-FOR (CONS L BODY))) (TERPRI) (WRITE X :PRETTY T) (TERPRI) (RETURN X))) (SETF (GET 'ALWAYS 'FORWORD) '(PROGN (PUSH ''(SETQ $$VAL T) INITS) (PUSH (LIST 'QUOTE `(COND ((NULL ,(CADR X)) (SETQ $$VAL NIL) (GO $$OUT)))) BODYS))) (SETF (GET 'AS 'FORWORD) '(PROGN (INCF INCCNT) (SETQ IOV (SETQ IV (CADR X))) (OR IV1 (SETQ IV1 IV)) (PUSH (LIST IV 1) VARLIST))) (SETF (GET 'BIND 'FORWORD) '(IF (CONSP (CADR X)) (SETQ VARLIST (APPEND (REVERSE (CADR X)) VARLIST)) (PUSH (CADR X) VARLIST))) (SETF (GET 'BY 'FORWORD) '(LET ((INCAMT (INTERN (CONCATENATE 'STRING "$$INC" (PRINC-TO-STRING INCCNT)) "USER"))) (COND ((NUMBERP (CADR X)) (SET INCAMT (CADR X))) (T (SET INCAMT (SUBST IOV IV (CADR X))) (LET ((BYVAR (GENSYM))) (PUSH BYVAR VARLIST) (SET (INTERN (CONCATENATE 'STRING "$$INCVAR" (PRINC-TO-STRING INCCNT)) "USER") BYVAR)))))) (SETF (GET 'COLLECT 'FORWORD) '(PROGN (PUSH (LIST 'QUOTE `(SETQ $$VAL (CONS ,(CADR X) $$VAL))) BODYS) (PUSH ''(SETQ $$VAL (NREVERSE $$VAL)) FINALS))) (SETF (GET 'COUNT 'FORWORD) '(PROGN (PUSH ''(SETQ $$VAL 0) INITS) (PUSH (LIST 'QUOTE `(IF ,(CADR X) (SETQ $$VAL (1+ $$VAL)))) BODYS))) (SETF (GET 'DO 'FORWORD) '(IF (NULL (ISOPRP (CADR X))) (PUSH (LIST 'QUOTE (CADR X)) BODYS) (SETQ X (CONS 'X X)))) (SETF (GET 'EACHTIME 'FORWORD) '(PUSH (LIST 'QUOTE (CADR X)) EACHS)) (SETF (GET 'FINALLY 'FORWORD) '(PUSH (LIST 'QUOTE (CADR X)) FINALS)) (SETF (GET 'FIRST 'FORWORD) '(PUSH (LIST 'QUOTE (CADR X)) INITS)) (SETF (GET 'FROM 'FORWORD) '(LET ((INCREM (INTERN (CONCATENATE 'STRING "$$INC" (PRINC-TO-STRING INCCNT)) "USER"))) (IF (EQL IV (CADR (CADAR INITS))) (RPLACA (CDDR (CADAR INITS)) (CADR X)) (PUSH `'(SETQ ,IV ,(CADR X)) INITS)) (SET (INTERN (CONCATENATE 'STRING "$$INIT" (PRINC-TO-STRING INCCNT)) "USER") (CADR X)) (OR (SYMBOL-VALUE INCREM) (SET INCREM 1)) (OR (EQL IV (CADR (CADDAR UPDATES))) (PUSH `(LIST 'INCF ',IV (IF (CONSTANTP ,INCREM) ,INCREM (LIST 'SETQ ,(INTERN (CONCATENATE 'STRING "$$INCVAR" (PRINC-TO-STRING INCCNT)) "USER") ,INCREM))) UPDATES)))) (SETF (GET 'IN 'FORWORD) '(PROG (INCEXPR) (SETQ IOV (GENSYM)) (SETQ INCEXPR (INTERN (CONCATENATE 'STRING "$$INC" (PRINC-TO-STRING INCCNT)) "USER")) (SET INCEXPR (LIST 'CDR IOV)) (PUSH (LIST IOV (CADR X)) VARLIST) (PUSH (LIST 'QUOTE `(IF (NOT ,IOV) (GO $$OUT) (SETQ ,IV (CAR ,IOV)))) EACHS) (PUSH `(LIST 'SETQ ,(LIST 'QUOTE IOV) ,INCEXPR) UPDATES))) (SETF (GET 'INSIDE 'FORWORD) '(PROGN (SETQ IOV (GENSYM)) (PUSH (LIST IOV (CADR X)) VARLIST) (PUSH (LIST 'QUOTE `(COND ((NULL ,IOV) (GO $$OUT)) ((NOT (CONSP ,IOV)) (SETQ ,IV ,IOV) (SETQ ,IOV NIL)) (T (SETQ ,IV (CAR ,IOV)) (SETQ ,IOV (CDR ,IOV))))) EACHS))) (SETF (GET 'JOIN 'FORWORD) '(PROGN (PUSH (LIST 'QUOTE `(SETQ $$VAL (NCONC (NREVERSE ,(CADR X)) $$VAL))) BODYS) (PUSH ''(SETQ $$VAL (NREVERSE $$VAL)) FINALS))) (SETF (GET 'LARGEST 'FORWORD) '(PROGN (PUSH '$$EXTREME VARLIST) (PUSH (LIST 'QUOTE `(COND ((OR (NULL $$EXTREME) (> ,(CADR X) $$EXTREME)) (SETQ $$EXTREME ,(CADR X)) (SETQ $$VAL ,IV)))) BODYS))) (SETF (GET 'MAX 'FORWORD) '(PUSH (LIST 'QUOTE `(IF (NULL $$VAL) (SETQ $$VAL ,(CADR X)) (SETQ $$VAL (MAX $$VAL ,(CADR X))))) BODYS)) (SETF (GET 'MIN 'FORWORD) '(PUSH (LIST 'QUOTE `(IF (NULL $$VAL) (SETQ $$VAL ,(CADR X)) (SETQ $$VAL (MIN $$VAL ,(CADR X))))) BODYS)) (SETF (GET 'NEVER 'FORWORD) '(PROGN (PUSH ''(SETQ $$VAL T) INITS) (PUSH (LIST 'QUOTE `(COND (,(CADR X) (SETQ $$VAL NIL) (GO $$OUT)))) BODYS))) (SETF (GET 'ON 'FORWORD) '(PROG (INCEXPR) (SETQ INCEXPR (INTERN (CONCATENATE 'STRING "$$INC" (PRINC-TO-STRING (INCF INCCNT))) "USER")) (SET INCEXPR (LIST 'CDR IOV)) (COND ((EQL IV (CAAR VARLIST)) (RPLACA (CDAR VARLIST) (CADR X))) (T (PUSH (LIST 'QUOTE `(SETQ ,IV ,(CADR X))) INITS))) (PUSH `(LIST 'SETQ ,(LIST 'QUOTE IV) ,INCEXPR) UPDATES) (PUSH (LIST 'QUOTE `(IF (NOT ,IV) (GO $$OUT))) PRETESTS))) (SETF (GET 'REPEATWHILE 'FORWORD) '(PUSH (LIST 'QUOTE `(IF (NOT ,(CADR X)) (GO $$OUT))) POSTTESTS)) (SETF (GET 'REPEATUNTIL 'FORWORD) '(IF (NUMBERP (CADR X)) (PUSH (LIST 'QUOTE `(IF (> ,IV ,(CADR X)) (GO $$OUT))) POSTTESTS) (PUSH (LIST 'QUOTE `(IF ,(CADR X) (GO $$OUT))) POSTTESTS))) (SETF (GET 'SMALLEST 'FORWORD) '(PROGN (PUSH '$$EXTREME VARLIST) (PUSH (LIST 'QUOTE `(COND ((OR (NULL $$EXTREME) (< ,(CADR X) $$EXTREME)) (SETQ $$EXTREME ,(CADR X)) (SETQ $$VAL ,IV)))) BODYS))) (SETF (GET 'SUM 'FORWORD) '(PROGN (PUSH ''(SETQ $$VAL 0) INITS) (PUSH (LIST 'QUOTE `(SETQ $$VAL (+ ,(CADR X) $$VAL))) BODYS))) (SETF (GET 'TO 'FORWORD) '(LET (LIMIT (INITAMT (INTERN (CONCATENATE 'STRING "$$INIT" (PRINC-TO-STRING INCCNT)) "USER")) (INCREM (INTERN (CONCATENATE 'STRING "$$INC" (PRINC-TO-STRING INCCNT)) "USER")) (BYVAR (INTERN (CONCATENATE 'STRING "$$INCVAR" (PRINC-TO-STRING INCCNT)) "USER")) (END (INTERN (CONCATENATE 'STRING "$$END" (PRINC-TO-STRING INCCNT)) "USER"))) (OR (EQL IV (CADR (CADAR INITS))) (PUSH `'(SETQ ,IV 1) INITS)) (OR (SYMBOL-VALUE INCREM) (SET INCREM 1)) (OR (CONSTANTP (CADR X)) (PUSH (LIST (SETQ LIMIT (GENSYM)) (CADR X)) VARLIST)) (OR (SYMBOL-VALUE INITAMT) (SET INITAMT 1)) (OR (EQL IV (CADR (CADDAR UPDATES))) (PUSH `(LIST 'INCF ',IV (IF (CONSTANTP ,INCREM) ,INCREM (LIST 'SETQ ,BYVAR ,INCREM))) UPDATES)) (SET END (CADR X)) (PUSH (LIST 'FROMTOTEST `',IV INITAMT END `',INCREM BYVAR `',LIMIT) PRETESTS))) (SETF (GET 'THEREIS 'FORWORD) '(PROGN (PUSH (LIST 'QUOTE `(COND (,(CADR X) (SETQ $$VAL (OR ,IV1 T)) (GO $$OUT)))) BODYS))) (SETF (GET 'UNION 'FORWORD) '(PUSH (LIST 'QUOTE `(SETQ $$VAL (UNION ,(CADR X) $$VAL))) BODYS)) (SETF (GET 'UNLESS 'FORWORD) '(PUSH (LIST 'QUOTE `(IF ,(CADR X) (GO $$ITERATE))) PRETESTS)) (SETF (GET 'UNTIL 'FORWORD) '(IF (NUMBERP (CADR X)) (PUSH (LIST 'QUOTE `(IF (> ,IV ,(CADR X)) (GO $$OUT))) PRETESTS) (PUSH (LIST 'QUOTE `(IF ,(CADR X) (GO $$OUT))) PRETESTS))) (SETF (GET 'WHEN 'FORWORD) '(PUSH (LIST 'QUOTE `(IF (NOT ,(CADR X)) (GO $$ITERATE))) PRETESTS)) (SETF (GET 'WHILE 'FORWORD) '(PUSH (LIST 'QUOTE `(IF (NOT ,(CADR X)) (GO $$OUT))) PRETESTS)) (SETF (GET 'IL:FORMACRO 'IL:MAKEFILE-ENVIRONMENT) '(:PACKAGE "USER" :READTABLE "XCL")) -- Darrel J. Van Buer, PhD; unisys; 2400 Colorado Ave; Santa Monica, CA 90406 (213)829-7511 x5449 KI6VY darrel@CAM.UNISYS.COM or ...{allegra,burdvax,cbosgd,hplabs,ihnp4}!sdcrdcf!darrelj