To start with, you should define a package for this library. Here’s the package file that comes with the version you can download from the book’s Web site:

    The COM.GIGAMONKEYS.MACRO-UTILITIES package contains the with-gensyms and once-only macros from Chapter 8.

    Since you already have a handwritten version of the code you want to generate, it shouldn’t be too hard to write such a macro. Just take it in small pieces, starting with a version of define-binary-class that generates just the **DEFCLASS** form.

    1. (major-version u1)

    But that’s not a legal slot specifier for a **DEFCLASS**. Instead, you need something like this:

    Easy enough. First define a simple function to translate a symbol to the corresponding keyword symbol.

    Now define a function that takes a define-binary-class slot specifier and returns a **DEFCLASS** slot specifier.

    1. (defun slot->defclass-slot (spec)
    2. (let ((name (first spec)))
    3. `(,name :initarg ,(as-keyword name) :accessor ,name)))
    1. BINARY-DATA> (slot->defclass-slot '(major-version u1))

    Looks good. Now the first version of define-binary-class is trivial.

    This is simple template-style macro—define-binary-class generates a **DEFCLASS** form by interpolating the name of the class and a list of slot specifiers constructed by applying slot->defclass-slot to each element of the list of slots specifiers from the define-binary-class form.

    To see exactly what code this macro generates, you can evaluate this expression at the REPL.

    1. ((identifier (iso-8859-1-string :length 3))
    2. (major-version u1)
    3. (revision u1)
    4. (flags u1)
    5. (size id3-tag-size)
    1. (defclass id3-tag ()
    2. ((identifier :initarg :identifier :accessor identifier)
    3. (major-version :initarg :major-version :accessor major-version)
    4. (revision :initarg :revision :accessor revision)
    5. (flags :initarg :flags :accessor flags)
    6. (size :initarg :size :accessor size)