while ループ ¶続いて2つのwhileループがあります。最初のwhileには、forward-sentenceの接頭辞引数が負の数である場合に真となる真偽判定があります。これは逆方向に辿るためのものです。このループの本体は、2番目のwhile節の本体と似ていますが、完全に同一ではありません。このwhileループは省略し、2番目のwhileループに注目します。
2つ目の while
ループは、点を前方に移動させるためのものです。その骨組みは以下のようになっています。
(while (> arg 0) ; true-or-false-test
(let varlist
(if (true-or-false-test)
then-part
else-part
(setq arg (1- arg)))) ; while loop decrementer
while ループはデクリメント型です。(デクリメントカウンタを用いたループを参照してください。)このループには、カウンタ(この場合は変数
arg)が 0
より大きい限り真となる真偽判定があり、また、ループが繰り返されるたびにカウンタの値から 1 を減算するデクリメンターが備わっています。
コマンドの最も一般的な使い方である forward-sentence
にプレフィックス引数が指定されない場合、arg の値が 1 となるため、この while ループは1回実行されます。
while ループの本体は、ローカル変数を生成してバインドする let 式で構成されており、その本体として if 式を持つ。
while ループの本体は次のようになっています。
(let ((par-end
(save-excursion (end-of-paragraph-text) (point))))
(if (re-search-forward sentence-end par-end t)
(skip-chars-backward " \t\n")
(goto-char par-end)))
let という式は、ローカル変数 par-end
を生成してバインドします。後述するように、このローカル変数は正規表現による検索に制約や制限を設けるために設計されています。検索によって段落内で適切な文が見つからなかった場合、段落の末尾に達した時点で検索は停止します。
しかしその前に、まず par-end
が段落末尾の値にどのように束縛されるのかを見てみましょう。実際には、let が par-end の値を、Lispインタプリタが式を評価した際に返される値に設定します。
(save-excursion (end-of-paragraph-text) (point))
この式では、(end-of-paragraph-text) で point
を段落の末尾に移動し、(point) で point の値を返し、その後 save-excursion で point を元の位置に戻します。 したがって、let は par-end を save-excursion 式が返す値(すなわち段落末尾の位置)にバインドします。 (end-of-paragraph-text 関数では forward-paragraph を使用していますが、これについては後ほど説明します。)
Emacsは次にletの本体を評価します。これは次のようなif式です。
(if (re-search-forward sentence-end par-end t) ; if-part (skip-chars-backward " \t\n") ; then-part (goto-char par-end))) ; else-part
if は、第1引数が真であるかどうかを判定し、真であれば then
部を評価します。そうでない場合は、Emacs Lisp インタプリタが else 部を評価します。if 式の真偽判定は、正規表現検索です。
forward-sentence
関数の本来の処理と思われるものがここに埋もれているのは奇妙に思えるかもしれませんが、Lisp ではこの種の操作は一般的にこのように行われます。