#:g1: com.informatimago.common-lisp.lisp-reader.readerの紹介

Posted 2014-11-13 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の318日目です。

com.informatimago.common-lisp.lisp-reader.readerとはなにか

 com.informatimago.common-lisp.lisp-reader.readerは、Pascal Bourguignon氏作のANSI Common Lisp標準に準拠したリーダーの実装です。

パッケージ情報

パッケージ名com.informatimago.common-lisp.lisp-reader.reader
Quicklisp

インストール方法

(ql:quickload :com.informatimago.common-lisp.lisp-reader.reader)

試してみる

 Common Lispのリーダーを丸ごと実装しているのですが、動作はカスタマイズも可能で、リーダーと密に連携するためかCommon Lispのパッケージの実装も付属してきます。
カスタマイズは色んな方法が考えられるかと思いますが、リードテーブルにトークンの解釈をする関数が設定されているので、これをいじるだけでも結構色々なことができそうです。

 例として、標準のリーダーでは扱いが面倒臭いパッケージマーカー(:)を単なる文字として扱うようなリーダーを作成してみます。

(defun parse-token* (token)
  "
RETURN:  okp ; the parsed lisp object if okp, or an error message if (not okp)
"
  (let ((message nil))
    (macrolet
        ((rom (&body body)
           "Result Or Message"
           (if (null body)
               'nil
               (let ((vals (gensym)))
                 `(let ((,vals (multiple-value-list ,(car body))))
                    ;; (format *trace-output* "~S --> ~S~%" ',(car body) ,vals)
                    (if (first ,vals)
                        (values-list ,vals)
                        (progn
                          (when (second ,vals)
                            (setf message  (third ,vals)))
                          (rom ,@(cdr body)))))))))
      ;; (format *trace-output* "token: ~S~%" token)
      (multiple-value-bind (ok type object)
          (rom (parse-decimal-integer-token token)
               (parse-integer-token         token)
               (parse-ratio-token           token)
               (parse-float-1-token         token)
               (parse-float-2-token         token)
               ;; (parse-consing-dot-token     token)
               (parse-symbol-token*          token))
        (declare (ignorable type))
        ;; (format *trace-output* "ok = ~S ; type = ~S ; object = ~S~%"
        ;; ok type object )
        (values ok (if ok object message))))))

(defparser parse-symbol-token* (token) (accept 'symbol (intern (token-text token) *package*)))

(setf (readtable-parse-token *readtable*) #'parse-token*) ;=> #<FUNCTION PARSE-TOKEN*>

(with-input-from-string (in "(a:a:a:a b:b:b c \"a\" #'a:a:a)") (read in)) ;=> (|A:A:A:A| |B:B:B| C "a" #'|A:A:A|)

(with-input-from-string (in "(|a:a:a| :a::b::c:: ::)") (read in)) ;=> (|a:a:a| |:A::B::C::| |::|)

(readtable-parse-token *readtable*)でリードテーブルに付属のトークンを解釈する関数を読み書き可能なのでパッケージマーカーについては特に何もせず文字列をシンボルに変換するだけの関数に差し替えています。

まとめ

 今回は、com.informatimago.common-lisp.lisp-reader.readerを紹介してみました。
ほとんど標準のリーダーと同じ動作だけれど、ちょっとだけカスタマイズして使いたい、ということがありますが、パッケージマーカー等が微妙に邪魔だったりします。
この辺りを迂回できるだけでも結構便利に使えますね。

comments powered by Disqus