Книга: Practical Common Lisp
Designing the Macros
Designing the Macros
Since you already have a rough idea what code your macros will need to generate, the next step, according to the process for writing a macro I outlined in Chapter 8, is to switch perspectives and think about what a call to the macro should look like. Since the goal is to be able to write something as compressed as the pseudocode in the ID3 specification, you can start there. The header of an ID3 tag is specified like this:
ID3/file identifier "ID3"
ID3 version $02 00
ID3 flags %xx000000
ID3 size 4 * %0xxxxxxx
In the notation of the specification, this means the "file identifier" slot of an ID3 tag is the string "ID3" in ISO-8859-1 encoding. The version consists of two bytes, the first of which—for this version of the specification—has the value 2 and the second of which—again for this version of the specification—is 0. The flags slot is eight bits, of which all but the first two are 0, and the size consists of four bytes, each of which has a 0 in the most significant bit.
Some information isn't captured by this pseudocode. For instance, exactly how the four bytes that encode the size are to be interpreted is described in a few lines of prose. Likewise, the spec describes in prose how the frame and subsequent padding is stored after this header. But most of what you need to know to be able to write code to read and write an ID3 tag is specified by this pseudocode. Thus, you ought to be able to write an s-expression version of this pseudocode and have it expanded into the class and function definitions you'd otherwise have to write by hand—something, perhaps, like this:
(define-binary-class id3-tag
((file-identifier (iso-8859-1-string :length 3))
(major-version u1)
(revision u1)
(flags u1)
(size id3-tag-size)
(frames (id3-frames :tag-size size))))
The basic idea is that this form defines a class id3-tag
similar to the way you could with DEFCLASS
, but instead of specifying things such as :initarg
and :accessors
, each slot specification consists of the name of the slot—file-identifier
, major-version
, and so on—and information about how that slot is represented on disk. Since this is just a bit of fantasizing, you don't have to worry about exactly how the macro define-binary-class
will know what to do with expressions such as (iso-8859-1-string :length 3)
, u1
, id3-tag-size
, and (id3-frames :tag-size size)
; as long as each expression contains the information necessary to know how to read and write a particular data encoding, you should be okay.
- Binary Files
- Binary Format Basics
- Strings in Binary Files
- Composite Structures
- Designing the Macros
- Making the Dream a Reality
- Reading Binary Objects
- Writing Binary Objects
- Adding Inheritance and Tagged Structures
- Keeping Track of Inherited Slots
- Tagged Structures
- Primitive Binary Types
- The Current Object Stack
- 4.4.4 The Dispatcher
- About the author
- Chapter 7. The state machine
- Appendix E. Other resources and links
- Example NAT machine in theory
- The final stage of our NAT machine
- Compiling the user-land applications
- The conntrack entries
- Untracked connections and the raw table
- Basics of the iptables command
- Other debugging tools
- Setting up user specified chains in the filter table