2014/01/19
行継続
行指向の文法、つまり改行が単なる空白文字より大きな区切りを意味する文法において、
編集上の都合から見た目の行を折り返したい場合がある。
多くの場合は、行末に「次の行に継続する」ことを指示する文字を置くことで実現される。
行末バックスラッシュが多いのはUnixとC文化かな。
Common Lispのformat文字列では~
。Fortranは&
。Texinfoは@
。
Visual Basicではアンダースコアだったっけ。
一方Vim Scriptでは、行末に文字を置くのではなく、継続する行の先頭に文字を置くよ、 という話を読んだ。
さて、では一方 Vim script は、と言うと…
let g:quickrun_config = { \ '_': { \ 'input': '=%{b:input}', 'cmdopt': '%{b:cmdopt}', 'args': '%{b:args}', \ 'runner': 'vimproc', \ 'runner/vimproc/updatetime': 500, \ }, \ }
viとの互換性が理由だそうだ。
が、「次の行の方に前行からの継続を示すマーカがある」という文法を扱ったことが 何回かあるような気がしたので考えてみた。
RFC822のヘッダは原則1行で完結するけれど、次の行が空白文字で始まっている場合は それが継続行とみなされる。
Subject: Long subject line can be folded like this.
WiLiKiのマークアップは、行頭の ~
で前の行からの継続を示す。
強調などのマークアップは行をまたげないので、'''長い行をこんなふうに ~強調したかったら行継続を使う'''。
なぜこうしたのか忘れちゃったけど、wikiマークアップは「行頭にあること」 で意味を持つものが多いのでそれに合わせたのかも。
プログラミング言語で「次行行頭」にマーカを置く例はなかなか見つからない。 COBOLが "-" を「リテラルを前の行から継続」に使ってるけれど、 '-'を書くカラムが決まってるから「行頭」と言えるかどうか。
http://cobol.404i.com/basics.php
000340 DISPLAY 'This might be a very long string that 000350- 'needs to be continued onto the next line'
この表記を見てFTPのリプライ行継続マーカ (あれも-
だ) を思い出したが、
FTPの方は「次に続く行がある場合」につけるので、「行末継続文字」グループの
親戚みたいなもんだろう。
★ ★ ★
技術的な観点では、「前の行から続いているよ」というマーカよりは、 「まだ行が続くよ」の方がパーザが書きやすい。前者では 次の行を読んでみないと今の行が終わるかどうかわからないので、 先読み、もしくはバッファリングが必要になる。
ただ、人間が普通のテキストを読み書きする際には、「まだ続くよ」マーカは あまり使われない。「行」が意味を持つ文章で、組版の都合でどうしても 行途中で折り返さないとならない時は、継続行がインデントで示されるのが普通だ。
Their sense thus weak, lost with their fears thus strong, Made senseless things begin to do them wrong; For briers and thorns at their apparel snatch, Some sleeves, some hats, from yielders all things catch.
これは手元にあったペーパーバックからフォーマットをそのまま引用したものだけど、 "strong" や "catch"が前行からの継続であることは自然にわかる。 RFC822形式はある意味「人間にとって自然な記法」と言えるかもしれない。
「行の継続」だけでなくもう少しスコープを広げると、 結局先読みやバッファリングが必要になる構文はそこそこある。
- Makefileのタブを使う文法は今となっては古くさいけれど、あの行頭タブは ひとつのルールのブロックを継続するマーカと言える。
- インデント指向な文法でも、次の行のインデントを読んでみないと 今のブロックが終わるかどうかはわからない。
なので、パーザの書きやすさを理由に「次の行に続くよ」式文法を採用する意味は あまり大きくないかもしれない。
★ ★ ★
行継続構文についてもうひとつ考えるべき問題は、行をくっつけた時の「糊」の部分を どうするか、である。トークンの区切りとしての空白は何個あっても意味が変わらないので ただ行をくっつけるだけで良いが、リテラルの中で改行している場合は空白の個数が 意味を持ってくる。
「ただくっつける」という動作の場合、リテラル中に余分な空白を入れたくなければ、 次の行を行頭から始めないとならない:
str = "This is a string \ literal"
けれども、意味的にインデントを揃えたいと思うのが人情だろう:
str = "This is a string \ literal."
このため、「次に来る行の行頭の空白を全て無視する」としている仕様もある。
Schemeの文字列リテラルや、Common Lispのformat文字列の ~
がそうだ。
(define str "This is a string \ litreral.")
しかしこれはこれで、「出力の行頭に一定数のスペースを含めたい」って時に ややこしい。例えばこんな出力が欲しいとき:
Usage: command [-a arg] [-b arg] file ... Options: -a arg Blah blah blah -b arg Blah blah blah
物理行の先頭でインデントしててもその空白が食われてしまうので、 必要な空白の前に空白でない何かを置いとかないとならない:
(define (usage) (display "Usage: command [-a arg] [-b arg] file ...\ \nOptions:\ \n -a arg Blah blah blah\ \n -b arg Blah blah blah\ \n"))
Common Lispのformat文字列では「次の行の空白を保存する」という オプションもあるが、プログラムテキスト上の意味的なインデントと 出力に含めたいインデントを区別できないので、ちょっと足りてない感じだ。
「後続行に、前から続く行であることを示すマーカを入れる」という文法であれば、
空白文字以外のマーカを使うことでこの問題を解決できる。
たとえば仮想的に、行頭の\s*~
が「前の行からの継続」を示す、
という文法があるなら、こんなふうに書けるだろう。
(define (usage) (display "Usage: command [-a arg] [-b arg] file ...\n ~Options:\n ~ -a arg Blah blah blah\n ~ -b arg Blah blah blah\n ~"))
リテラルに関してこれに近いことをやっていた言語があったような気もするのだけど 思い出せない。
なお、「人間にとって自然」に見えるRFC822の行折り返しだが、空白文字の扱いについて
微妙な点がある。英文の慣習では、\s*\n\s+
がひとつの空白に置換され、
RFC822もそれに沿っているわけだが、この文法だと「空白を含めずに折り返す」
というケースが書けない。Subjectヘッダの扱いに関して困った覚えがある。
(MIMEを用いても、各MIMEエンコーディングは物理行内で完結しないとならないので、仕様に厳密に従うと行継続の空白が残ってしまうのだ。実際のメールクライアントはそのへんヒューリスティックに対応しているっぽいが。 (追記2014/01/20 06:06:20 UTC)これは私の誤解だった。rfc2047の6.2節にてこのケースへの対応が示されている。コメント欄参照。)
なので、「継続を示すマーカ」は空白文字とか区別できる方がいい。
特に結論めいたものはないけれど、新たな文法を考えるなら、 少なくともリテラルの行継続については、「行頭の <空白>* <非空白文字のマーカ>」というのは 案外良い選択なんではないかな、と思った。
Tag: Programming
nobsun (2014/01/20 02:32:55):
nobsun (2014/01/20 02:33:54):
shiro (2014/01/20 02:51:18):
な (2014/01/20 03:55:12):
shiro (2014/01/20 06:03:05):
ksmakoto (2014/01/23 09:20:49):
shiro (2014/01/23 18:39:17):
ksmakoto (2014/01/24 03:37:09):
thinca (2014/01/30 02:31:44):
shiro (2014/01/30 02:42:57):