>トップ
石田晴久先生が近代科学社刊『マイクロコンピュータプログラミング入門』(藤原博文氏による書評)で紹介されている、東京版 Tiny BASIC インタプリタを、Ruby でシミュレーションするものです(注: 東京版 Tiny BASIC は、「東大版」Tiny BASIC とは別物です)。エミュレーションはしていませんので、再現度はそれなりです。特に変数まわりは Ruby の配列にマッピングしてしまったので、オリジナルの、整数値が 32767 を越えるとラップアラウンドする、配列を使って PEEK・POKE と同じことができるなどの動作は再現しません。
(竹岡さんからの情報ですが、東大版 Tiny BASIC(パロアルト版ベース)は、整数のオーバフローはエラーになる、配列をPEEK・POKEの代用にする、といったことはできない、という仕様だ、とのことです。パロアルト版のソースは竹岡さんのサイトに ftp://www.takeoka.org/pub/micro/pbas.asm )
東京版(および、元となったテキサス版)Tiny BASIC の一番の特徴である、中間言語で書かれたインタプリタと、それを実行する内部インタプリタ、という構成を再現することを目標としました。
書籍内の全サンプルが動作することを確認しています。正常系の実装は済んでいますが、エラー処理などには手を付けていません。BASIC でエラーになると、Ruby の例外としてインタプリタごと止まります。
誤 → 正
オリジナル | ||||
---|---|---|---|---|
行番号 | 長さ(n) | 文の本体 | CR | 次の行番号... |
2 | 1 | ← n - 2 → | 1 | |
以下のように変更 | ||||
行番号 | 長さ(n) | 文の本体 | LF | 次の行番号... |
2 | 1 | ← n - 1 → | 1 |
ルーチンの細かい動作は適宜修正
CY=1 で戻る (可能性のある) MCALL の次の命令は TEST にできない (ふつうJUMP命令)
MASK とは何か? 0d14h 番地。プリンタへの出力を許可/停止するもの
TSTL ルーチンの副作用により、DE (テキストポインタ) は LINE に設定される
TSTL ルーチンの最初のほうでは SKIP (空白の読み飛ばし) をしているのだから、INSRT ルーチンでもそうしたほうがよさそうに思われる。' 10 PRINT "A"' とか入力された時におかしくなりそう
引数なしの LIST はマルチステートメントにできない( LIST : RUN とかできない。そういう仕様。LIST の直後が改行でなくコロンだとすると、コロンを引数と見て、式として解析しようとして失敗する)
NXT ルーチンは、コマンド実行の時(CURLB == 0)は内部インタプリタをコマンド入力に飛ばすだけ。プログラム実行中の時は、テキストポインタが改行を指しているものとして、1バイト読み飛ばしてから、次の行の実行準備をしている。これは、内部インタプリタが改行を認識した後の動作としてはバグ。すなわち、演習問題 1.5 のように、引数なしの LIST をプログラム中から実行した場合、引数なしの PRINT<改行> や PRINT ...;<改行> の場合である
次の行が、先頭に空白を置かないで詰めて書かれている場合は先頭の1文字が無視される。また、エラーが起きた場合の表示など、インタプリタが認識している行番号がおかしくなっている(はずである)
SKIP ルーチンは戻るときにテキストポインタが指している値を A レジスタに残す。これを使っているところがいくつかある
DONE ルーチンは、テキストポインタが改行を指していたら単に戻る(ほとんどの場合、次の中間言語命令は MCALL NXT)である。コロンだったら、1バイト進めて内部インタプリタをラベル EXEC に飛ばす。どちらでもなければエラー(実装では改行でも1バイト進めるように修正)
DONEX ルーチンは、DONE の、コロンの次の命令は実行しない(GOTO 文など)ためのバージョンで、改行またはコロンを指していたら戻る。どちらでもなければエラー
END と STOP は、中身同じ
END も STOP もせず、最後の行まで実行し終わった場合の処理が書いてないので、そういうことになると暴走する?(実装では NXT1 で検出するよう修正)
TSTF で CR やスペースのチェックをしてるが無意味ではないか?
TSTN ルーチン中の '(' との比較は必ず失敗する(その時点で A には '0'〜'9' 以外が入っていることはありえない)。キャリーフラグを立てる(数字を見つけているので、キャリーフラグを立てて TSTN から戻る必要がある)以外に用をなしていない
GOSUB の後は改行がくることを前提にしている。コロンでつないでマルチステートメントになっていると誤動作するないしエラーになる(かもしれない)。改行をテキストポインタが指していて、NXT が 1 バイト空読みするのでうまく動く(実装ではマルチステートメント対応に修正)
FOR ルーチンについての説明で、FOR の後にあるコロンか改行の次のテキストアドレスを保存するとなっているが、それだと NEXT で戻ってくる時、コロンの次であれば文の先頭を、改行の次であれば行の先頭の行番号の入っているワードをテキストアドレスが指していることになる。しかし、そのような状態から正しく実行再開する方法はない(行番号のバイト並びは 0 と ffff 以外の任意の並びがありうるので、識別方法はない)ので、これはおかしい(再開後必ず 1 バイト戻すなどする必要がある。実装では改行かコロンを指すポインタを保存するように修正。この状態からなら DONE で正しく実行再開できる)
p.6 (5) PRINT 文「: による文の区切りのところで復帰改行をさせたくないときには : の代わりに ! 記号を打っておく」実装を見る限り、「の代わりに」ではなく、「の直前に」である(次項参照)
p.14 の「次の例をみていただきたい」のように、PRINT文の ! のあとに文をつなげるとエラーになるはずである(中間言語で、! を認識したあとで DONE ルーチンを呼んでいるため。16 進変換の INPUT 文のように、! の直後は改行にするか、あらためてコロンを置く必要がある
p.17-18 文字型データの入出力 の例はよくわからない
TODO グローバルなワークエリアの詳細と、それぞれが初期化されるタイミング