VTL(Very Tiny Language)はパソコンの黎明期(「パソコン」ではなく「マイコン」という言葉が一般的だった1970年代頃)に作られたインタープリタ型のプログラミング言語で,「マイクロBASIC」とも呼ばれます.
その特徴は,インタープリタ本体のサイズがわずか768バイト(1Kバイトの3/4)に収まるというコンパクトさです.
この言語はマイクロBASICとも呼ばれるように,通常のBASIC(Visual Basic等のモダンなBASICではない古典的なBASIC)と同様に行番号によりプログラムの流れをコントロールしますが,BASICよりもかなり機械語に近い低級言語といえます.
特に代入操作を基本としてプログラムを書くようになっており,プログラムカウンタやメモリマップドI/Oを直接操作するような感覚でプログラミングを行います.
このVTLという言語を知ったのは,自分が高校生の頃に学校の図書館に置いてあった古いASCIIという雑誌からでした.
それは1980年前後のマイコンブームの頃のもので,当時のCPUやメモリなどは驚くほど貧弱でしたが,誌面からはマイコンという新しいものに対する熱気が感じられて,自作のプログラムを紹介する記事も多く,非常に面白い内容でした.
そのような時代にVTLという言語は,CPUのクロックが500kHz(500,000Hz,念のため),RAMの容量が1Kバイト(1024バイト,同じく)のAltair680というマシン用に作られました.
この言語を知ったとき,そのシンプルさに惹かれて大変興味を持ちました.
なかなか自分で実装しようとまでは思いませんでしたが,AVR等の組み込み用CPUを使うようになり,この小さな言語をそれらの非力なCPUでも動かしてみたいと思ってVTLの処理系を作成してみました.
このVTLが過去にどれだけ普及したのかは分かりませんが,VTLを拡張したGAME(General Algorithmic Micro Expressions)という言語がASCII誌上で発表され,その後このGAMEで書かれた多くのプログラムがASCIIに掲載されました.
今(2008年12月)検索エンジンで調べてみると,Return of the Very Tiny LanguageというVTLを元にした処理系が見つかりました[6].また,いくつかのVTLに関する資料[5][7]も見つかりましたが,あまり多くの情報は見つけられませんでした.
ここでは,VTLの使い方を簡単に説明します.
VTLは通常の(古典的な)BASICと同様に対話的な編集・実行環境を持っています.
例えば,
?=23+45
と入力すると(行末でリターンキーを押します),"23+45"の計算結果である"68"が画面に出力されます."?"はユーザーターミナルを表す「システム変数」と呼ばれる特別な変数で,この"?"という変数に対して代入した値は画面へ出力されます.
ダイレクトモードでは,このように入力したステートメントがすぐに実行されます.
一方でプログラムモードでは,あらかじめメモリ上にプログラムを格納しておいて後で実行します.
プログラムをメモリ上に格納するには,ステートメントの前に行番号(1~65535の数字)と1つのスペースをつけて入力します.
例えば,
100 A=123 200 ?=A*2
と入力すると,「変数Aに123という値を代入して(100行目)」「変数Aの値に2を掛けた値を画面に出力する(200行目)」というプログラムをメモリに格納します. メモリ上に格納されたプログラムを実行するには,
#=1
と入力します(プログラムを先頭から実行するという意味で,BASICでいう"RUN"命令に相当します).すると,画面上には"246"と表示されるはずです.
プログラムリストを表示するには"0"と入力します(BASICでいう"LIST"命令に相当します).
またプログラム中の行を削除する場合は,その行番号だけを入力します(これは通常のBASICと同じです).
キーボードから一度に入力できる文字数は73バイトで,バックスペースキーで直前の1文字を削除できます.
74文字以上入力された場合やCTRL-U(68版VTLではShift-P,80版VTLでは"@")が入力されると,入力中の文がキャンセルされて改行されます.
VTLで扱うことのできる数値は,0~65535の範囲の数(符号無し2バイトの整数のみ)です.
VTLでは,次の4つの算術演算子が使えます:
+ | 加算 |
- | 減算 |
* | 乗算 |
/ | 除算 |
除算の結果の余りについては,後述する"%"というシステム変数で参照することができます.
また,次の3つの関係演算子が使えます:
= | 等しい |
< | 小なり |
> | 大なりまたは等しい |
">"は"≥"の意味で扱われます.
これらの関係演算子は,
条件が成り立てば"1"を,成り立たなければ"0"を返します.
例えば,"A=B=C"というステートメントは,変数BとCの値が等しければ変数Aに1を,そうでなければAに0を代入することになります.
VTLでは,演算子の間に優先順位は存在せず,左から順番に演算が行われます.演算の順序を変えたい場合は括弧"()"をつけます.例えば,"2+3*4"の結果は"20"となり,"2+(3*4)"の結果は"14"となります.
変数には,"A"から"Z"のアルファベット1文字を使うことができます.
配列変数は,1次元のものを1種類だけ使うことができます.n (n≥0)番目の配列変数は":n)"と記述します.例えば":X+3)=Y"のように使います.配列は後述するシステム変数"&"以降のメモリ領域を使いますが,メモリの上限を超えたかどうかの配列の添え字のチェックはしていないので注意が必要です.
いくつかの記号は特別な意味を持つ「システム変数」となっています.以下,VTLにおけるシステム変数について説明します.
VTLの文法について上記のように説明してきましたが,VTLの中身(実装)はもっと単純化されています(68版VTL,80版VTL,C言語版VTLの場合).
例えばステートメントは"X=Y"のように"="を使って書くことになっていますが,この文字はVTL内部では単に読み飛ばされているので,"="以外の文字を使うことができます.
また変数として使えるのは大文字のアルファベット26文字としていますが,実際の処理系では"["など他の文字も使えます.
")"を使えばコメントを記述できるとしていますが,これは")"を特別扱いしているのではなく,単にこの変数には何が入っていてもよいという取り決めをしているだけです.
"?"への代入による文字列の出力は特別扱いされており,実際は式の右辺がダブルクォーテーションで囲まれていれば,左辺(と"="の記号)は何でも構わないので,例えば'?="ABC"'と'AA"ABC"'は同じ意味になります.
VTLではエラーメッセージというものは存在せず,上記のように論理回路のDon't careのような扱いにより入力を一意に解釈して実行するようになっています.そのため仕様のとおりには動作しますが,仕様から外れた入力をした場合でも多くの場合何らかの動作をします.ただし将来の拡張や互換性(?)を考えると,仕様からはずれた使い方はお勧めできません.
今回は,C言語でVTLインタープリタを書きました.オリジナルの68版[1]やそれを移植した80版[2]はアセンブラで書かれていますが,移植性を重視してCで書きました.そのためコードサイズは少し大きくなりますが,様々なCPUで動かすことができます.
プログラムの作成は,文献[2]が大変参考になりました.この文献では,80版VTLのソースコードが詳しく解説されています.
今回作成したC言語版VTLはプログラムの基本的なロジックは同じなので,80版VTLと完全に互換性があると思われます.
また80版は68版と互換性があるようなので,このC言語版はオリジナルの68版とも互換性があると思われます.昔の雑誌に載っていたVTL用のプログラムをこのC言語版で動かしましたが問題なく動作しました.
メモリマップは,この表のようになっています.基本的に68版や80版と同じです.
いくつかのCPUやOS上でこのC言語版VTLを動かしてみました.「AVR版」「H8版」「UNIX版」「MinGW版」があり,それぞれソースファイルに含まれる"avr/","h8/","unix/","mingw/"というディレクトリに移動してmakeでコンパイルできます.
以下,各機種ごとの説明です.
上記のCPUやOS以外でも,system.c中のinitl(),getchr(),putchr()の3つの関数を用意すれば,このC言語版VTLを動作させることができます.initl()は(必要であれば)機種に依存した初期化処理,getchr()は(バッファリングを行わない,エコー出力を行う)1文字入力,putchr()は(バッファリングを行わない)1文字出力です.詳しい内容は,AVR版,H8版,UNIX版,MinGW版のsystem.cをご参考にしてください.
VTLで書かれたプログラムの例を紹介します. プログラムリストのファイルはUNIX版やMinGW版で用いられているメモリイメージのフォーマットにもなっているので,ファイルをダウンロードして"vtl.img"という名前で保存し,VTLを実行後に"#=1"と入力すると,プログラムを動かすことができます.
階乗を計算するプログラムです.
再帰呼び出しの例となっています.
プログラムを実行して数字を入力すると,入力された数の階乗の値を表示します.
有名な数当てゲームです.
コンピュータが生成した4桁の数字(1234,9753など)を当てるのが目的です.4つの数字の中に同じ数字は含まれません.
プログラムを実行後,4桁の数字を予想して入力すると"1H2B"のようなヒントが返されます.
これはHitが1つ,Blowが2つという意味です.入力した数字が,コンピュータが生成した数字の中に出現はするけれども桁の位置が違う場合はBlow,桁の位置も正しい場合はHitとなります.
このヒントを頼りに,コンピュータが生成した数値を当てます.
正解の数字を入力すると"4H0B"と出力して,プログラムが終了します.
15パズルです. 下の図のように左上から0で始まり,右下が空白になるように数字を移動します.
0123 4567 89AB CDE
10~15の数字はA~Eのアルファベットで表示されます.
"2","8","6","4",の各数字を入力すると,それぞれ空白の上,下,左,右にある数字を空白の位置へ移動します(テンキーで操作して下さい).
上の図のように数字を揃えるとゲームが終了します.
マインスイーパです.
数字の"8","2","4","6"でカーソル("*"で表示されている)を上,下,左,右に動かし,スペースキーでカーソルの位置の地雷をチェックします.
地雷をチェックすると表示される数字は,カーソルの位置を中心として,その上下左右と斜め方向に隣接する計8個のマス目の中に,いくつの地雷が存在するかを表しています.もし地雷のあるマス目をチェックしてしまった場合はゲームオーバーです.
地雷が存在するマス目以外の全てのマス目をチェックすれば,ゲーム終了です.
マス目の数や地雷の数は,プログラムの先頭にある変数NとMの値を変えれば変更できます.
ASCII誌上では,次のようなVTL用のプログラムが発表されています.
とてもシンプルな言語ですが,結構複雑なプログラムが記述できることがわかります.
※エンサイクロペディア・アスキーは月刊雑誌のASCIIを数冊分まとめたもので,内容は雑誌の記事と同一です
※上記の参考資料の多くは絶版で入手が難しいと思われますが,大きな公立図書館や大学図書館では置いているところがあると思います(検索→NACSIS Webcat).