BASICの構造と拡張 - 前半 - 書籍「ADVANCED MZ-700」より引用・ダイジェスト ======================================================================== Hu-BASICのメモリ ---------------- ### HU-BASIC 各行の構造。 図1 行の構造 ┌─────┬─────┬─────────┬──┬──┐ │ 行の長さ │ 行番号 │ プログラム本体 │ 00 │ 00 │ └─────┴─────┴─────────┴──┴──┘ * 行の長さ : 2byte。リトルエンディアン。全体のbyte数が含まれる。 * 行番号 : 2byte。リトルエンディアン。 * プログラム本体 : 中間コードやASCIIコードが入っている。 * 行の終わり : 1byteの $00 が入ってる。 * プログラム全体の終わり : 2byte。00 00 が入る。 ### プログラムの格納場所 BASICプログラムの格納アドレス値が書かれた場所をテキストポイントと呼ぶ。 * テキストポインタは $888B 番地から2byte。 * 初期値は $898E。この値は NEWON コマンドを実行しない限り変化しない。 * NEWON コマンドは「オーナーズマニュアル」に載っていないコマンド。 (「Hu-BASICマニュアルにない命令群」 Oh!MZ 1983年6月号参照) * 入力したBASICプログラムは $898E 番地から格納される。 ### プログラムの格納形式 図2 内部表現の例 図2-1 プログラム 10 FOR I=1 TO 20 20 PRINT "I=";I 30 NEXT 40 END 図2-2 格納されたバイナリ :898E=10 00 0A 00 8D 20 49 F4 / ..... I. :8996=02 20 E0 20 12 14 00 00 / . . .... :899E=0D 00 14 00 8F 20 22 49 / ..... "I :89A6=3D 22 3B 49 00 / =";I. :89AB=06 00 1E 00 8E 00 / ...... :89B1=06 00 28 00 9B 00 / ..(... 00 00 8D 20 49 / ...... I 2番目の行 ($899E から始まる部分) に着目。 * 最初の2byte、0D 00 は $000D = 13。この2byteも含め、13byteでこの行は成立。 * 次の2byteは $0014 = 20。BASICの行番号と一致。 * 次の 8F は「PRINT」の内部表現。 * $20 はASCIIコードでスペースを表す。 「PRINT "I=";I」の、「T」 と「"」の間の空白に対応。 * 続く6byteはASCIIコード。 * 最後の1byte、$00 は1行の終わりを示す。 要は、以下のように変換されて記憶される。 * BASICの予約語は、中間コードと呼ばれる内部表現になる。 * それ以外の文字はASCIIコードになる。 * 数字は16進表現になる。 つまり、キーボードから行番号の文字列を入力すると… * BASICインタプリタは、その行の行番号を16進数に直す。 * 文字列内に、予約語と一致する部分があれば、中間コードに変換。 * 文の種類によっては必要な処理をさらに施す。 (例えば FOR 文。上の例で I=1 にあたる部分は 49 F4 02 となる)。 LISTを実行するとプログラム内容が表示されるが、 その際、中間コードを予約語に戻す逆変換が行われている。 Hu-BASICの変数 -------------- ### 変数の型 Hu-BASICの変数の型は、4種類ある。 * 整数型 * 単精度型 * 倍精度型 * 文字列型 ### 変数の格納場所 * 変数は型によらず、varptr と呼ばれるシステム変数が指す番地から格納される。 * varptr は $887F番地から2byte。プログラムエンドの次を指している。 * プログラムを変更すると varptr の内容も変わるが、 全体を移動することで変数の内容が変わってしまう事態を防いでいる。 ### 変数の格納形式 図3 変数格納形式 ┌───────┬───────┬───────┬───────┐ │ 型の長さ │ 変数名の長さ │ 変数名 │ 変数の内容 │ └───────┴───────┴───────┴───────┘ │--- 1byte ---│--- 1byte ----│ * 型の長さは1byte。整数型なら 02、単精度型なら 05 というように 型が必要とするbyte数を示す。 * 次の変数名の長さも1byte。 * 変数名はASCIIコードで入っている。 * 変数エリアの最後には 00 が入る。 ### 整数型 * 型の長さは 2。 * 変数の内容は下位、上位の順に値が収められている。(リトルエンディアン) * 負の数は2の補数で入る。 例1. DEFINT S SEISUU=10000 02 06 53 45 49 53 55 55 10 27 └──────────┘└──┘ 変数名 内容 $2710 = 2 * 16^3 + 7 * 16^2 * 1 * 16^1 = 8192 + 1792 + 16 = 10000 ### 単精度型 * 型の長さは 5。 * 変数の内容は、最初の1byteが指数部、残り4byteが仮数部。 * 仮数部は左側のビットがMSBになっていて、一番上のビットは符号ビット。 * 仮数部は小数点の右に1が立っていると考える。 つまり、仮数部が 40000000 なら、2進表現では以下になる。 0.1 100 0000 0000 0000 0000 0000 0000 0000 └┬┘└───┘└────┘└────┘└────┘ │ $40 $00 $00 $00 │ │ │ └─ (左側の1ビットは符号ビット) │ └─ 仮想的な1 * 指数部は $80 が 2 の 0乗を意味する。 * $81 なら 2^1。 * $7F なら 2^-1。 仮数部に仮想的な 1 をたてているので、このままでは 0 が表現できない。 故に、指数部が 00 のときは 0 とみなす。 指数部も仮数部も2進表現なので分かり難いが、10進数に対応させると分かり易い。 指数部は小数点の位置を示すと考える。 * 0 ならそのまま、 * 1 なら右へひとつずらす、 * -1 なら左へひとつずらす。 10進数では…。 1.86 * 10^-1 = 0.186 2進数でも同様。 (0.1011)b * 2^2 = (10.11)b 10進数になおすと、 1 * 2^1 + 0 * 2^0 + 1 * 2^-1 + 1 * 2^-2 = 2 + 0 + 0.5 + 0.25 = 2.75 となる。 例2. JISSUU=10000 05 06 4A 49 53 53 55 55 8E 1C 40 00 00 | | | | |<------ 変数名 ------>| |<---- 内容 ------>| 符号ビット | $1C40 = (0001 1100 0100 0000)B 8E は 2^14 を意味しているから、変数の内容は次のとおり。 10 0111 0001 0000 = $2710 = 10000 ### 倍精度型 * 型の長さは 8。 * 単精度型同様、変数の内容の最初の1byteが指数部。残り7byteが仮数部。 * 仮数部の解釈は単精度と同じ。 例3. DEFDBL D DBL=55555.2# 注1 08 03 44 42 4C 90 59 03 33 33 33 33 33 | | | | |<変数名>| |<------ 内容 --------->| 注1 DBL=55555.2 とすると、 PRINT DBL 55555.19999694824 つまり、単精度から倍精度への自動変換は行われない。 変数の代入においても事情は同じなので、 数値計算で精度が問題となる場合は注意が必要。 $90 は 2^16 を示す。 59 03 33 33 33 33 33 は、 符号ビット | 0101 1001 0000 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 (1101 1001 0000 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011)b = 2^15 + 2^14 + 2^12 + 2^11 + 2^8 + 2^1 + 2^0 + 2^-3 + 2^-4 + 2^-7 + 2^-8 + 2^-11 + 2^-12 + 2^-15 + 2^-16 + 2^-19 + 2^-20 + 2^-23 + 2^-24 + 2^-27 + 2^-28 + 2^-31 + 2^-32 + 2^-35 + 2^-36 + 2^-39 + 2^-40 = 55555.2 注2 注2 正しくは、55555.2 にはならない。 ### 文字型 * 型の長さは 3。 * 変数の内容の最初の1byteは、文字列の長さを示す。 * 続く2byteは、文字列が格納されている場所へのポインタ。 実際の番地は、ストリングポインタ + このポインタ2byte、の値になる。 * ストリングポインタは $8881番地から2byte。 たとえば、$8881 から CD 89 が入っていて、変数の内容が 05 42 04 なら、 実際の文字列は、$89CD + $0442 = $8E0F番地から 5byte に渡って入っている。 例4. DEFSTR S STR="STRING" 03 53 04 52 06 42 04 └───┘ └┘ 変数名 長さ ストリングポインタの内容が $89FE だとすると $89FE + $0442 = $8E40 だから、 $8E40番地から、53 54 52 49 4E 47 と入っている。 予約語の内部形式 ---------------- プログラムの実行速度を上げる狙いもあり、予約語は中間コードに変換される。 図4でも、PRINT は "8F" に、NEXT は "8E" に変換されていることが分かる。 図4 予約語テーブル(一部) :2DBE=47 4F 54 CF 47 4F 53 55 /GOT_GOSU :2DC6=C2 47 CF 52 55 CE 52 45 /.G_RU.RE :2DCE=54 55 52 CE 52 45 53 54 /TUR.REST :2DD6=4F 52 C5 52 45 53 55 4D /OR.RESUM :2DDE=C5 4C 49 53 D4 4C 4C 49 /.LIS.LLI :2DE6=53 D4 44 45 4C 45 54 C5 /S.DELET. :2DEE=52 45 4E 55 CD 41 55 54 /RENU.AUT :2DF6=CF 45 44 49 D4 46 4F D2 /_EDI.FO. :2DEE=4E 45 58 D4 50 52 43 4E /NEX.PRIN :2E06=D4 4C 50 52 49 4E D4 49 /.LPRIN.I :2E0E=4E 50 55 D4 4C 49 4E 50 /NPU.LINP :2E16=55 D4 49 C6 44 41 54 Cl /U.I.DAT. :2E1E=52 45 41 C4 44 49 CD 52 /REA.DI.R :2E26=45 CD 45 4E C4 53 54 4F /E.EN.STO :2E2E=D0 43 4F 4E D4 43 4C D3 /.CON.CL. :2E36=43 4C 45 41 D2 4F CE 4C /CLEA.O.L 中間コードは、予約語表内での順序に従っている。 つまり "8F" は、予約語表中で16番目であることを意味する。 $8F - $80 + 1 = 16 の予約語表は $2DBE から $315B にある (図4を参照)。 この表は、予約語の最後の文字のASCIIコードの8ビット目を1にして区切りとしている。 予約語は4種類に分類される (表1)。 表1 ┌───────────────────────────────────┐ │第1類 │ ├───────────────────────────────────┤ │GOTO, GOSUB, GO, RUN, RETURN, RESTORE, RESUME, LIST, LLIST, DELETE, │ │RENUM, AUTO, EDIT, FOR, NEXT, PRINT, LPRINT, INPUT, LINPUT, IF, DATA, │ │READ, DIM, REM, END, STOP, CONT, CLS, CLEAR, ON, LET, NEW, POKE, OFF, │ │WHILE, WEND, REPEAT, UNTIL, TRACE, TRON, TROFF, SPEED, DEFINT, DEFSNG,│ │DEFDBL, DEFSTR, DEF, LOAD, SAVE, MERGE, CHAIN, CONSOLE, OUT, SEARCH, │ │WAIT, PAUSE, WRITE, SWAP, ERASE, ERROR, ELSE, CALL, MON, LOCATE, MODE,│ │KEY, PUSH, POP, LABEL, RANDOMIZE, OPTION, LINE, OPEN, CLOSE, FIELD, │ │GET, PUT, SET, FILES, LFILES, DEVICE, NAME, KILL, LSET, RSET, INIT, │ │VDIM, MAXFILES, │ ├───────────────────────────────────┤ │第2類 │ ├───────────────────────────────────┤ │TO, STEP, THEN, USING, SUB, BASE, TAB, SPC, EQV, IMP, │ │XOR, OR, AND, NOT, ><, <>, =<, <=, =>, >=, =, >, <, +, -, │ │MOD, \, /, *, ↑, │ ├───────┴───────────────────────────┤ │第3類 │ ├───────────────────────────────────┤ │PSET, PRESET, COLOR, PLAY, BEEP, CGEN, PCOLOR, SKIP, RLINE, │ │MOVE, RMOVE, PHOME, HSET, GPRINT, AXIS, CIRCLE, TSET, PLOT, │ │PAGE, MUSIC, TEMPO, CURSOR, VERIFY, CLR, LIMIT, KLIST, CLICK, │ │BOOT, DEVI$, DEVO$, │ ├───────────────────────────────────┤ │第4類 │ ├───────────────────────────────────┤ │INT, ABS, SIN, COS, TAN, LOG, EXP, SQR, RND, PEEK, ATN, SGN, │ │FRAC, FIX, PAI, RAD, INP, CDBL, CSNG, CINT, DSKF, EOF, FPOS, │ │LOC, LOF, POS, FAC, SUM, FRE, LPOS, JOY, CHR$, STR$, HEX$, │ │OCT$, BIN$, MKI$, MKS$, MKD$, SPACE$, ASC, LEN, VAL, CVS, │ │CVD, CVI, ERR, ERL, CSRLIN, STRPTR, DTL, LEFT$, RIGHT$, MID$, │ │INKEY$, INSTR, HEXCHR$, MEM$, SCRN$, VARPTR, STRING$, TIME$, │ │FN, USR, ATTR$, CHARACTER$, │ └───────────────────────────────────┘ * 第1類と第2類の中間コードは1byte。 * 第3類と第4類は、それぞれ頭に $FE、$FF がついて2byte。 中間コードの対応表を表2に示す。 表2 予約語と中間コードの対応表 GOTO := 80 GOSUB := 81 GO := 82 RUN := 83 RETURN := 84 RESTORE := 85 RESUME := 86 LIST := 87 LLIST := 88 DELETE := 89 RENUM := 8A AUTO := 8B EDIT := 8C FOR := 8D NEXT := 8E PRINT := 8F LPRINT := 90 INPUT := 91 LINPUT := 92 IF := 93 DATA := 94 READ := 95 DIM := 96 REM := 97 END := 98 STOP := 99 CONT := 9A CLS := 9B CLEAR := 9C ON := 9D LET := 9E NEW := 9F POKE := A0 OFF := A1 WHILE := A2 WEND := A3 REPEAT := A4 UNTIL := A5 TRACE := A8 TRON := A9 TROFF := AA SPEED := AB DEFINT := AE DEFSNG := AF DEFDBL := B0 DEFSTR := B1 DEF := B2 LOAD := B4 SAVE := B5 MERGE := B6 CHAIN := B7 CONSOLE := B8 OUT := BA SEARCH := BB WAIT := BC PAUSE := BD WRITE := BE SWAP := BF ERASE := C0 ERROR := C1 ELSE := C2 CALL := C3 MON := C4 LOCATE := C5 MODE := C6 KEY := C7 PUSH := C8 POP := C9 LABEL := CA RANDOMIZE := CB OPTION := CC LINE := CD OPEN := CE CLOSE := CF FIELD := D1 GET := D2 PUT := D3 SET := D4 FILES := D5 LFILES := D6 DEVICE := D7 NAME := D8 KILL := D9 LSET := DA RSET := DB INIT := DC VDIM := DD MAXFILES := DE TO := E0 STEP := E1 THEN := E2 USING := E3 SUB := E4 BASE := E5 TAB := E6 SPC := E7 EQV := E8 IMP := E9 XOR := EA OR := EB AND := EC NOT := ED >< := EE <> := EF =< := F0 <= := F1 => := F2 >= := F3 = := F4 ※ > := F5 ※ < := F6 ※ + := F7 ※ - := F8 ※ MOD := F9 \ := FA ※ / := FB ※ * := FC ※ ^(↑) := FD ※ PSET := FE 81 PRESET := FE 82 COLOR := FE 83 PLAY := FE 8B BEEP := FE 8D CGEN := FE 94 PCOLOR := FE 95 SKIP := FE 96 RLINE := FE 97 MOVE := FE 98 RMOVE := FE 99 PHOME := FE 9A HSET := FE 9B GPRINT := FE 9C AXIS := FE 9D CIRCLE := FE 9E TSET := FE 9F PLOT := FE A0 PAGE := FE A1 MUSIC := FE A2 TEMPO := FE A3 CURSOR := FE A4 VERIFY := FE A5 CLR := FE A6 LIMIT := FE A7 KLIST := FE A8 CLICK := FE AB BOOT := FE AC DEVI$ := FE AD DEVO$ := FE AE INT := FF 80 ABS := FF 81 SIN := FF 82 COS := FF 83 TAN := FF 84 LOG := FF 85 EXP := FF 86 SQR := FF 87 RND := FF 88 PEEK := FF 89 ATN := FF 8A SGN := FF 8B FRAC := FF 8C FIX := FF 8D PAI := FF 8E RAD := FF 8F INP := FF 90 CDBL := FF 91 CSNG := FF 92 CINT := FF 93 DSKF := FF 94 EOF := FF 95 FPOS := FF 96 LOC := FF 97 LOF := FF 98 POS := FF 99 FAC := FF 9A SUM := FF 9B FRE := FF 9C LPOS := FF 9D JOY := FF 9E CHR$ := FF A0 STR$ := Ff A1 HEX$ := FF A2 OCT$ := Ff A3 BIN$ := FF A4 MKI$ := FF A5 MKS$ := FF A6 MKD$ := FF A7 SPACE$ := FF A8 ASC := FF AB LEN := FF AC VAL := FF AD CVS := FF AE CVD := FF AF CVI := FF B0 ERR := FF B3 ERL := FF B4 CSRLIN := FF B5 STRPTR := FF B6 DTL := FF B7 LEFT$ := FF BA RIGHT$ := FF BB MID$ := FF BC INKEY$ := FF BD INSTR := FF BE HEXCHR$ := FF BF MEM$ := FF C0 SCRN$ := FF C1 VARPTR := FF C2 STRING$ := FF C3 TIME$ := FF C4 FN := FF C7 USR := FF C8 ATTR$ := FF CB CHARACTER$ := FF CD ※ 原文には記述なし * 予約語に従ってBASICはそれぞれの処理ルーチンを呼ぶ。 * 処理ルーチンの番地は中間コードから調べるが、 速度をあげるために、処理番地は、中間コード - $7F番目の2byteが、 その中間コードに対応する処理ルーチンの番地になっている。 * ただし、すべての中間コードに処理番地があるのではなく、 第1類と第3類にだけ用意されている。 * 処理番地表は $315C から $3279 にある。 予約語と、対応する処理番地の表 (表3) を示す。 表3 予約語の処理ルーチン番地 GOTO := 38BB GOSUB := 36F2 GO := 38AD RUN := 1E86 RETURN := 35ED RESTORE := 2823 RESUME := 37B2 LIST := 55CE LLIST := 55C6 DELETE := 3380 RENUM := 3392 AUTO := 240C EDIT := 3551 FOR := 1ECB NEXT := 204D PRINT := 21B6 LPRINT := 21AE INPUT := 25CC LINPUT := 2546 IF := 38EA DATA := 32A6 READ := 285A DIM := 725E REM := 1CEB END := 2405 STOP := 22A2 CONT := 22D2 CLS := 40E8 CLEAR := 3353 ON := 3844 LET := 1D42 NEW := 2480 POKE := 3EDB OFF := 233D WHILE := 3621 WEND := 3654 REPEAT := 36C4 UNTIL := 35A5 TRACE := 233D TRON := 2507 TROFF := 2508 SPEED := 2292 DEFINT := 397B DEFSNG := 3981 DEFDBL := 3984 DEFSTR := 397E DEF := 2777 LOAD := 5760 SAVE := 58B0 MERGE := 5801 CHAIN := 552F CONSOLE := 3F31 OUT := 3345 SEARCH := 5560 WAIT := 39C4 PAUSE := 223C WRITE := 214F SWAP := 32BC ERASE := 233D ERROR := 2344 ELSE := 1CEB CALL := 3284 MON := 151A LOCATE := 3F08 MODE := 3E48 KEY := 4059 PUSH := 233D POP := 233D LABEL := 32A6 RANDOMIZE := 233D OPTION := 2525 LINE := 40ED OPEN := 5985 CLOSE := 591B FIELD := 552F GET := 233D PUT := 233D SET := 552F FILES := 5ADB LFILES := 5ADA DEVICE := 5503 NAME := 233D KILL := 5536 LSET := 233D RSET := 233D INIT := 5AB2 VDIM := 233D MAXFILES := 24A9 PSET := 418A PRESET := 41B5 COLOR := 40BD PLAY := 4111 BEEP := 4157 CGEN := 40FA PCOLOR := 3AFA SKIP := 3A55 RLINE := 3AE2 MOVE := 3AE9 RMOVE := 3AF3 PHOME := 3B30 HSET := 3B38 GPRINT := 3B40 AXIS := 3BA4 CIRCLE := 3BE9 TSET := 3E13 PLOT := 3EAC PAGE := 3E1B MUSIC := 4111 TEMPO := 4111 CURSOR := 3F08 VERIFY := 56A2 CLR := 24B4 LIMIT := 3356 KLIST := 3F98 CLICK := 4177 BOOT := 4171 DEVI$ := 540D DEVO$ := 545E