Subject: Re: Vancouver Lisp Users Group meeting for November 2008 - 0x20 Years of Lisp Systems, a Personal Journey
From: rpw3@rpw3.org (Rob Warnock)
Date: Thu, 20 Nov 2008 05:29:41 -0600
Newsgroups: comp.lang.lisp,comp.lang.scheme
Message-ID: <l-idncH1SYy417jUnZ2dnUVZ_rPinZ2d@speakeasy.net>
Pascal J. Bourguignon <pjb@informatimago.com> wrote:
+---------------
| billc <billclem@gmail.com> writes:
| > Here's the "official" meeting notice:
| > Topic: 0x20 Years of Lisp Systems, a Personal Journey
| 
| #x20
| 
| Or else you will have to write quite some reader macros...
+---------------

Here's the one I use:

;;; SET-ZERO-X-READER -- Provide C-style hex numbers, e.g., 0x1234.
(defun set-zero-x-reader (&optional (enable t))
  (flet ((zero-x-reader (stream char)
           (declare (ignore char))
           ;; Note that we lie about RECURSIVE-P to avoid EOF error signal.
           (let ((c (peek-char nil stream nil nil nil)))
             (cond
              ((null c)
               0)                               ; EOF. Just return the 0.
              ((char-equal c #\x)               ; "0x"?
               (read-char stream t nil t)       ; Eat the "x"
               (let ((*read-base* #x10))
                 (read stream t nil t)))        ;   and read rest in hex.
              ((digit-char-p c *read-base*)     ; Normal number?
               (read stream t nil t))           ; Yes, just read.
              ((char-equal c #\.)               ; "0.xyz" is number, too.
               (read stream t nil t))
              ((alpha-char-p c)                 ; Funny symbol? Sorry.
               (error "Can't handle token (#\0 ~s ...)" c))
              (t                                ; Else prob. terminator
               0)))))                           ;   just return zero.
    (if enable
      (set-macro-character #\0 #'zero-x-reader t)
      (set-syntax-from-char #\0 #\1))))         ; Revert to standard.

It has a couple of bugs[1], but it's generally solid enough that I
leave it enabled by default in the REPL, which makes it *much* easier
to cut & paste stuff from C environments.[2]


-Rob

[1] For example, it doesn't support symbols starting with "0",
    which breaks the LTk socket protocol to its backend server,
    so I have to disable it when using LTk.

[2] I have also previously mentioned the inverse, a FORMAT function
    named |0X|, which does C-style hex output:

  (defun \0x (stream arg colon-p at-sign-p &optional mincol padchar)
    "Hexadecimal numeric printing for use with the FORMAT ~/.../ directive.
    Outputs ARG to STREAM as \"~(0x~mincol,padX~)\" [default \"~(0x~8,'0X~)\"].
    If COLON-P, the entire output will be capitalized instead of lowercased.
    If AT-SIGN-P is true, the \"0x\" prefix will be suppressed."
    (let* ((fmt1 "~~~:[~;:@~](~:[0x~;~]~~~:[8~;~:*~a~],'~:[0~;~:*~a~]x~~)")
	   (fmt2 (format nil fmt1 colon-p at-sign-p mincol padchar)))
      (format stream fmt2 arg)))

    Example:

      (format t "~4/0x/~%" (+ 0x13 5))
      0x0018
      NIL
      > 

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607