From: billc
Subject: Vancouver Lisp Users Group meeting for November 2008 - 0x20 Years of 	Lisp Systems, a Personal Journey
Date: 
Message-ID: <a453523c-680e-4e72-bb5c-d59fe9524fad@a26g2000prf.googlegroups.com>
Hi all,

Norman Jaffe has been using Lisp and Lisp Machines for more years than
most lispvan members have been alive! Working on such a broad range of
Lisp systems has given him a fairly unique perspective on Lisp as a
language and Lisp Machines as a working environment (Norm gave an
earlier presentation on "Wearing Lisp" at the April 2006 lispvan
meeting). During this presentation, Norm will be showing off some
actual Lisp Machines and Lisp Environments and talking about his
experiences with them.

We will have the meeting at a new location, The Hackery, (with a
projector and a special meeting room!), so make certain you take note
of the new location.

Here's the "official" meeting notice:

Topic: 0x20 Years of Lisp Systems, a Personal Journey
Presenter: Norman Jaffe
Date: Thursday, November 27th, 2008
Time: 7pm - 10pm (or whenever)
Venue: The Hackery, 304 Victoria Dr (entrance off Franklin), Vancouver
Summary: While at the University of Washington and Simon Fraser
University in the early '70s, I was exposed to a wide variety of
computer languages and systems. Most have 'fallen by the wayside', but
four have influenced my travels through the computing landscape -
Lisp, Smalltalk, Snobol and APL. Tonight I'll talk about where LISP
has taken me, from informal 'Greenspun' code to dedicated hardware. I
hope to show the breadth of Lisp systems and the exciting new
directions that I see.

Join us for a beer (bring your own - there's a fridge) and/or coffee
and a chance to see some old and new lisp machines and lisp
environments and to discuss what was, what is, and what could be!

For updates (and additional links), see my blog posting:
http://bc.tech.coop/blog/081119.html

--
Bill Clementson

From: Pascal J. Bourguignon
Subject: Re: Vancouver Lisp Users Group meeting for November 2008 - 0x20 Years of  Lisp Systems, a Personal Journey
Date: 
Message-ID: <87wsezw7fb.fsf@hubble.informatimago.com>
billc <········@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...

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

PUBLIC NOTICE AS REQUIRED BY LAW: Any use of this product, in any
manner whatsoever, will increase the amount of disorder in the
universe. Although no liability is implied herein, the consumer is
warned that this process will ultimately lead to the heat death of
the universe.
From: Rob Warnock
Subject: Re: Vancouver Lisp Users Group meeting for November 2008 - 0x20 Years of  Lisp Systems, a Personal Journey
Date: 
Message-ID: <l-idncH1SYy417jUnZ2dnUVZ_rPinZ2d@speakeasy.net>
Pascal J. Bourguignon <···@informatimago.com> wrote:
+---------------
| billc <········@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.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kaz Kylheku
Subject: Re: Vancouver Lisp Users Group meeting for November 2008 - 0x20 Years of  Lisp Systems, a Personal Journey
Date: 
Message-ID: <20081120124743.822@gmail.com>
On 2008-11-20, Andreas Davour <·······@updateLIKE.uu.HELLse> wrote:
> ····@rpw3.org (Rob Warnock) writes:
>
>> [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
>>       > 
>
> I'm not sure if I should be impressed or run screaming.

Nope! Why, of course, you should use it to troll the Ruby, OCaml and F#
newsgroups. :)
From: Kaz Kylheku
Subject: Re: Vancouver Lisp Users Group meeting for November 2008 - 0x20 Years of  Lisp Systems, a Personal Journey
Date: 
Message-ID: <20081120125109.713@gmail.com>
["Followup-To:" header set to comp.lang.lisp.]
On 2008-11-20, Rob Warnock <····@rpw3.org> wrote:
>     (let* ((fmt1 "~~~:[···@~](~:[0x~;~]~~~:[8~;~:*~a~],'~:[0~;~:*~a~]x~~)")
> 	   (fmt2 (format nil fmt1 colon-p at-sign-p mincol padchar)))
>       (format stream fmt2 arg)))

