%第1版第15刷 P.65-72
3章 BASICの内部構造
BASICをより高度に利用するためには、BASICインタプリタがどのようにプログラムを管理し実行しているか、ということに関する知識が不可欠なものとなります。ここでは、そのようなBASICの内部構造について説明します。
3.1 ユーザーエリア
ユーザーエリアの下限アドレスは、MSX1ではRAM容量が8K, 16K, 32K, 64Kといろいろであったため個々に異なっていましたがMSX2の場合RAM容量は最低でも64Kなので、ユーザーエリアの下限アドレスはつねに8000H番地となります。なお、これはBOTTOM(FC48H)の内容から知ることができます。
ユーザーエリアの上限アドレスは、ディスクが実装されていない場合F380H番地ですが、ディスクが実装されている場合(DISK-BASIC使用時)はドライブ数やディスク容量などにより変わってきます。これはリセット後CLEAR文を実行する前のHIMEM(FC4AH)の内容から知ることができます。主なディスク装置を実装した時のユーザーエリアの上限アドレスを表2.19に示します(この値は編集部独自の調査によるもので、同じ型番の製品でも値が異なる可能性あり)。
ディスクドライブ名 | メディア | ドライブ数 | ユーザーエリアの上限 |
---|---|---|---|
ディスクなしの状態 | ―― | ―― | &HF380 |
ソニー(HB-701FD) | 1DD | 1 | &HE68C |
2 | &HE276 | ||
ソニー(HBD-30W) | 2DD | 1 | &HE48D |
2 | &HDE77 | ||
東芝(HX-F100) | 1DD | 1 | &HE68E |
2 | &HE278 | ||
ビクター(HC-F303) | 1DD | 1 | &HE68F |
2 | &HE279 | ||
ヤマハ(FD-05) | 2DD | 1 | &HE48D |
2 | &HDE77 | ||
松下(CF-3300) | 2DD | 1 | &HE48D |
2 | &HDE77 |
注)ドライブ数の"1"のものは、1ドライブ実装の時「CTRLキー」を押しながらリセットした場合。
表2.19 主なディスク装置によるユーザーエリアの違い
MSXを起動した時のメモリの状態を図2.6に示します。
なお、MSX2でプログラムを作る場合、ユーザーエリアの上限アドレスとしては一番低い「2DD 2ドライブ」のディスク装置の実装を念頭に置いて、8000H番地〜DE3FH番地に作成するよう推奨されています。しかし、ディスクのワークエリアがさらに大きくなる可能性もあるので、アプリケーションプログラムはかならずHIMEMの内容を確かめ、最悪の場合でも暴走しないように対処してください。対処の方法としては、次のようなものが考えられます。
1. ワークエリアをリロケータブルにする
2. ワークエリアをBOTTOMから確保する
3. ドライブの数を減らすように指示して停止する
MSXはディスクが実装されている場合もSHIFTキーを押しながらリセットすることにより、ディスクを切り離すことができます。また、ディスクが1ドライブだけ実装されている時に普通に起動すると、MSXは2ドライブ分のディスクのワークエリアをとってしまうので(主に2ドライブのシミュレータに使用される)、このような時はCTRLキーを押しながらリセットすることにより、1ドライブ分のワークエリアのみ確保して起動させることが可能です。これらを行うことによって、少しはユーザーエリアを増やすことができます。
3.2 ユーザーエリアの詳細
BASIC使用時にユーザーエリアがどのように使われているかを図2.7に、それらのエリアがどこから始まっているかの情報を持つワークエリアを表2.20に示します。なお、このワークエリアは読み出し専用となっているため(イニシャライズルーチンがリセット時に設定する)、書き換えた場合の動作に関しては保証されません。
エリア名 | 開始アドレス | 終了アドレス |
---|---|---|
ユーザーエリア | [BOTTOM(FC48H)] | リセット時の[HIMEM(FC4AH)]-1 |
プログラムエリア | [TXTTAB(F676H)] | [VARTAB(F6C2H)]-1 |
単純変数エリア | [VARTAB(F6C2H)] | [ARYTAB(F6C4H)]-1 |
配列変数エリア | [ARYTAB(F6C4H)] | STREND(F6C6H)]-1 |
フリーエリア | [STREND(F6C6H)] | [SPレジスタ]-1 |
スタックエリア | [SPレジスタ] | [STKTOP(F674H)]-1 |
文字列領域 | [STKTOP(F674H)] | [MEMSIZ(F672H)]-1 |
(文字列領域の空エリアの先頭) | [FRETOP(F69BH)] | |
ファイルコントロールブロック | [MEMSIZ(F672H)] | [HIMEM(FC4AH)-1] |
マシン語領域 | [HIMEM(FC4AH)] | ユーザーエリアの終わりまで |
表2.20 各エリアの開始と終了アドレスを持つワークエリア
各ユーザーエリアの役割を以下に示します。
● BASICプログラムエリア
BASICで作成したプログラムは、ユーザーエリアの下限アドレス(MSX2では8000H番地)から格納され、その大きさはプログラムの量とともに変化します。
● 変数領域
変数領域はBASICプログラムエリアのすぐ後ろに位置しており、プログラム実行時に使用された変数に関して、その名前や値の保存のため確保されます。この時の変数の格納形式を図2.8(単純変数の場合)、図2.9(配列変数の場合)に示します。なお、配列変数をDIM文で宣言せずに使用すると添字が10の配列としてエリアが確保されます。ただし、4次元以上の配列はかならず宣言する必要があります。
● フリーエリア
プログラムエリアや変数領域が大きくなったり、スタックが多くなって、フリーエリアがなくなると“OUT OF MEMORY”エラーになります。なお、BASICのFRE関数でPRINT FRE(0)を評価することにより、その大きさを知ることができます。
● スタックエリア
BASICが使用するスタックエリアです。GOSUB命令やFOR命令などの実行時に上位アドレス側から順に使用されます。
● 文字列領域
文字列変数の内容を保存するために使用される領域で、上位アドレス側から順に使用されていきます。なお、この領域の大きさはBASICのCLEAR文の第1パラメータで指定することができ、省略時は200バイトの大きさで確保されます。このエリアがすべて使われてしまうと“OUT OF STRING SPACE”となります。BASICのFRE関数でPRINT FRE("")を評価することにより、残りの領域の大きさを知ることができます。
● ファイルコントロールブロック
ファイルの情報を保存する領域で、1ファイルごとに10BH(267)バイト分の領域が取られます。ファイルいくつ分の領域を確保するかはBASICのMAXFILES文で指定でき、リセット時はファイル1つ分(MAXFILES=1)の領域が取られています。しかし、それとは別にSAVE, LOAD命令のために、常時かならず1つ分の領域が確保されているので、実際にはこれも含めて2つ分の領域が確保されていることになります。ファイルコントロールブロックの形式を表2.21に示します。
変位 | ラベル | 意味 |
---|---|---|
+0 | FL.MOD | ファイルがオープンされたモード |
+1 | FL.FCA | BDOS用FCBへのポインタ(Low) |
+2 | FL.LCA | BDOS用FCBへのポインタ(High) |
+3 | FL.LSA | バックアップキャラクタ |
+4 | FL.DSK | デバイスナンバー |
+5 | FL.SLB | インタープリタが内部で使用 |
+6 | FL.BPS | FL.BUFの位置 |
+7 | FL.FLG | いろいろな情報をもつフラグ |
+8 | FL.OPS | 仮想的なヘッドの位置 |
+9〜 | FL.BUF | ファイルバッファ(256バイト) |
表2.21 ファイルコントロールブロック(FCB)の形式
● マシン語領域
マシン語プログラムを扱ったりメモリを直接操作する場合の領域です。これらを行う場合は、CLEAR命令によって、あらかじめこの領域を確保しておく必要があります。
● ディスクのワークエリア
ディスクが実装時に取られるワークエリアを図2.10に示します。この領域はディスクが実装されていない場合はまったく存在しませんので注意してください。なお、図中右のラベルは、そこにこのアドレスの情報があることを意味します。
3.3 BASICプログラムの格納形式
プログラムはメモリ上に図2.11のような形式で記憶されており、その内容には以下のような意味があります。
● リンクポインタ
次の行へのテキストポインタが絶対アドレスで書かれています。
● 行番号
文字通りプログラムの行番号が格納されており、通常は0〜65529(0000H〜FFF9H)の値が入ります。メモリを直接操作することにより65530以上の行番号を作ることも可能ですが、LISTコマンドはその行以降を表示しません。
● テキスト
ここにプログラム本体が中間コード形式で格納されています。中間コードに変換されるものは、予約語(キーワード)、演算子、数値で、その他のもの(変数名や文字列定数など)はキャラクタコードの形で格納されます。中間コードを表2.22に、テキスト中の数値形式を図2.12に示します。
キャラクタコードについては、巻末の付録を参照してください。なお、グラフィックキャラクタは「CHR$(1)+(グラフィックキャラクタコード+64)」の2バイト(2文字分)で格納されますので、グラフィック文字を取り扱う時には注意が必要です。
> | EE | CMD | D7 | ERR | E2 | LIST | 93 | PAINT | BF | SPRITE | C7 |
= | EF | COLOR | BD | ERROR | A6 | LLIST | 9E | PDL | FFA4 | SQR | FF87 |
< | F0 | CONT | 99 | EXP | FF8B | LOAD | B5 | PEEK | FF97 | STEP | DC |
+ | F1 | COPY | D6 | FIELD | B1 | LOC | FFAC | PLAY | C1 | STICK | FFA2 |
- | F2 | COS | FF8C | FILES | B7 | LOCATE | D8 | POINT | ED | STOP | 90 |
* | F3 | CSAVE | 9A | FIX | FFA1 | LOF | FFAD | POKE | 98 | STR$ | FF93 |
/ | F4 | CSNG | FF9F | FN | DE | LOG | FF8A | POS | FF91 | STRIG | FFA3 |
^ | F5 | CSRLIN | E8 | FOR | 82 | LPOS | FF9C | PRESET | C3 | STRING$ | E3 |
\ | FC | CVD | FFAA | FPOS | FFA7 | LPRINT | 9D | 91 | SWAP | A4 | |
ABS | FF86 | CVI | FFA8 | FRE | FF8F | LSET | B8 | PSET | C2 | TAB( | DB |
AND | F6 | CVS | FFA9 | GET | B2 | MAX | CD | PUT | B3 | TAN | FF8D |
ASC | FF95 | DATA | 84 | GOSUB | 8D | MERGE | B6 | READ | 87 | THEN | DA |
ATN | FF8E | DEF | 97 | GOTO | 89 | MID$ | FF83 | REM | 3A8F | TIME | CB |
ATTR$ | E9 | DEFDBL | AE | HEX$ | FF9B | MKD$ | FFB0 | RENUM | AA | TO | D9 |
AUTO | A9 | DEFINT | AC | IF | 8B | MKI$ | FFAE | RESTORE | 8C | TROFF | A3 |
BASE | C9 | DEFSNG | AD | IMP | FA | MKS$ | FFAF | RESUME | A7 | TRON | A2 |
BEEP | C0 | DEFSTR | AB | INKEY$ | EC | MOD | FB | RETURN | 8E | USING | E4 |
BIN$ | FF9D | DELETE | A8 | INP | FF90 | MOTOR | CE | RIGHT$ | FF82 | USR | DD |
BLOAD | CF | DIM | 86 | INPUT | 85 | NAME | D3 | RND | FF88 | VAL | FF94 |
BSAVE | D0 | DRAW | BE | INSTR | E5 | NEW | 94 | RSET | B9 | VARPTR | E7 |
CALL | CA | DSKF | FFA6 | INT | FF85 | NEXT | 83 | RUN | 8A | VDP | C8 |
CDBL | FFA0 | DSKI$ | EA | IPL | D5 | NOT | E0 | SAVE | BA | VPEEK | FF98 |
CHR$ | FF96 | DSKO$ | D1 | KEY | CC | OCT$ | FF9A | SCREEN | C5 | VPOKE | C6 |
CINT | FF9E | ELSE | 3AA1 | KILL | D4 | OFF | EB | SET | D2 | WAIT | 96 |
CIRCLE | BC | END | 81 | LEFT$ | FF81 | ON | 95 | SGN | FF84 | WIDTH | A0 |
CLEAR | 92 | EOF | FFAB | LEN | FF92 | OPEN | B0 | SIN | FF89 | XOR | F8 |
CLOAD | 9B | EQV | F9 | LET | 88 | OR | F7 | SOUND | C4 | ||
CLOSE | B4 | ERASE | A5 | LFILES | BB | OUT | 9C | SPACE$ | FF99 | ||
CLS | 9F | ERL | E1 | LINE | AF | PAD | FFA5 | SPC( | DF |
表2.22 中間コード一覧表
数値は予約語や変数名との区別をつけるために“識別コード”と呼ばれる番号が割り付けられており、それを見ることで後に続く値がどのようなものかわかるようになっています。
2バイトの数値の場合は、上位と下位バイトが逆に格納されます。符号付き数値については、識別コードの前に+または-の中間コードが置かれるのみであり、数値自体はかならず正の数で記憶されます。浮動小数点表記法についてはおおむね巻末のマスパック(Mathematical Package)の説明と同じですが、上記のように数値はかならず正の数で記憶される点に注意してください。2進法(&B)については、識別コードは割り当てられておらず、アスキーコードそのままの形で記憶されます。