文字列の別表記

プログラミング言語によっては、文字列を複数の方法で表記出来ることがある。
例えば、rubyの場合は以下の様に表記することが可能だ。

"文字列"
'文字列'
%Q{文字列}
# その他にもあったように思うけど、使わないので不明。

対して、common lispの場合は、ダブルクォート(#\")で囲む方法しかない。
大抵の場合はそれでも十分なのだが、たまに#\"や#\\をエスケープしないで多用したいことがある。

なので、そのためのリードマクロを書いてみる。

;; 文字列読み込み
;; numは、streamの最初の何文字を引用符として使用するかを指定
;; ex. num=1,!string!; num=2,_!string!_
(defun read-quot (stream num)
  (let ((quots (loop for i from 1 to num collect #1=(read-char stream))))
    (do ((acc (list #1#) (cons #1# acc)))
	((every #'char= quots acc)
	 (coerce (nreverse (nthcdr (length quots) acc)) 'string)))))

;; リードマクロ
(set-dispatch-macro-character #\# #\q
  (lambda (stream chr num)
    (declare (ignore chr))
    (read-quot stream (or num 1))))

;; 実行例
> #q!c:\windows\system32\"file1"!
--> "c:\\windows\\system32\\\"file1\""

> #2q__c:\windows\system32\f_i_l_e__
--> "c:\\windows\\system32\\f_i_l_e"

案外簡単にできた。
問題は、この表記をデフォルトではemacs(のlisp-mode)が文字列として認識してくれないことだろう。これは今回の例に限らず、マクロ・リードマクロ全般に付随する問題だけど..