You might be interested in an S-exp to format string translator that I
developed.

Your string is a bit hard to understand; it took a while to reverse engineer
it and render it to my syntax, but here goes:


(form (tilde) 
      (bool "" ·@")                 ; param 
      "(" 
      (bool "0x" "")                ; param
      (tilde) 
      (bool "8" ((go-back) (a)))    ; param
      ",'" 
      (bool "0" ((go-back) (a)))    ; param
      "x" 
      (tilde) 
      ")")

The output string is:

"~~~:[··@~](~:[0x~;~]~~~:[8~;~:*~A~],'~:[0~;~:*~A~]x~~)"

       ^
       \ here is a small difference from yours.

You used a :; separator in conjunction with ~:[  which is useless.
The :; separator is used to indicate a default case in enumerations.
Booleans don't have a default case; it's just true and false.
You should probaby avoid this construction in the interest of portability;
the CLHS doesn't document the combination of ~:[ and ;:.

It's still hard to understand, but less so. By adding the ";param" comments, I
made it clear for myself where the parameters are being taken. The rest is
template material.

So we know there are four parameters.

The first one optionally generates ·@".

The next one optionally generates "0x".

The third one generates "8" when the parameter is false, otherwise it generates
that parameter. The (go-back) directive causes the parameter which controls the
boolean switch to be re-used for the (a) directive (i.e. the aesthetic ~a).

The fourth one similarly generates the fourth parameter aesthetically or "0" if
it is missing.

These four substitutions, call them $1 $2 $3 and $4, are inserted
into a template like this:

  ~$1($2.~$3,'$4x~) 

It's a ~x directive wrapped in ~( .. ~)  with an optional prefix specified
by $2, plus a width and padding character specified by $3 and $4.

Here is the source code for FORM:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defvar *in-logical-block* nil)
  (defvar *in-justify-block* nil)

  (defun form-check-type (&rest specs)
    (loop for (name type value) in specs
          do
            (unless (or (null value)
                        (and (eq type 'integer)
                             (member value '(:arg :numargs)))
                        (subtypep (type-of value) type))
              (error "FORM: ~s must be of type ~s, not ~s" name type value))))

  (defun form-check-arg (directive)
    (unless (cdr directive)
      (error "FORM: ~s directive requires argument" (first directive))))

  (defun param-type-p (param)
    (or (integerp param)
        (member param '(:arg :numargs))))

  (defun write-param (param stream)
    (case param
      (:arg (write-char #\V stream))
      (:numargs (write-char #\# stream))
      (otherwise (princ param stream))))

  (defun form-character (stream &key readably spell-out mention-shift-keys)
    (when readably
      (write-char ··@ stream))
    (when (or spell-out mention-shift-keys)
      (write-char #\: stream)
      (when mention-shift-keys
        (write-char ··@ stream)))
    (write-char #\C stream))

  (defun form-simple-with-count (stream char &optional count)
    `(form-check-type
       (count integer ,count))
    (when count
      (write-param count stream))
    (write-char char stream))

  (defun form-modifiers (stream leading-comma-p &rest modifiers)
    (loop for tail on modifiers
          if (null (first tail))
            if (every #'null (rest tail))
              do (loop-finish)
            else
              do (when leading-comma-p
                   (write-char #\, stream))
            end
          else
            if (characterp (first tail))
              do (format stream "~a'~a"
                         (if leading-comma-p #\, "")
                         (first tail))
            else
              do (when leading-comma-p
                   (write-char #\, stream))
                 (write-param (first tail) stream)
            end
          end
          do (setf leading-comma-p t)))


  (defun form-radix (stream radix &key sign mincol padchar
                                       commachar commainterval)
    (unless (subtypep (type-of radix) 'character)
      (form-check-type `(radix integer ,radix)))
    (form-check-type
      `(sign integer ,sign)
      `(mincol integer ,mincol)
      `(padchar character ,padchar)
      `(commachar character ,commachar)
      `(commainterval integer ,commainterval))
    (if (param-type-p radix)
      (write-param radix stream))
    (form-modifiers stream (param-type-p radix)
                    mincol padchar commachar commainterval)
    (when sign
      (write-char ··@ stream))
    (when (or commachar commainterval)
      (write-char #\: stream))
    (write-char (if (param-type-p radix) #\R radix) stream))

  (defun form-floating (stream sym char &key width precision expdigits
                                             scalefactor overflowchar
                                             padchar exponentchar)
    (form-check-type
      `(width integer ,width)
      `(precision integer ,precision)
      `(expdigits integer ,expdigits)
      `(scalefactor integer, scalefactor)
      `(padchar character ,padchar)
      `(exponentchar character ,exponentchar))
    (when (and (or expdigits exponentchar) (eq sym 'f))
      (error "FORM: EXP-DIGITS or EXPONENTCHAR not valid with ~s directive"
             sym))
    (if (eq sym 'f)
      (form-modifiers stream nil width precision scalefactor
                      overflowchar padchar)
      (form-modifiers stream nil width precision expdigits scalefactor
                      overflowchar padchar exponentchar))
    (write-char char stream))

  (defun form-money (stream &key precision mindigits width padchar)
    (form-check-type
      `(precision integer ,precision)
      `(mindigits integer ,mindigits)
      `(width integer ,width)
      `(padchar character ,padchar))
    (form-modifiers stream nil precision mindigits width padchar)
    (write-char #\$ stream))

  (defun form-object (stream char &key nilparens colinc
                                  pad-left-to pad-right-to
                                  pad-left-by pad-right-by padchar)
    (form-check-type
      `(nilparens boolean ,nilparens)
      `(pad-left-to integer ,pad-left-to)
      `(pad-right-to integer ,pad-right-to)
      `(pad-left-by integer ,pad-left-by)
      `(pad-right-by integer ,pad-right-by)
      `(colinc integer ,colinc)
      `(padchar character ,padchar))
    (when (and (or pad-left-to pad-left-by)
               (or pad-right-to pad-right-by))
      (error "FORM: left and right padding specified simultaneously"))
    (let ((mincol (or pad-left-to pad-right-to))
          (minpad (or pad-right-by pad-left-by)))
      (form-modifiers stream nil mincol colinc minpad padchar))
    (when (or pad-left-to pad-left-by)
      (write-char ··@ stream))
    (when nilparens
      (write-char #\: stream))
    (write-char char stream))

  (defun form-write (stream &key pretty)
    (form-check-type `(pretty boolean, pretty))
    (if pretty
      (write-char #\: stream))
    (write-char #\W stream))

  (defun form-cond-newline (stream &optional kind)
    (case kind
      ((nil :linear) (write-char #\_ stream))
      (:miser (write-string ·@_" stream))
      (:fill (write-string ":_" stream))
      (:mandatory (write-string ··@_" stream))
      (otherwise (error "FORM: invalid conditional newline kind: ~s" kind))))

  (defun form-block (stream &optional properties &rest directives)
    (unless (listp properties)
      (push properties directives)
      (setf properties nil))
    (destructuring-bind (&key parens autofill
                              take-remaining-args
                              prefix suffix prefix-per-line)
                        properties
      (when (and suffix (not prefix))
        (error "FORM: BLOCK cannot have suffix, but no prefix"))
      (when parens
        (write-char #\: stream))
      (when take-remaining-args
        (write-char ··@ stream))
      (write-char #\< stream)
      (when prefix
        (write-string prefix stream)
        (write-char #\~ stream)
        (when prefix-per-line
          (write-char ··@ stream))
        (write-char #\; stream))
      (let ((*in-logical-block* t))
        (dolist (directive directives)
          (form-translate directive stream)))
      (when suffix
        (write-string "~;" stream)
        (write-string suffix stream))
      (write-string "~:" stream)
      (when autofill
        (write-char ··@ stream))
      (write-char #\> stream)))

  (defun form-indent (stream &rest args)
    (let (amount (kind :current))
      (dolist (arg args)
        (if (integerp arg)
          (setf amount arg)
          (setf kind arg)))
      (form-check-type `(amount integer ,amount))
      (when amount
        (write-param amount stream))
      (case kind
        ((nil :current)
         (write-char #\: stream))
        (:block)
        (otherwise (error "FORM: indent kind or amount expected, not ~s"
                              arg)))
      (write-char #\I stream)))

  (defun form-call (stream foo name)
    (form-check-type `(name string ,name))
    (format stream "/~a/" name))

  (defun form-tab (stream &key column colinc section relative)
    (form-check-type
      `(column integer ,column)
      `(colinc integer ,colinc)
      `(section boolean ,section)
      `(relative boolean ,relative))
    (form-modifiers stream nil column colinc)
    (when section
      (write-char #\: stream))
    (when relative
      (write-char ··@ stream))
    (write-char #\T stream))

  (defun form-justify-properties (stream directives &key mincol colinc
                                                         minpad padchar
                                                         pad-left pad-right
                                                         first-item-conditional
                                                         conditional-width)
    (form-check-type
      `(mincol integer ,mincol)
      `(colinc integer ,colinc)
      `(minpad integer ,minpad)
      `(padchar character ,padchar)
      `(pad-left integer ,pad-left)
      `(pad-right integer ,pad-right)
      `(first-item-conditional boolean ,first-item-conditional)
      `(conditional-width integer ,conditional-width))
    (form-modifiers stream nil mincol colinc minpad padchar)
    (when pad-left
      (write-char #\: stream))
    (when pad-right
      (write-char ··@ stream))
    (write-char #\< stream)
    (let ((*in-justify-block* t))
      (when first-item-conditional
        (cond
          ((null directives)
           (setf directives '("" "")))
          ((null (rest directives))
           (setf directives (append directives '(""))))))
      (when directives
        (form-translate (first directives) stream))
      (dolist (directive (rest directives))
        (write-char #\~ stream)
        (when first-item-conditional
          (when conditional-width
            (write-param conditional-width stream))
          (write-char #\: stream)
          (setf first-item-conditional nil))
        (write-string ";" stream)
        (form-translate directive stream)))
    (write-string "~>" stream))

  (defun form-justify (stream &optional properties &rest directives)
    (unless (listp properties)
      (push properties directives)
      (setf properties nil))
    (apply #'form-justify-properties stream directives properties))

  (defun form-end-justify (stream)
    (unless *in-justify-block*
      (error "FORM: END-JUSTIFY must be enclosed within JUSTIFY block"))
    (write-char #\^ stream))

  (defun form-go-nth (stream &optional argument-number)
    (form-check-type
      `(argument-number integer ,argument-number))
    (when argument-number
      (write-param argument-number stream))
    (write-string ·@*" stream))

  (defun form-go-forward-back (stream backward-p &optional argument-step)
    (form-check-type
      `(argument-step integer ,argument-step))
    (when argument-step
      (write-param argument-step stream))
    (when backward-p
      (write-char #\: stream))
    (write-char #\* stream))

  (defun form-enum-bool-when-count (stream kind count directives)
    (when count
      (write-param count stream))
    (case kind
      (:when
        (when (rest (rest directives))
          (error "FORM: WHEN-TRUE takes only one argument"))
        (write-char ··@ stream))
      (:bool
        (when (or (null (rest directives))
                  (rest (rest (rest directives))))
          (error "FORM: BOOL takes exactly two arguments"))
        (write-char #\: stream)))
    (write-char #\[ stream)
    (when directives
      (when (and (eq kind :enum-d)
                 (null (rest directives)))
        (write-string ":;" stream))
      (form-translate (first directives) stream))
    (loop for directive-tail on (rest directives)
          do (write-char #\~ stream)
             (when (and (null (rest directive-tail))
                        (and (eq kind :enum-d)))
               (write-char #\: stream))
             (write-char #\; stream)
             (form-translate (first directive-tail) stream))
    (write-string "~]" stream))

  (defun form-enum-bool-when (stream kind &rest directives)
    (let (count)
      (when (param-type-p (first directives))
        (setf count (pop directives)))
      (form-enum-bool-when-count stream kind count directives)))

  (defun form-iterate-properties (stream directives
                                         &key sublists take-remaining-args
                                              at-least-once max-iterations)
    (when max-iterations
      (write-param max-iterations stream))
    (when sublists
      (write-char #\: stream))
    (when take-remaining-args
      (write-char ··@ stream))
    (write-char #\{ stream)
    (dolist (directive directives)
      (form-translate directive stream))
    (write-char #\~ stream)
    (when at-least-once
      (write-char #\: stream))
    (write-char #\} stream))

  (defun form-iterate (stream &optional properties &rest directives)
    (unless (listp properties)
      (push properties directives)
      (setf properties nil))
    (apply #'form-iterate-properties stream directives properties))

  (defun form-recurse (stream take-args-p)
    (when take-args-p
      (write-char ··@ stream))
    (write-char #\? stream))

  (defun form-directive (directive stream)
    (write-char #\~ stream)
    (case (first directive)
      (c (apply #'form-character stream (rest directive)))
      (newline (apply #'form-simple-with-count
                      stream #\% (rest directive)))
      (freshline (apply #'form-simple-with-count
                        stream #\& (rest directive)))
      (page (apply #'form-simple-with-count
                   stream #\| (rest directive)))
      (tilde (apply #'form-simple-with-count
                    stream #\~ (rest directive)))
      (r (form-check-arg directive)
         (apply #'form-radix stream (rest directive)))
      ((d b o x)
       (apply #'form-radix
              stream
              (case (first directive)
                (d #\D) (b #\B) (o #\O) (x #\X))
              (rest directive)))
      ((f e g)
       (apply #'form-floating stream (first directive)
              (case (first directive) (f #\F) (e #\E) (g #\G))
              (rest directive)))
      ((a s) (apply #'form-object stream
                    (case (first directive) (a #\A) (s #\S))
                    (rest directive)))
      (w (apply #'form-write stream (rest directive)))
      (cond-newline (apply #'form-cond-newline stream (rest directive)))
      (block (apply #'form-block stream (rest directive)))
      (indent (apply #'form-indent stream (rest directive)))
      (call (form-check-arg directive)
            (apply #'form-call stream (rest directive)))
      (tab (apply #'form-tab stream (rest directive)))
      (justify (apply #'form-justify stream (rest directive)))
      (end-justify (apply #'form-end-justify stream (rest directive)))
      (go-nth (apply #'form-go-nth stream (rest directive)))
      (go-forward (apply #'form-go-forward-back stream nil (rest directive)))
      (go-back (apply #'form-go-forward-back stream t (rest directive)))
      (enum (apply #'form-enum-bool-when stream :enum (rest directive)))
      (enum-default (apply #'form-enum-bool-when stream :enum-d
                           (rest directive)))
      (bool (apply #'form-enum-bool-when stream :bool (rest directive)))
      (when-true (apply #'form-enum-bool-when stream :when (rest directive)))
      (iterate (apply #'form-iterate stream (rest directive)))
      (recurse (apply #'form-recurse stream nil (rest directive)))
      (recurse-args (apply #'form-recurse stream t (rest directive)))
      (otherwise
        (error "FORM: unrecognized directive ~s" directive))))

  (defun form-translate (directive stream)
    (cond
      ((stringp directive)
       (write-string directive stream))
      ((atom directive)
       (error "FORM: invalid directive: ~s" directive))
      ((consp directive)
       (if (consp (first directive))
         (mapc (lambda (nested-directive)
                 (form-translate nested-directive stream)) directive)
         (form-directive directive stream))))))

(defmacro form (&rest directives)
  (with-output-to-string (stream)
    (dolist (directive directives)
      (form-translate directive stream))))
From: Kaz Kylheku
Subject: Re: Vancouver Lisp Users Group meeting for November 2008 - 0x20 Years of  Lisp Systems, a Personal Journey
Date: 
Message-ID: <20081120164907.803@gmail.com>
On 2008-11-20, Kaz Kylheku <········@gmail.com> wrote:
> ["Followup-To:" header set to comp.lang.lisp.]
> On 2008-11-20, Rob Warnock <····@rpw3.org> wrote:
>>     (let* ((fmt1 "~~~:[···@~](~:[0x~;~]~~~:[8~;~:*~a~],'~:[0~;~:*~a~]x~~)")
>> 	   (fmt2 (format nil fmt1 colon-p at-sign-p mincol padchar)))
>>       (format stream fmt2 arg)))
>
> You might be interested in an S-exp to format string translator that I
> developed.
>
> Your string is a bit hard to understand; it took a while to reverse engineer
> it and render it to my syntax, but here goes:
>
>
> (form (tilde) 
>       (bool "" ·@")                 ; param 
>       "(" 
>       (bool "0x" "")                ; param
>       (tilde) 
>       (bool "8" ((go-back) (a)))    ; param
>       ",'" 
>       (bool "0" ((go-back) (a)))    ; param
>       "x" 
>       (tilde) 
>       ")")

Not being happy with this, I added support for meta-format-string generation.
That is to say, there is S-exps for specifying the static parts of the format
string which represent pieces of a format string saved for a second formatting
round.

The general (META ...) operator will cause all tildes to be escaped in 
enclosing constructs, its opposite being (TORA ...).  (Greek for "now").

META-ENCLOSURE is for coding a parenthesized enclosure, with pieces that
are implicitly TORA.

META-SIMPLE is for coding a simple formatting directive, with optional
modifiers, specified by a property list where the properties indicate type,
and the values are sexps that compute the text.

Here goes:

  (form 
    (meta-enclosure #\(      ;; enclosure based on ~( ... ~) i.e. case conv.
      :at :optional          ;; @ is optional, i.e. specified by boolean arg
      :directives            ;; contents of ~( ... ~) enclosure:
         ((bool "0x" "")     ;;   optional "0x" prefix, depending on bool arg
          (meta-simple #\x   ;;   ~x directive with two computed modifiers
           :modifiers
           (integer (bool "8" ((go-back) (a)))          ;; int. modifier
            character (bool "0" ((go-back) (a))))))))   ;; char modifer


  =>  "~~~:[··@~](~:[0x~;~]~~~:[8~;~:*~A~],'~:[0~;~:*~A~]x~~)"

Haha!

More fun. An enclosure with ~; - separated pieces is called a "multi",
and there is a meta generation for it:

  ;; empty basic one

  (form (meta-multi #\[)) 
  
    -> "~~[~~]"

  ;; three (a) forms turn to three ~a directives as separate pieces:

  (form (meta-multi #\[ :directives ((a) (a) (a))))

    -> "~~[~A~~;~A~~;~~A~~]"

  ;; default case is supported

  (form (meta-multi #\[ :default-p t :directives ((a) (a) (a))))

    -> "~~[~A~~;~A~~;:~~A~~]"

  (format nil (form (meta-multi #\[ :directives ((a) (a) (a)))) 
              "red" "green" "blue)

    -> "~[1~;2~;3~]"

  (loop for color in '(0 1 2 3 4)
        with meta-formstring = (form (meta-multi #\[ 
                                       :directives ((a) (a) (a) (a))
                                       :default-p t))
        with colors-formstring = (format nil meta-formstring 
                                         "red" "green" "blue" "unknown")
        collect (format nil colors-formstring color))

   -> ("red" "green" "blue" "unknown" "unknown")

:)
From: Rob Warnock
Subject: Re: Vancouver Lisp Users Group meeting for November 2008 - 0x20 Years of  Lisp Systems, a Personal Journey
Date: 
Message-ID: <KvSdnfuxD8zSjLXUnZ2dnUVZ_szinZ2d@speakeasy.net>
Kaz Kylheku  <········@gmail.com> wrote:
+---------------
| ["Followup-To:" header set to comp.lang.lisp.]
| On 2008-11-20, Rob Warnock <····@rpw3.org> wrote:
| >     (let* ((fmt1 "~~~:[···@~](~:[0x~;~]~~~:[8~;~:*~a~],'~:[0~;~:*~a~]x~~)")
| > 	   (fmt2 (format nil fmt1 colon-p at-sign-p mincol padchar)))
| >       (format stream fmt2 arg)))
| 
| You might be interested in an S-exp to format string translator that I
| developed.
| 
| Your string is a bit hard to understand; it took a while to reverse
| engineer it and render it to my syntax, but here goes: ...
...
| The output string is:
| "~~~:[··@~](~:[0x~;~]~~~:[8~;~:*~A~],'~:[0~;~:*~A~]x~~)"
|        ^
|        \ here is a small difference from yours.
| You used a :; separator in conjunction with ~:[  which is useless.
| The :; separator is used to indicate a default case in enumerations.
| Booleans don't have a default case; it's just true and false.
| You should probaby avoid this construction in the interest of portability;
| the CLHS doesn't document the combination of ~:[ and ;:.
+---------------

Please look again!! *VERY CLOSELY!!* Here, I'll extract the relevant bit:

    ~:[···@~]

Please notice that I didn't *use* a "~:;" separator!! I used a "~;"
separator, exactly what is supposed to be used for boolean conditionals.
The ":" that is confusing you is a literal ":" *after* the "~;" that
is emitted (along with an ·@" character) when the conditional is true.

For others trying to follow along here, note that the alternate
(false branch) is empty. Only the consequent (true branch) outputs
anything here, the string ··@". The purpose of this bit is to pass
the COLON-P argument to |0X| ["capitalize the output"] on to the
generated "~(" directive, that is, emit ···@(" if COLON-P is true
and plain "~(" if not. I suppose could have replaced the whole ugly
"~:[···@~]" conditional FORMAT directive above with simply "~a", by
replacing the COLON-P argument in the first following FORMAT with:

    (if colon-p ···@(" "~(")

The ugly conditional FORMAT directive just pushes that IF down into
the FMT1 string.


-Rob

p.s. Yes, I'll freely admit that the format string in |0X| is
"hard to understand" (Kaz was being kind, actually!) -- it was
certainly hard for me to write (clearly "write once/read never"
code!!). But it only had to be written once, since the |0X| function
is buried deep in my UTILS package. In fact, I haven't ever needed
to read it again in the year and a half since it was first written,
until now.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Tobias C. Rittweiler
Subject: C-style hex number reader macro (Was: Re: Vancouver Lisp Users Group ...)
Date: 
Message-ID: <87skpll1aw.fsf_-_@freebits.de>
····@rpw3.org (Rob Warnock) writes:

> 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))
>   ...)

Hey Rob!

You can find my take on it post scriptum. I tested it on tokens like

   0xCAFE, 0x042, 0x00DEADBEEF00, 0.001   turning to numbers

and
  
   0x-reader, frob-0x-value, my-0.2-cent  turning to symbols.


I can think of two issues:

  a) Tokens of the form 0x001 are potential numbers per the spec, so an
     implementation may interpret those tokens specially. My reader macro
     below would follow that special interpretation.

  b) I use a scratch package which will be filled with symbols over
     time. (It's not as bad as it sounds, as it'll be filled with symbols
     containing "0x" only, so very few in praxis.) I think this eludes
     the need for weak packages. :-)

Issue a) is mostly hypothetical, and issue b) does not matter much as
long as you do not use this reader macro on untrusted input.

  -T.




(eval-when (:compile-toplevel :load-toplevel :execute)
  (when (find-package "SB-READER")
    (pushnew :sb-reader *features*)))

(defvar *tmp-package* (make-package (gensym "TMPPKG")))

(defun set-0x-reader (&optional (enable t))
  (labels ((read-token (stream char)
	     #+(and sbcl sb-reader)       (sb-reader::read-token stream char)
	     #+(and sbcl (not sb-reader)) (sb-impl::read-token stream char)
	     #-sbcl			; default
	     (let ((resurrected-stream
		    (make-concatenated-stream
		     (make-string-input-stream (string char))
		     stream)))
	       (set-syntax-from-char #\0 #\1)
	       (unwind-protect (read resurrected-stream t nil t)
		 (set-macro-character #\0 #'0x-reader t))))
	   (0x-reader (stream char)
	     (let* ((actual-pkg *package*)
		    (*package* *tmp-package*)
		    (token (read-token stream char)))
	       (etypecase token
		 (number token)
		 ;; This works as follows:
		 ;;
		 ;;    If the symbol was not interned in *TMP-PACKAGE*,
		 ;;    we know it _must_ have been a straight symbol in
		 ;;    the first place.
		 ;;
		 ;;    Otherwise, we look at the symbol if it's of the
		 ;;    form 0xnnnn; if so, we return the nnnnn as
		 ;;    number, otherwise we return the symbol interned in
		 ;;    the original *PACKAGE*.
		 (symbol
		  (if (not (eq (symbol-package token) *tmp-package*))
		      token
		      (let ((token-string (symbol-name token)))
			(if (char-equal (char token-string 1) #\x)
			    (multiple-value-bind (n pos)
				(parse-integer token-string
					       :start 2
					       :radix 16
					       :junk-allowed t)
			      (if (and n (= pos (length token-string)))
				  n
				  (intern token-string actual-pkg)))
			    (intern token-string actual-pkg)))))))))
    (if enable
	(set-macro-character #\0 #'0x-reader t)
	(set-syntax-from-char #\0 #\1))))
From: billc
Subject: Re: Vancouver Lisp Users Group meeting for November 2008 - 0x20 Years 	of Lisp Systems, a Personal Journey
Date: 
Message-ID: <cc5b8a69-10db-4be2-b1a3-3f7851b1abc3@a29g2000pra.googlegroups.com>
Hi all,

I've posted a summary (with movie and ppt) of last night's lispvan
presentation on my blog:
http://bc.tech.coop/blog/081128.html

Thanks Norm for a fantastic presentation! We had 15 attendees and the
new venue looks like a keeper! Plenty of space, no noise, a projector,
lots of free parking, and a fridge for our beer - what more could one
want from life? ;-)

Cheers,
Bill

On Wed, Nov 26, 2008 at 7:52 AM, Bill Clementson <········@gmail.com>
wrote:
> Hi all,
>
> Just a reminder of tomorrow's lispvan meeting. Remember that it is at
> a new location.
>
> See you there!
> Bill
>
> On Wed, Nov 19, 2008 at 4:11 PM, Bill Clementson <········@gmail.com> wrote:
>> Hi all,
>>
>> Norman Jaffe has been using Lisp and Lisp Machines for more years than
>> most lispvan members have been alive! Working on such a broad range of
>> Lisp systems has given him a fairly unique perspective on Lisp as a
>> language and Lisp Machines as a working environment (Norm gave an
>> earlier presentation on "Wearing Lisp" at the April 2006 lispvan
>> meeting). During this presentation, Norm will be showing off some
>> actual Lisp Machines and Lisp Environments and talking about his
>> experiences with them.
>>
>> We will have the meeting at a new location, The Hackery, (with a
>> projector and a special meeting room!), so make certain you take note
>> of the new location.
>>
>> Here's the "official" meeting notice:
>>
>> Topic: 0x20 Years of Lisp Systems, a Personal Journey
>> Presenter: Norman Jaffe
>> Date: Thursday, November 27th, 2008
>> Time: 7pm - 10pm (or whenever)
>> Venue: The Hackery, 304 Victoria Dr (entrance off Franklin), Vancouver
>> Summary: While at the University of Washington and Simon Fraser
>> University in the early '70s, I was exposed to a wide variety of
>> computer languages and systems. Most have 'fallen by the wayside', but
>> four have influenced my travels through the computing landscape -
>> Lisp, Smalltalk, Snobol and APL. Tonight I'll talk about where LISP
>> has taken me, from informal 'Greenspun' code to dedicated hardware. I
>> hope to show the breadth of Lisp systems and the exciting new
>> directions that I see.
>>
>> Join us for a beer (bring your own - there's a fridge) and/or coffee
>> and a chance to see some old and new lisp machines and lisp
>> environments and to discuss what was, what is, and what could be!
>>
>> For updates (and additional links), see my blog posting:
>> http://bc.tech.coop/blog/081119.html
>>
>> --
>> Bill Clementson
>>
>