2020.7.24
前へ
次へ
ホームページトップへ戻る

[新連載]復活!TINY BASIC
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
すべてはここからはじまりました。
中日電工も。
40年前を振り返りつつ新連載です。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜



[第46回]


●PRTSTG,QTSTG

前回のところで「QTSTRとPRTNUMはいずれ説明します」と書きました。
QTSTGについてプログラムリストを確認していて、これはやっぱり前回の続きとして説明しておいたほうがよいように思えましたので今回説明してしまうことにしました。
[第27回]では「PRTSTGについていずれ説明します」と書いています。
PRTSTGはQTSTGの中でCALLされていますから、この機会にPRTSTGも説明をしてしまいます。
PRTNUMはちょっと複雑です。
ですのでPRTNUMは次回書くことにします。



まずはPRTSTGです。
PRTSTGは文字列表示サブルーチンです。
DEで示すアドレスにある文字コードから表示を開始します。
’0D’コードを見つけるとそこで改行したあとリターンします。
PRTSTGをCALLするときにあらかじめAレジスタに文字コードを入れておくことで、その文字コードの直前までの文字列を表示してリターンすることができます。
この機能によって、意図しないときに文字列の途中で表示が中止されてしまう可能性が出てきます。
そこでその機能を使わない場合にはPRTSTGをCALLする前に文字コードとしては使わない値としてAレジスタに00を入れておくようにします。
AレジスタはPRTSTGの中で文字を表示するために使いますからPRTSTGの先頭でBレジスタに移されます。
PRTSTGをCALLするとそれ以前のBレジスタの値が変わってしまうことに注意が必要です。
PS1:でDEレジスタで示されるメモリアドレスから文字コードがAレジスタに読み込まれます。
その後DEレジスタは+1されます。
そしてAレジスタの値とBレジスタが比較されます。
一致した場合はその文字は表示されずにそこでリターンします。
一致しなかった場合にはRST 2が実行されます。
RST 2は1文字表示サブルーチンです。
[第11回]で少しだけ書いていますが詳しい説明はしていません。
文字表示はハードウェアに直接関わるところですのでオリジナルのTINY BASICのその部分をそのまま説明することには余り意味がありません。
ここは「中日電工版」TINY BASICではUSBを介してWindowsのコマンドプロンプト画面に表示することになるため、オリジナルのその部分を書き換えました。
Windows側の機能も含めて考えることになりますから、その部分についてはもう少し先のところで説明をしたいと思っています。
ですので今のところはRST 2をCALLするとAレジスタに入れた文字コードに対応する文字が画面に表示される、ということだけを理解しておいてください。
1文字表示後に’0D’かどうかをチェックしています(アドレス0566 CPI CR)。
’0D’ならそこでリターンします。
’0D’以外ならPS1:にジャンプして文字列表示を続けます。

次はQTSTGです。
QTSTGは ” ” か ’ ’ で囲まれた中の文字列を表示します。
最初に RST 1で ”(文字コード22)をチェックしています(アドレス056C RST 1)。
RST 1は前回も説明をしていますのでそちらを参照してください。
一致した場合には056Fにジャンプします。
不一致の場合には057E(QT3:)にジャンプします。
以下一致した場合の056Fからの処理について説明をします。
Aレジスタに22( ” の文字コード)を入れてPRTSTGをCALLします。
RST 1の実行によってDEの値は ” の次のアドレスまで進んでいますから、PRTSTGの実行によってそのアドレスからAレジスタに入れた値22( ” の文字コード)がみつかるところまでの文字列が表示されます。
” は表示されませんがDEが示すアドレスはその次のアドレスになります。
実はその後で巧妙なテクニックが使われています。
ここは危険なテクニックです。
文字列表示後のアドレス0574で0Dコードをチェックしています(CPI 0D)。
本来はQTSTGをCALLしたもとのルーチンで表示後のエンドコードのチェックを行なうようにするところをここで済ませてしまっています。

