R. Matthew Emerson <rme@clozure.com> wrote:
+---------------
| Don Geddis <don@geddis.org> writes:
| > I had a sudden idea: maybe I should just use variables that
| > evaluate to integers:
| > (in-package "ENUM")
| > (defparameter elementary 0)
+---------------
DEFCONSTANT would probably be more appropriate here than DEFPARAMETER.
CMUCL does the same thing a lot in the UNIX package when defining bits
needed for system calls, e.g., from "cmucl-19c/src/unix.lisp":
(defconstant o_rdonly 0 "Read-only flag.")
(defconstant o_wronly 1 "Write-only flag.")
(defconstant o_rdwr 2 "Read-write flag.")
+---------------
| OpenMCL has a DEFENUM macro that's used in a few places in the system.
| http://trac.clozure.com/openmcl/browser/trunk/ccl/lib/macros.lisp#L3191
| It's used in circumstances like this:
| (ccl::defenum (:prefix "MXCSR-" :suffix "-BIT")
| ie ;invalid exception
| de ;denormal exception
...[trimmed]...
| rc1 ;rounding control bit 1
| fz ;flush-to-zero (not-IEEE)
| )
+---------------
CMUCL has a DEF-ENUM in the UNIX package that has less flexibility
in naming [the :prefix & :suffix args in OpenMCL's DEFENUM are a nice
touch here] but a *lot* more flexibility in auto-assigning values.
The macro is:
(defmacro def-enum (inc cur &rest names)
(flet ((defform (name)
(prog1 (when name `(defconstant ,name ,cur))
(setf cur (funcall inc cur 1)))))
`(progn ,@(mapcar #'defform names))))
Notice that "INC CUR" values of "ASH 1" are useful for bitmasks,
while "+ 0" is useful for sequential integers from 0:
;; Input modes. Linux: /usr/include/asm/termbits.h
(def-enum ash 1 tty-ignbrk tty-brkint tty-ignpar tty-parmrk tty-inpck
tty-istrip tty-inlcr tty-igncr tty-icrnl #-bsd tty-iuclc
tty-ixon #-bsd tty-ixany tty-ixoff #+bsd tty-ixany
#+hpux tty-ienqak #+bsd nil tty-imaxbel)
;; output modes
#-bsd (def-enum ash 1 tty-opost tty-olcuc tty-onlcr tty-ocrnl tty-onocr
tty-onlret tty-ofill tty-ofdel)
#+bsd (def-enum ash 1 tty-opost tty-onlcr)
...
;; special control characters
#+(or hpux svr4 linux) (def-enum + 0 vintr vquit verase vkill veof
#-linux veol #-linux veol2)
#+bsd (def-enum + 0 veof veol veol2 verase nil vkill nil nil vintr vquit)
...
The "(WHEN NAME ...)" in the definition lets you skip values, e.g.;
> (unix::def-enum + 1 one two nil four nil nil nil eight)
EIGHT
> (list eight four two one)
(8 4 2 1)
>
The generality of the INC argument is somewhat marred by the fact
that the function has to have a macro-expansion-time value, so to
supply your own function you need to EVAL-WHEN it [in-line LAMBDAs
don't work here, since INC is passed *unevaluated* to FUNCALL]:
> (eval-when (:compile-toplevel :load-toplevel :execute)
(defun x3 (x ign)
(declare (ignore ign))
(* x 3)))
X3
> (unix::def-enum X3 1
one three nine twenty-seven eighty-one two-hundred-forty-three
seven-hundred-twenty-nine two-thousand-one-hundred-eighty-seven)
TWO-THOUSAND-ONE-HUNDRED-EIGHTY-SEVEN
> (list one three nine two-thousand-one-hundred-eighty-seven)
(1 3 9 2187)
>
-Rob
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607