情報処理学会, 卓上出版シンポジウム, 1988年7月21日〜23日 箱根 静雲荘
LispマシンELISの核言語TAOにはその設計の段階から2バイト文字のサポートが組み込まれていた. TAOでは日本語文字コードにEUCを使用し, 1バイトのASCII文字と2バイトの漢字の完全な混在を可能としている. 文字列は1バイト文字と2バイトの文字がパックされたリストと考える. 文字列はTAO/ELISの基本データ構造であり, 文字列の生成や操作はファームウェア (マイクロコード) でサポートされている. 漢字の混った文字列はアトムのプリント名やパッケージの名前, ファイル名などに自由に使うことができる.
文字列を文字のリストとして考えているので, TAOのプリミティブな文字列操作関数はリスト操作と対応づけることができる. 次に主な関数の例をあげる.
| 文字列操作 | リスト操作 |
| (shead str [n]) | (car list) or (firstn n list) |
| (stail str [n]) | (cdr list) or (nthcdr n list) |
| (snull str) | (null list) |
| (sequal str1 str2) | (equal list1 list2) |
| (sconc str1 str ...) | (append list1 list2 ...) |
| (slength str) | (length list) |
| (spop str) | (pop list) |
| (nchar str n) | (nth n list) |
| (nsubstring str start [end]) | (nthcdr start (firstn end list)) |
| (smemq str1 str2) | (member m list) |
| (string-lessp str1 str2) | ??? |
この他, 文字操作や文字種変換の比較的大きな機能の関数も大部分はマイクロコードで実現されている. カタカナとひらがなの変換や, ASCII文字を2バイトの全角文字に直す関数も用意されている.
| 関数の例 | 結果 |
| (digit-char-p "7") | 7 |
| (lower-case-p "f") | "f" |
| (kanjip "可") | "可" |
| (nhiragana-katakana "あいうえお") | "アイウエオ" |
| (nstring-capitalize "string") | "String" |
| (ascii-jis "*+*") | "*+*" |
1. で述べたようにプリミティブは豊富に用意されているが, 日本語の文章の作成や編集を行なうにはそれらを活かしたエディタと漢字の入力手段が必要である.
われわれがプログラミングで使っているのはEmacsタイプのエディタである. (TAO/ELISにはZEN (Zeroth Editor for Nue) という名前の画面エディタがある. ほぼEmacsと思ってよい. ) Emacsの特徴は, ほとんどの編集コマンドがコントロール文字に割り当てられていて, 挿入モード, コマンドモードの区別がない (実は印字文字には自分を編集バッファに 挿入するというコマンドが割り当てられている), 文字, 単語, S式などテキストのまとまった部分を編集の単位とするコマンドが 豊富に用意されている. 利用者によるカスタム化ができる, などである. また, 文字列のサーチが目的の文字列を1文字入力するごとに先へ探しにいく インクリメンタルサーチであることも特徴といえる.
われわれはTAO/ELIS上でシステム開発や, 計算機による実験を行なっている. この種の使い方では, プログラムを書いては走らせる, の繰り返しであり, 計算機接続時間のかなりの時をエディタ操作で費やすことになる. よって, テキスト編集は極めて日常的な作業であり, 編集コマンドにもわれわれは十分習熟している. そこで, 日本語の入力と編集もぜひEmacsで行なって, 日本語のために別のコマンド 体系を憶えるようなことは避けたい. また, プログラムにコメントをいれたり, 別のウィンドウで実行した結果を文書に挿入する などの使い方を考えれば, 日本語の機能が付加されたからといって, 通常の 編集機能が変わってしまうのは好ましくない. この方針に沿ってEmacsコマンドとの整合性と類似性を重視して作成したのが Kanzen (漢字ZEN) と呼ばれる日本語の入力法である.
Kanzenの設計思想をまとめておく.この思想を実現するために, 入力中, 変換中などの状態情報はバッファ上の文字列自体に保持し, エディタには変換のモードを設けないような構成とした. 変換起動, 次候補選択などのコマンドはすべてコマンド発行時にバッファの情報を使って処理をする. これにより, 確定前の文字列が残っているようなときでも, 編集コマンドはすべて有効である. 具体的には, TAO/ELISの基本データ構造であるフォント付き文字列を利用した. これは文字ごとに7ビットの情報を保持できる文字列である. 文字列操作時にもその情報は保存される. Kanzenで重要な意味をもつ下線部, 反転部 (後出) の情報はここに置き, 編集作業による対象の移動などに対処してる.
日本語の入力は, ローマ字かな変換または, 新JIS配列によるかな入力で行なう. このときデフォルトはひらがな確定入力である. 漢字に変換したいときはその読みの先頭をローマ字の大文字で入力する. かな入力のときは初めにSpace (またはユーザが指定したキー)を入力して先に漢字変換を指定する. 変換開始文字には下線が印として付けられる. そして次の大文字 (や他の変換起動文字) の入力で変換開始文字から適当な区切り文字までが漢字に変換される. 変換された文字列は反転表示されて次候補の選択が可能になる. 反転表示部は次に別の文字列が変換されて反転表示されると, 通常表示になり, 確定状態となる.
入力と変換の様子を示す. 左側が入力文字列, 右側が画面に表示されたものである.
| Ky | Ky |
[下線はその文字が大文字で入力されたことを示す. ]
| o | きょ |
[ローマ字かな変換が起こる. 下線がついたままであることに注意. ]
| uW | 今日W |
| atasiha | 今日わたしは |
| I | 今日私はい |
[次の大文字 I で, 「わたしは」の部分が変換起動される. それと同時にもとからあった反転表示部が確定する. 変換は, 大文字のほか, 句読点・空白・改行・カッコなど文章上の明らかな区切り記号, ^C (ASCIIモードへの移行), ^J (日本語モードへの移行) で起動される. 変換の範囲は, 下線部から現在のカーソル位置または最初の区切り記号, 漢字・カタカナ・ASCII文字などの直前までである. 第一文節の後ろは全部ひらがなのまま残る. ]
前にも述べたように, 下線部, 反転表示部はエディタの編集用バッファの文字列に付いた情報であって,
エディタのモードを変えるようものではない.
上の例のどの状態でも通常の編集コマンドは有効である.
上で W を入力したとき,
表示は 今日W となっているが,
ここでカーソルを動かして別の部分の編集を行なうことも可能である.
後で, W の後ろにカーソルを戻せば,
上の例はそのまま続行できる.
Kanzenを使って日本語のテキストの編集をしているときは, 日本語の特徴に合わせた編集コマンドが働くようになっている. 例えば, forward-word, backward-wordなど, 英語では単語を単位としてカーソルを移動するコマンドは, ひらがなからその他の文字に変わるところを区切りとする.
例えば次の文で, 『移』にカーソルがあるとき, forward-wordを繰り返すと, 次の下線の文字にカーソルが移動する. 残念ながら『その他』の『そ』には止まらない.
移動するコマンドはひらがなからその他の文字に
また, Kanzenの変換方式では前から順番に漢字が確定していくので,
サーチも確定したところから直ちに行なうことにした.
ひらがなは確定入力なので,
これはちょうどインクリメンタルサーチにあたる
ただし, 例えば『k』を入力したところではサーチは始まらない.
次に『a』をいれて『か』に変換されたところで『か』を探しにいく.
だが, 新JIS入力でのインクリメンタルサーチで問題が生じた. 新JIS入力の濁音は濁点を後から入力する. つまり『か』+『゛』で『が』を入力する. ところが, サーチ中は『か』を入力したところでサーチが始まってしまう. 解決策としては, (1)濁音になり得る文字の時はサーチを待つ, (2)『゛』が入力されて直前の文字が濁音に変わった時は1文字分のサーチを取り消して, 改めて濁音の文字が入力されたように扱う, の2つの方法が考えられる. Kanzenでは(2)を採用した. だが, 例えばバッファに『が』は存在するが『か』はないとき, 『か』をサーチするとこのサーチは失敗する. ところが続けて『゛』を入力すると失敗がまず取り消され, そしてサーチは成功することになる. これはかなり苦しい選択ではあるが, 最善だと考えている.
以上のようにコマンドをEmacsに合わせることにより, 日本語ファイルの作成と編集においてもプログラムテキストの編集と同様の使用感が得られた.
TAOで書かれたアプリケーションプログラムでも, 統一された手段で日本語の入力が行なえるとよい. これを実現するため, 入力用ストリームの中のデバイスにあたる部分にエディタを接続した. 入力ストリームのデバイス部にはストリームのバッファが空になったときに呼ばれる関数が設定されている. 例えばファイルストリームであれば, デバイスとストリーム内のバッファとのDMAを実行する関数がある. ここに, エディタを呼び出す関数を置いて, 入力時のKanzen利用を可能とした.
次のような関数で日本語入力用のストリームが作られる.
! はTAOの式で代入をあらわす. ここではsetqにあたる.
(!stream (make-kanji-stream)) (!x (read stream))
このread関数が実行されると1行分のウィンドウをもったZENエディタが起動される. ここでKanzenを使って日本語を入力することができる. かっこを閉じずに改行を入力するとウィンドウが1行づつ高くなっていく. このウィンドウの内部では, エディタのコマンドが有効である. ここで作られたストリームはファイルストリームや端末に接続されたストリームと同じ形をしているので, 通常の入力関数で利用可能である.
だが, このストリームは日本語入力を実現するためにバッファストリームとなっている. よって, read-char関数のように通常は1文字入力を直ちに受けつけるものも, 改行を入力するまで止まってしまうのが問題である. また, read-char-with-timeout関数のようにある時間で戻るものも, 次候補を選んでいるあいだに戻って良いのかどうかなど, 通常のストリームとの意味上の整合性にまだ問題が残っている.
このストリームを使ってLispのトップレベルでの入力にも漢字が使えるようにした. ここでのヒストリーの探索はインクリメンタルとし, 作業全般にわたりモードを減らすようにしている. また, このトップレベルではエディタコマンドとしての関数名やファイル名の補完も動作する.
Kanzenは日本語の文章の入力と編集のための手段であって, 出力整形の機能は含んでいない. 本来, ZENは,VT100タイプの端末でテキストを編集することを主な目的として設計されたので, 図表や絵の作成は考えていない. きれいな出力を得るための清書系も別のシステムで行なう方針である.
その1つとして, ELISに直結したプリンタに出力するためのroffタイプの清書系が備わっているが, われわれのところではあまり使われない. ネットワーク環境が整備されたのがその主な原因である. この環境にはELIS自身のネットワークソフトウェアの整備と研究室内外の機器とソフトウェアの蓄積の両方が含まれる. これにより, UNIXなどに備わっている資産を利用することが容易になった.
現在はSUN 3上で稼働しているjTeXを使って印刷出力を得ている. ELISとSUNとはEthernetのTCP/IPプロトコルで接続されている. 出力結果を得るまでの手順はおおよそ次のようになっている.
煩雑のようだが, 実際には次のようなTAO関数を定義して使用している.
(defun jtex (jis-file) (ncopy jis-file "nuesun::tex/" "auto" "amagai" "password") (rsh (sconc "cd tex; jtex " jis-file)) )
ncopyはftpを非対話的に使う関数である. "auto" はテキストとバイナリのファイルタイプの自動判定を指示している. rshはUNIXのRemote Shellプロトコルのクライアントを実現した関数で, UNIXコマンドを 引数にとる. この関数を使えば, それほど不便を感じずに他の計算機の資産を活用することができる. もちろんこの方法ではjTeXでエラーがでたときにSUN上で直すわけにはいかない. jTeXをTAO/ELISに移植すればこの問題は解決できるが, 将来の課題である.
TAO/ELISは大容量の文字列領域と高速の文字列操作関数を備えている. 文字列操作マシンとしての能力はかなり高い. だが, 現在のところ, TAO関数で直接提供しているのはプリミティブな操作であって, SNOBOLやICONに備わっているような高級なマッチングやこれに伴う制御構造はない. テキスト処理もエディタで提供できる程度の機能があるだけである. 文字列操作用の高級言語や日本語辞書と組み合わせた編集支援システムなどはこれからの課題である.
最後に, Kanzenのかな漢字変換ルーティンと辞書を提供していただいた杉村利明氏と, 本論文を印刷するのに使ったjTeXを提供していただいた斉藤康己, 磯崎秀樹の各氏に感謝する.