Simple octal reader macro in Common Lisp As an exercise, I've implemented a simple reader macro in Common Lisp (using SBCL).  It converts Octal (unsigned integers only) into numbers.

Usage:

* #z1234

668


The code:

(defun oct-string-to-number 
  (string)
  "Converts an octal string to a number.  Only digits from 0 - 7 are accepted; sign or decimal point symbols will cause oct-to-number to fail"
  (setq place 1)
  (setq result 0)
  (setq digits '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7))
  (loop for char across (reverse string)
    do 
    (setq pos (position char digits))
    (setq result (+ result (* pos place)))
    (setq place (* 8 place)))
  result)

(defun slurp-octal-digits 
  (stream)
  (setq string (make-array 0 :element-type 'character :fill-pointer 0 :adjustable t))
  "Slurps all digits from 0 - 7 from a stream into a string, stopping at EOF, no data, or a non-digit character." 
  (setq digits '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7))
  (with-output-to-string (out)
             (loop do
                   (setq char (read-char stream))
                   (setq isnum nil)
                   (if char
                   (progn
                     (setq isnum (find char digits))
                     (if isnum
                     (vector-push-extend char string)
                       (unread-char char stream))))
                   while (not (eq nil isnum))))
  string)

(defun octal-string-transformer 
  (stream subchar args)
  "Slurps an octal number from stream, and converts it to a number.  Number must be an unsigned integer."
  (setq oct-string (slurp-octal-digits stream))
  (oct-string-to-number oct-string))

;; Sets #z to call octal-string-transformer, so e.g. #z1234 will evaluate to 668.  Use #z as SBCL has #o already :-)
(set-dispatch-macro-character
 #\# #\z
 #'octal-string-transformer)


I'm quite new to Common Lisp, so I'd greatly appreciate feedback on everything: formatting, style, idiom, correctness :-)

Edited to add: Actually, the formatting in the pasted code snippet is rendered oddly; indentation that is present when I edit vanishes when I submit.  So maybe be a bit gentle with feedback about the formatting ;-)
First of all a note about variables: You're using setq on previously undefined and undeclared variables. This is actually undefined behavior and in most implementations will create global dynamic/special variables. To create local variables (which you presumably intended) use let.

(defun oct-string-to-number 
  (string)
  "Converts an octal string to a number.  Only digits from 0 - 7 are accepted; sign or decimal point symbols will cause oct-to-number to fail"


This whole function can be implemented as (parse-integer string :radix 8). However for the sake of learning let's go through the function anyway:

(setq digits '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7))
...
(setq pos (position char digits))


Iterating through the list of digits to convert a digit to an integer, is neither the most efficient nor the most succinct to do it. You can use the digit-char-p function which returns the digit's int value, if the given char is a digit and nil otherwise. (The same applies in slurp-octal-digits where you do the same thing).

(loop for char across (reverse string)
    do 
    (setq pos (position char digits))
    (setq result (+ result (* pos place)))
    (setq place (* 8 place)))


Instead of reversing the string and keeping track of a place variable, you can just iterate over the string from the beginning and multiply the result by 8 each step:

(loop for char across string
    do 
    (setq result (+ (* 8 result) (digit-char-p char))))


That being said, I'd rather use reduce then loop here (that is, if I weren't using parse-integer) - especially as higher order functions are one of the most useful things in lisp that a newcomer should get acquainted to. Using reduce the function would be written like this:

(defun oct-string-to-number (string)
  "Converts an octal string to a number.  Only digits from 0 - 7 are accepted; sign, non-octal digit or decimal point will signal error."
  (reduce
    (lambda (sum digit)
      (+ (* 8 sum) (digit-char-p digit 8)))
    string :initial-value 0))