BASICをより高度に利用するためには、BASICインタープリタの内部構造に関する知識が不可欠です。この章では、BASICの内部構造について説明します。
4.1 ユーザーエリア
ユーザーエリアの下限アドレスは、MSX1ではRAM容量が8K、16K、32K、64Kといろいろだったため異なっていましたが、MSX2の場合、RAM容量は最低でも64Kなので、ユーザーエリアの下限アドレスは常に8000H番地です。なお、これは【BOTTOM(0FC48H)】の内容から知ることができます。
ユーザーエリアの上限アドレスは、ディスクが実装されていない場合、F380Hですが、ディスクが実装されている場合(Disk BASIC使用時)はドライブ数やディスク容量などにより変わります。これは電源投入後、CLEAR文を実行する前の【HIMEM(0FC4AH)】の内容から知ることができます。
MSXを起動したと時のメモリ状態を図2.20に示します。
MSXのアプリケーションプログラムを作成する場合、必ずHIMEMの内容を確かめ、最悪の場合でも暴走しないように対処してください。対処の方法としては、次のようなものが考えられます。
- ワークエリアをリロケータブルにする
- ワークエリアをBOTTOMから確保する
- ドライブ数を減らすように指示して停止する
MSXはディスクが実装されている場合も、[SHIFT]キーを押しながらリセットすることにより、ディスクを切り離すことができます。また、ディスクが1ドライブだけ実装されている機種を起動すると、2ドライブのシミュレータ機能が働き、2ドライブ分のワークエリアが確保されます。このような時は[CTRL]キーを押しながらリセットすると、2ドライブシミュレータを無効にして、起動することができます。これにより、1.5Kバイトのユーザーエリアを確保できます。
4.2 ユーザーエリアの詳細
BASIC使用時のユーザーエリアの状況を図2.21に、それらのエリアの開始番地へのポインタ情報を持つワークエリアを表2.15に示します。なお、このワークエリアは読み出し専用ですから、内容を書き換えた場合の動作に関しては保証されません。
表2.15 各エリアの開始と終了アドレスを持つワークエリア
エリア名 | 開始エリア | 終了アドレス |
マシン語領域 | 【HIMEM(0FC4AH)】 | ユーザーエリアの終わりまで |
ファイルコントロールブロック | 【MEMSIZ(0F672H)】 | 【HIMEM(0FC4AH)】-1 |
文字列領域 | 【STKTOP(0F674H)】 | 【MEMSIZ(0F672H)】-1 |
(文字列領域の空きエリアの先頭) | 【FRETOP(0F69BH)】 | |
スタックエリア | 【SPレジスタ】 | 【STKTOP(0F674H)】 |
フリーエリア | 【STREND(0F6C6H)】 | 【SPレジスタ】-1 |
配列変数エリア | 【ARYTAB(0F6C4H)】 | 【STREND(0F6C6H)】-1 |
単純変数エリア | 【VARTAB(0F6C2H)】 | 【ARYTAB(0F6C4H)】-1 |
プログラムエリア | 【TXTTAB(0F676H)】 | 【VARTAB(0F6C2H)】-1 |
ユーザーエリア | 【BOTTOM(0FC48H)】 | リセット時の【HIMEM(0FC4AH)】-1 |
各ユーザーエリアの役割を以下に示します。
■BASICのプログラムエリア
BASICで作成したプログラムは、ユーザーエリアの下限アドレス(MSX2では8000H番地)から収納され、その大きさはプログラム量ととともに変化します。
■変数領域
変数領域はBASICプログラムエリアのすぐ後ろに位置し、プログラム実行時に使用された変数の名前や値の保存のために確保されます。この時の変数の格納形式を図2.22(単純変数の場合)、図2.23(配列変数の場合)に示します。なお、配列変数を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.16に示します。
表2.16 ファイルコントロールブロック(FCB)の形式
変位 | ラベル | 意 味 |
+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バイト) |
■マシン語領域
マシン語のプログラムを扱ったり、メモリを直接操作する場合の領域です。これらを行う場合はCLEAR命令によって、あらかじめ領域を確保しておく必要があります。
■ディスクのワークエリア
ディスク実装時に確保されるワークエリアを図2.24に示します。この領域はディスクが実装されていない場合は存在しませんので注意してください。なお、図中左のラベルは、そこにこのアドレスの情報があることを意味します。
4.3 BASICプログラムの格納形式
BASICプログラムはメモリ上に図2.25のような形式で記憶されており、その内容には以下のような意味があります。
■リンクポインタ
次の行へのテキストポインタが絶対アドレスで書かれています。
■行番号
文字どおりプログラムの行番号が格納されており、通常は0〜65529(0000H〜FFF9H)の値が入ります。メモリを直接操作することにより65530以上の行番号を作ることも可能ですが、LISTコマンドはその行以降を表示しません。
■テキスト
ここにプログラ本体が中間コード形式で格納されています。中間コードに変換されるものは、予約語(キーワード)、演算子、数値で、その他のもの(変数名や文字列定数など)はキャラクタコードの形で格納されます。中間コードを表2.17に、テキスト中の数値形式を図2.26に示します。
キャラクタコードについては、巻末の付録を参照してください。なお、グラフィックキャラクタは「CHR$(1)+(グラフィックキャラクタコード+64)」の2バイト(2文字分)で格納されますので、グラフィック文字を取り扱う時には注意が必要です。
表2.17 中間コード一覧表
> | EE | CSNG | FF9F | GOTO | 89 | NAME | D3 | SGN | FF84 |
= | EF | CSRLIN | E8 | HEX$ | FF9B | NEW | 94 | SIN | FF89 |
< | F0 | CVD | FFAA | IF | 8B | NEXT | 83 | SOUND | C4 |
+ | F1 | CVI | FFA8 | INP | FA | NOT | E0 | SPACE$ | FF99 |
- | F2 | CVS | FFA9 | INKEY$ | EC | OCT$ | FF9A | SPC ( | DF |
* | F3 | DATA | 84 | INP | FF90 | OFF | EB | SPRITE | C7 |
/ | F4 | DEF | 97 | INPUT | 85 | ON | 95 | SQR | FF87 |
^ | F5 | DEFDBL | AE | INSTR | E5 | OPEN | B0 | STEP | DC |
\ | FC | DEFINT | AC | INT | FF85 | OR | F7 | STICK | FFA2 |
ABS | FF86 | DEFSNG | AD | IPL | D5 | OUT | 9C | STOP | 90 |
AND | F6 | DEFSTR | AB | KEY | CC | PAD | FFA5 | STR$ | FF93 |
ASC | FF95 | DELETE | A8 | KILL | D4 | PAINT | BF | STRIG | FFA3 |
ATN | FF3E | DIM | 86 | LEFT$ | FF81 | PDL | FFA4 | STRING$ | E3 |
ATTR$ | E9 | DRAW | BE | LEN | FF92 | PEEK | FF97 | SWAP | A4 |
AUTO | A9 | DSKF | FFA6 | LET | 88 | PLAY | C1 | TAB ( | BD |
BASE | C9 | DSKI$ | EA | LFILES | BB | POINT | ED | TAN | FF8D |
BEEP | C0 | DSKO$ | D1 | LINE | AF | POKE | 98 | THEN | DA |
BIN$ | FF9D | ELSE | 3AA1 | LIST | 93 | POS | FF91 | TIME | CB |
BLOAD | CF | END | 81 | LLIST | 9E | PRESET | C3 | TO | D9 |
BSAVE | D0 | EOF | FFAB | LOAD | B5 | 91 | TROFF | A3 | |
CALL | CA | EQV | F9 | LOC | FFAC | PSET | C2 | TRON | A2 |
CDBL | FFA0 | ERASE | A5 | LOCATE | D8 | PUT | B3 | USING | E4 |
CHR$ | FF96 | ERL | E1 | LOF | FFAD | READ | 87 | USR | DD |
CNT | FF9E | ERR | E2 | LOG | FF8A | REM | 8F | VAL | FF94 |
CIRCLE | BC | ERROR | A6 | LPOS | FF9C | RENUM | AA | VARPTR | E7 |
CLEAR | 92 | EXP | FF8B | LPRINT | 9D | RESTORE | 8C | VDP | C8 |
CLOAD | 9B | FIELD | B1 | LSET | B8 | RESUME | A7 | VPEEK | FF98 |
CLOSE | B4 | FILES | B7 | MAX | CD | RETURN | 8E | VPOKE | C6 |
CLS | 9F | FIX | FFA1 | MERGE | B6 | RIGHT$ | FF82 | WAIT | 96 |
CMD | D7 | FN | DE | MID$ | FF83 | RND | FF88 | WIDTH | A0 |
COLOR | BD | FOR | 82 | MKD$ | FFB0 | RSET | B9 | XOR | F8 |
CONT | 99 | FPOS | FFA7 | MKI$ | FFAE | RUN | 8A | ' | 3A8FE6 |
COPY | D6 | FRE | FF8F | MKS$ | FFAF | SAVE | BA | ||
COS | FF8C | GET | B2 | MOD | FB | SCREEN | C5 | ||
CSAVE | 9A | GOSUB | 8D | MOTOR | CE | SET | D2 |
数値は予約語や変数名との区別をつけるために「識別コード」と呼ばれる番号が割り付けられており、それを見ることで後に続く値がどのようなものかわかるようになっています。
2バイトの数値の場合は、上位と下位バイトが逆に格納されます。符号付き数値については、識別コードの前に+または−の中間コードが置かれるのみであり、数値自体はかならず正の数で記憶されます。浮動小数点表記法についてはおおむね6.3のマスパック(Mathematical Package)の説明と同じですが、上記のように数値はかならず正の数で記憶される点に注意してください。2進数(&B)については、識別コードは割り当てられておらず、アスキーコードそのままの形で記憶されます。