December 13, 2007
String parsing with the LOOP facility
As part of a read macro I needed to parse strings. Lisp strings don’t have escapes except for double quotes (as they are string delimiters) and the backslash (which is the escape character).
Here’s what I came up with, a really fine example of Algol style code with three nested conditionals:
(defun read-lisp-string (stream) "Parse a Lisp string. Expects stream to point to the first character after the leading double quote." (coerce (loop for char = (read-char stream) with nbackslashes = 0 with eos = nil if (char= char #\\) do (setq nbackslashes (+ nbackslashes 1)) and if (and (evenp nbackslashes) (not (equal nbackslashes 0))) collect char end else if (char/= char #\") do (setq nbackslashes 0) and collect char else if (oddp nbackslashes) collect char else do (setq eos t) until eos) 'simple-string))
The most important thing I learned: although in all places you can read that there’s no accepted standard for the LOOP facility, the respective section of the spec is quite helpful in determining whether a certain clause is allowed at some place.
Comments(2)
LOOP’s fun, but I think this particular task would look better with a simpler variation:
(defun read-lisp-string (input)
(with-output-to-string (output)
(loop
(let ((char (read-char input)))
(case char
(#\\
(setf char (read-char input)))
(#\”
(return)))
(write-char char output)))))
(Hope the formatting survives…)
Great, thanks!