LoginSignup
2
0

More than 3 years have passed since last update.

久しぶりなLisp フォーマッタ本編

Last updated at Posted at 2021-01-01

気を入れて

前編でテキトーな記事を書いてしまいました。本編のフォーマッタのことはさっぱり書かずに余談が多すぎました。フォーマッタのことについて書き加えます。

お手本

竹内郁雄先生の書法、流儀をお手本にしています。初めての人のためのLISPに例題として簡単なプリティープリンタが紹介されています。ここではシンプルに次のルールが採用されています。

ppの原則(251ページ)
(1)1行にS式が打てるなら、その行に打つ。
(2)同一行に対応する開きガッコがない閉じガッコ(「お供」と呼ぼう)が並ぶときは
それの左端に空白を1個はさむ
(3)カッコのレベルが1つ深まると、段が2文字分深まる。

お供

お供のことをすっかり忘れていました。LISPを学び始めたときにはこのお供を入れて書いていたように思うのですが、いつの間に閉じカッコはべったり詰めて書くようになってました。お供は最内部のS式についてのみ適用されるようです。その外側ではお供があってもスペースは入りません。自作フォーマッタはこれを当初、静的に解析しようとしていました。そうすると複雑なコードになってしまいました。そこで関数プログラミングからは逸脱しますが、大域変数でお供が発生していたかどうかを記憶することとしました。

追加ルール

cond節やifなど慣習により書法が決まっているものについても清書してほしいので次のルールを追加することにしました。

追加ルール
(4)コンスにつき、先頭要素以外の要素につきいずれも文字数が15を超えるならば
それらについてインデントする。
(5)コンスをインデントするときにおいて、組み込み関数であるときは残りの要素のインデントは
第一要素の位置に合わせる。
(6)cond節の条件帰結が1行で書けるとしても、総文字数が一定数を超える場合には条件式と帰結式を分けて書く。
(7)クオート、バッククオートのときで1行で書けないときは1文字下げて改行する。
(8)cond節など書法の慣習が定着しているシンタックスはそれに従う。

(+ なんたらかんたらあれこれああする関数 さらにあれしてこれしてさらにあれする関数)
は長くて見辛いので(4)でインデントすることとしました。

コメント

コメントのフォーマットについては竹内先生の本では触れられていません。セミコロンを使うコメントはセミコロンが1つのもの、2つのもの、3つのものに区別されるのが慣習のようです。1つのものは改行せず、同一行の同じ列に置くのが慣習のようです。

文字列を活用

竹内先生の本にあるように一般的なプリティープリンタは数なのか?シンボルなのか?とその型を調べてそれに応じた出力をしています。しかし、それだと同じ自然数でも 123 #Xface #O0706 #B01010101 のように多様な表現があります。オリジナルのコードの情報を失わないためにそれらはコンスを除きすべて文字列として取り込むこととしました。

オリジナルコードの保存

foo.lspというファイルであれば、オリジナルのコードはfoo.orgに保存することとしています。開発初期段階でありformatterがこける可能性もあります。こけてもオリジナルのファイルはそのまま残るようにしています。

利用方法

libraryフォルダのformatter.lspとしてあります。これをloadすればいいのですが、めんどくさいので起動時に-fオプションでもloadするようにしてあります。そして (formatter "foo.lsp")のようにすればOKです。

清書例


#|
初めての人のためのLISP
竹内郁雄 著 より
|#


;;;147ページ
(defun delete-1 (x y)
    (setq y (cons 'dummy))       ;dummy set
    (del2 x y)                   ;call del2
    (cdr y) )

;;;89ページ
(defun atom-count (x)
    (cond ((nullx) 0)                        ;null
          ((atom x) 1)                       ;atom
          ;;else
          (t (+ (atom-count (car x))
                (atom-count (cdr x))))))

;;;79ページ
(defun last-elm (x)
    (cond ((null x) nil)
          (t (last-elm2 x)) ))

;;96ページ
(defun my-reverse (x)
    (cond ((null x) x)
          (t (append (my-reverse (cdr x)) (list (car x)))) ))



コードはgithubにおいてあります。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0