CLC-INTERCALの入出力がわかんないよぉ…😢
ということで、この記事で解説します。なお、この記事の内容ははCLC-INTERCAL 1.-94.-2のDocsにある、doc/html/input_output.htmlの和訳っぽいものです。また、CLC-INTERCAL 1.-94.-2のライセンスをCOPYINGファイルで確認したところBSD 3-clauseライセンスっぽいものでしたが、それは私の主観による認識です。
その前に:用語の定義
INTERCALにおいて、「標準入力などからの値の内容を読み込み、変数にその値を書き込む」命令がWRITE INであり、「変数に格納されている値を読み込み、これを標準出力などに書き出す」命令がREAD OUTとなっています。この記事ではそれに準じ、前者を「書き出し」、後者を「読み込み」と定義します。
読み書きの方法は何種類?
INTERCAL-72からお越しの方は、CLC-INTERCALではローマ数字の他に文字列も取り扱えるということに感動するでしょう。C-INTERCALからの方は、配列での文字列の取り扱いが違う方式であることに驚かれることでしょう。更には、CLC-INTERCALでクラスが導入されたことについては初耳の方が多数いらっしゃるでしょう。
数値読み書き
CLC-INTERCALでは1spotや2spotにおいて適用されます。
CLC-INTERCALでの数値読み込みは他のバリエーションのINTERCAL同様、各桁を大文字で英単語で綴った空白区切りの行により可能となっています。CLC-INTERCALでは国際化のため英語以外も使用可能です。
一方書き出しはローマ数字で表されます。なお、大きな数値については注意されたい事項があります。それは、百万以上の桁については各桁にバックスラッシュを前置することです。C-INTERCALでは上部に線を引くこととは異なっています。
読み書きはどちらも、行単位で行われます。
英数字読み書き
この方法はtail配列に適用されます。
CLC-INTERCALでは、内部の文字コードとして拡張Baudotを採用しています。この文字コードは、5ビットのデータを単位とし、状態を持っています。通常のBaudotでは英字と図の2状態がありますが、CLC-INTERCALのBaudotでは、大文字、小文字、図、記号の4状態があります。
この読み書きの方法においては、行単位で行われます。書き出し命令の際には元のデータとなる1行をASCII(厳密にはISO-8859-1など)文字列として解釈し、これを拡張Baudotに変換して配列の各要素に値を格納します。ただし、命令を実行する前に、事前に書き出される文字数以上の要素数が確保されていなければエラーとなります。また、書き出される文字列のなかに拡張Baudotに変換できないものがあれば同様にエラーとなります(アナゴルで確認済み)。なお、末尾の改行文字は破棄されます。
配列に書き出しがなされると、最初の2つの要素で最初の状態を指定していることがわかりました。それゆえ3要素目が最初の文字の実態となります。また、文字の種類が変わる際にのみ状態変更文字が格納されます。
書き出しの際、下位5ビットが元のBaudot文字に該当します。ソースコードBase/INTERCAL/Charset/Baudot.pmにおけるascii2baudotサブルーチンから確認したところ、文字列は厳密には0x40から0x5fまでの値で構成された配列になることがわかりました。
読み込みの場合は各要素において下位5ビットがBaudot文字として解釈され、これがASCIIに変換されます。最後の文字が出力されると、改行が付け足されます。なお、アナゴルで使用されている実装はデフォルトの状態が大文字となっていることが確認されております。
バイナリ読み書き
任意のバイト列を読み書きする唯一の方法がこれです。この方法はハイブリット配列に適用されます。
書き出しにおいては、書き出される対象の配列の長さだけのバイト列が書き出されます。この際、最初のバイトから順に次のアルゴリズムにしたがって配列の各要素に順に書き出されます:
現在読まれているバイトを.2、その前のバイトを.1とする。ただし最初のバイトの前のバイトは#172とする。なお、現在読まれているバイトがEOFの場合は手順7から続ける。
.3<-.2~.1
.4<-(.2のビットを反転させたもの)~(.1のビットを反転させたもの)
:5<-.3¢.4
:5の上位16ビットをランダムなものとする。ただしそのうち少なくとも1つのビットは1である。
この結果:5の内容が書き出される値である。
バイトを読み込んでいるところにおいてEOFに達した場合は#0が書き出される。
上記のアルゴリズムからわかる通り、EOFではない場合はゼロ以外の値になることが保証されます。
一方読み込みにおいてはこのアルゴリズムの逆順となるように実行されます。書き出し同様に最初のバイトが読み込まれる際においてはその前は172が読み込まれたものと見なされます。なお、#0が格納されている要素は無視され、何も読み出されません。
ところで、リファレンス文書において「将来、ビットの分布が十分無作為でなければならない可能性がある」という記載がなされておりますが、現段階ではその必要はございません。
クラス読み書き
クラス名単独で読み書きをしようとしても、何も起きません。しかし、クラスレジスタはファイルハンドラと関連付けられており、そのクラスを記載することで読み書き命令において使用するファイルハンドラを指定できるようになります。例えば、
DO READ OUT .1 + @3 + .2 + @2 + .3
という文では、.1が標準読み込みに読み込まれ、.2が標準スプラットに読み込まれ、.3が標準書き出しから書き出されます。
という機能をアナゴル鯖で試したのですが、上手くいかなくてコードゴルフとしての使用ができませんでした。まだまだバグ改善が必要です。
追記 できちゃった:
DO.1<-#1DO.2<-#2DO.3<-#3
DOREADOUT.1+@3+.2+@2+.3
DOREADOUT.1+.2+.3
ただし標準書き込みに次を与えること:
ONE OH OH
結果、
追記終わり
おわりに
いかがでしたか?本稿では皆様にCLC-INTERCALを少しでも知っていただきたく、そして少しでも私の対戦相手となっていただきたくて入出力もとい読み書き機能を紹介しました。
全てCLC-INTERCALが廃れてしまった所為です。