0576 POP H
0577 JZ RUNNXL
は’0D’だったときの処理です。
その次からの
057A QT2:INX H
057B INX H
057C INX H
057D PCHL
は’0D’ではなかったときの処理です。
実はいずれもQTSTGサブルーチンの処理ではなくてQTSTGをCALLしたもとのプログラムの処理なのです。
本来は書いてはならない「禁断のプログラミング」です。

” ” または ’ ’ の文字列表示の後に0Dコードがあるということは、つまりPRINT文の最後に’0D’コードがあるということで、それは行の終わりを意味していますから、RUNNXLにジャンプします。
RUNNXLは[第37回]で説明をしました。
次の行を実行するルーチンです。
しかしQTSTGはサブルーチンですから、ここからいきなりメインルーチンのRUNNXLにジャンプするとスタックが食い違ってしまいます。
そこでPOP Hをダミー命令として実行してスタックを合わせています。

その次の’0D’ではなかった場合の処理なのですが、これがまた実に見事なプログラムになっています。
上で実行したPOP Hは上ではダミー命令として使ったのですが、ここではそれを意味のある命令として利用しています。
POP Hを実行することで、HLにはQTSTGをCALLしたもとのプログラムのCALL QTSTGの次のアドレスが入ります。
QT2:からの3ステップでそのアドレスが+3されます。
つまりHLの値はもとのプログラムのCALL QTSTGの次の3バイトを飛ばした次のアドレスになります。
そして最後にPCHLが実行されます。
HLが示すアドレスへのジャンプです。
一体なにをやっているのでしょう。
それをはっきりさせるためにはQTSTGがどこでCALLされているかを知る必要があります。

QTSTGはPRINTルーチンとINPUTルーチンでそれぞれ1回CALLされています。
そのほかではCALLされていません。
下はPRINTルーチンでQTSTGをCALLしているところです。



PRINTについては前回説明しました。
アドレス01A3のCALL QTSTGの結果、文字列ではなかった場合には次のJMP PR8が実行されます。
PR8:では数値を検出して表示します。
しかしCALL QTSTGの結果、文字列だった場合にもJMP PR8が実行されてしまっては困ります。
文字列の表示の場合には ” ” か ’ ’ の中の文字列が表示されたあとDEに後ろの ” か ’ の次のアドレスが入った状態ですからそのあとすぐに数式のチェックをするわけにはいきません。
その後ろには ,(カンマ)があるかそれとも ; か0Dコードがあるはずです。
つまりCALL QTSTGの結果、文字列だった場合には次のJMP PR8の3バイトを飛ばしてPR3:に行く必要があります。
そうするためにQTSTGのQT2:から後ろのプログラムがあるのです。
実に見事ではありますが、恐ろしいプログラムです。
このことを知らずに不用意にプログラムを書き換えたりすると原因不明の暴走をしてしまうことになります。
あな、おそろしや。

それではもう一箇所INPUTのほうはどうでしょうか。
下はINPUTルーチンでQTSTGをCALLしているところです。



INPUTについてはまだ説明をしていませんが、QTSTGをCALLしている部分についてはPRINTと同じです。
アドレス02CEのCALL QTSTGの結果、文字列ではなかった場合には次のJMP IP2が実行されます。
IP2:では変数名をチェックしてその変数に数値をインプットする処理が行なわれます。
文字列だった場合にもその次に変数名があればその変数に数値をインプットする処理が行なわれますが変数名ではなくて ,(カンマ)が置かれてその次に変数名を置く場合もありますから、IP2:とは少し違う処理になります。
その場合にはJMP IP2を飛ばしてその次のRST 7以下を実行する流れになります。
ここでもやはりCALL QTSTGの次の3バイトを飛ばしてその次のアドレスにジャンプすることになります。
うむむ。
これはもう名人芸でありましょう。
よくぞこのような恐ろしいプログラムを思いついたものだと感心してしまいます。

感心しているうちに時間がなくなってしまいました。
まだ説明の途中ですが、この続きは次回にすることにいたします。

復活!TINY BASIC[第46回]
2020.7.24upload

前へ
次へ
ホームページトップへ戻る