Text Editor and Corrector
Text Editor and Corrector(略称:TECO)は、1960年代にマサチューセッツ工科大学で開発されたテキストエディタ。当初の名称は[paper] Tape Editor and COrrectorであった。TECOとその派生エディタは、vi(後にUNIXオペレーティングシステムに搭載)やEmacsエディタが普及する以前は広く使われていた。EmacsはTECOの直系の子孫である(TECO用マクロ集の名称だった)。
TECOの構文は複雑であり、テキスト操作の汎用インタプリタ型プログラミング言語としても使えるようになっていた。マクロ機能は非常に強力で、今日では正規表現と呼ばれるものと対抗できるマッチング機能を備えていた。ほとんど全ての文字にコマンドが割り当てられており、適当な文字列も(必ずしも有益とは言えないが)TECOプログラムと解釈することができる。当時よく行われたゲームとして、TECOで何かのファイルを編集していて、自分の名前をコマンド列として与えたときに何が起きるかを見てみるというものがあった。
リチャード・ストールマンは、当初TECO上でEmacsを実装した。その後、Multics EmacsやGNU EmacsはLISPおよびEmacs Lispで実装された。TECOを有名にしたのは、1964年にマサチューセッツ工科大学のProject MACで実装されたDEC PDP-6上のものである。この実装では画面上に編集対象のテキストが継続的に表示され、対話型のオンラインエディタとして使われた。ただし、これは当初の実装とは異なるし、当初想定された使い方でもない。その後のTECOはDECの端末(VT100など)でフルスクリーン表示が可能となった。
TECOはいくつかのオペレーティングシステムやコンピュータで利用可能であった。PDP-1、PDP-6およびPDP-10上のIncompatible Timesharing System (ITS)、PDP-10上のTOPS-10およびTOPS-20などである。DECの各種オペレーティングシステムに対応したバージョンもあり、RT11用バージョンではGT40グラフィックス端末で利用可能だったり、RSTS/E用バージョンでは一種のオペレーティング環境を提供していて、TECOの中であらゆる操作が可能となっていた。ヒューレット・パッカードはコンパックを経由してDECを取得しており、現在もOpenVMSにはTECOが付属している。
DECがPDP-10向けに配布した派生バージョンは現在もインターネット上で入手可能であり、MS-DOS/Microsoft Windows環境にも(部分的に)実装した例がいくつかある。
TECOは1963年ごろ、マサチューセッツ工科大学のダニエル・マーフィーがPDP-1向けに開発した。当時彼が使えるPDP-1(2台)は別の部門のもので、これらにプログラムのソースコードを供給するには紙テープを使用する必要があった。一方、IBMのメインフレームではパンチカードにソースコードを1行ずつパンチすることができ、カードの上端には人間が読める内容が印字されるようになっていた。このため、IBMのマシンでプログラムを書く際には、カードを並べ替えたり、削除したり、挿入したりといったことが手作業で可能だった。しかし、紙テープにはそのような機能が一切なく、そこからオンライン編集の必要性が生まれた。
PDP-1用の初期のエディタは「高価なタイプライタ」と呼ばれていた。作者はスティーブン・パイナーで、ラインエディタとしての基本的な機能しか備えておらず、検索・置換機能も持っていなかった。その名称は同じようにPDP-1向けに開発された「巨大なタイプライタ」と似たような皮肉である。当時のオンラインエディタは、デバッグ時間を大幅に短縮する手段であった。
TECOはPDP-1をより効率的に活用することを目的としていた。マニュアルを見てみると、コンソールを使ってCPU時間を占有して編集を行うよりも、バッチ的にテキスト編集を行うコマンド列を紙テープで用意して適用することを指向していたことがわかる。つまり、編集対象の紙テープと編集コマンドの紙テープをPDP-1にセットして読み込ませ、TECOを実行して編集結果を再び紙テープに出力する。その後、アセンブラをロードして実行する。この間、オンライン編集による時間の浪費は発生しない。
TECOの当時としては洗練されていた検索機能は、オフラインのFlexowriter端末では行番号が印字されず、編集内容でしか場所を指定できないという事情が影響している。各種ループ機能や条件分岐は、編集コマンドの紙テープで十分な編集機能を発揮するために必要とされたのである(このため、TECOは言語としてチューリング完全となった)。編集テープをなるべく短くするため、各編集コマンドはなるべく短くなるように設定された。
編集テープは一種のプログラムであり、他のプログラムと同様にデバッグを必要とする。従って、バッチ的な編集という当初の目的は、ちょっとした検索・置換でもさらなるデバッグを要するという問題に陥った。結局、TECOは「高価なタイプライタ」のようにオンライン編集に使われるようになった(とは言っても、TECOの方が機能が豊富で編集が容易であった)。最初のPDP-1バージョンは画面表示がなく、編集の途中の状態を見るには、編集テープ内に編集対象テキストをコンソールのタイプライタに印字するコマンドを挿入するしかなかった。
hello.c というファイルの内容が以下のようになっているとする:
int main(int argc, char **argv)
{
printf("Hello world!\n");
return 0;
}
これについて、"Hello" の代わりに "Goodbye" と表示したいとする。以下はそれを行うときのTECOのセッション例である。"*" はプロンプト、"$" は ESC のエコー表示である:
<pre>
EBhello.c$$                     バックアップ付きでファイルをリード/ライト・オープン
P$$                             最初のページを読み込む
SHello$0TT$$                    "Hello" を検索してその行を表示する
printf("Hello world!\n");    その行
-5DIGoodbye$0TT$$               5文字削除して、"Goodbye" を挿入し、その行を表示
printf("Goodbye world!\n");  修正された行
EX$$                            編集結果をファイルにコピーして終了
</pre>
プログラミング言語としてのTECOの文法は奇妙だが、非常に強力で、そのクローンはMS-DOSやUNIX上でいまだに利用可能である。TECOのコマンドは文字(制御文字もある)であり、プロンプトはアスタリスク「*」である。ESCキーを2回押下することでコマンドが完了し、画面にはドル記号「$$」で表示される。
TECOプログラムでは、大文字/小文字は区別されず、空白は無視される。ただし、タブは挿入コマンドであり、無視されない。
バッファ内の各行を行の先頭の文字に従ってソートする。この例ではGoto文を使用している。
!START! j 0aua               ! 先頭にジャンプし、1文字めをレジスタAにロード !
!CONT! l 0aub                ! 次の行の1文字めをレジスタBにロード !
qa-qb"g xa k -l ga 1uz '     ! A>B なら行を入れ替えて、フラグをレジスタZにセットする !
qbua                         ! B を A にロード !
l z-."g -l @o/CONT/ '        ! バッファに他の行があれば(CONTに)ループする !
qz"g 0uz @o/START/ '         ! 行入れ替えが起きた場合、最初からもう1回行う !
例1と同じことをするが、構造化プログラミングを使用している。
0uz                             ! 繰り返しフラグをクリア !
<j>B なら、行を入れ替えてフラグをセット !
qbua                            ! B を A にロード !
l .-z;>                         ! バッファに他の行があればループ !
qz;>                            ! 入れ替えが起きたときは最初に戻る !
TECOで書かれたBrainfuckインタプリタの例である。バッファの内容をBrainfuckプログラムとして実行する。
@^UB#@S/{^EQQ,/#@^UC#@S/,^EQQ}/@-1S/{/#@^UR#.U1ZJQZ\^SC.,.+-^SXQ-^SDQ1J#@^U9/[]-+<>.,/<@:-FD/^N^EG9/;>J30000<0@I//>ZJZUL30000J0U10U20U30U60U7@^U4/[]/@^U5#<@:S/^EG4/U7Q7;
-AU3(Q3-91)"=%1|Q1"=.U6ZJ@i/{/Q2\@i/,/Q6\@i/}/Q6J0;'-1%1'>#<@:S/[/UT.U210^T13^TQT;QT"NM5Q2J'>0UP30000J.US.UI<(0A-43)"=QPJ0AUTDQT+1@I//QIJ@O/end/'(0A-45)"=QPJ0AUTDQT-1@I/
/QIJ@O/end/'(0A-60)"=QP-1UP@O/end/'(0A-62)"=QP+1UP@O/end/'(0A-46)"=-.+QPA^T(-.+QPA-10)"=13^T'@O/end/'(0A-44)"=^TUT8^TQPJDQT@I//QIJ@O/end/'(0A-91)"=-.+QPA"=QI+1UZQLJMRMB\
-1J.UI'@O/end/'(0A-93)"=-.+QPA"NQI+1UZQLJMRMC\-1J.UI'@O/end/'!end!QI+1UI(.-Z)"=.=@^a/END/^c^c'C>