FOR文を実装
2012年6月5日
FOR文が使えるようにした。
幾つか制約があるが、それを踏まえた上でプログラミングすれば、まともに使える(はず)。制約とは、以下のとおり。
・NEXT文では、変数指定の必要はない。
・TOで指定された値と同一にならないと、停止しない。例えば、「FOR A=0 TO 9 STEP 2」などとすると、永久ループになる。
・上記の性質と関係するが、例えば「FOR A=10 TO 9」などと記述すると、ループの中身が65536回実行される。
FOR文、NEXT文のコンパイルルーチンは、次のとおり。
離れた場所にあるFOR文とNEXT文の間でのプロセスの移動には、スタックを用いている。なので、FORループの中でGOTOを用いたりRETURNしたりすると、暴走することになる。まぁ、そういう仕様と言うことで。
ちなみに、memcpy()にはZ80のブロック命令が用いられているので、ここの部分は結構高速である。いずれにせよ、一通り使えるようになってから、速度向上とファイルサイズの圧縮のために、記述方法を全体的に見直すつもりにはしている。
出来上がったFOR文で一万回ループを実行してみると、凡そ0.5秒ほどだった。普通のBASICインタープリターの20倍ほどの速度である。
幾つか制約があるが、それを踏まえた上でプログラミングすれば、まともに使える(はず)。制約とは、以下のとおり。
・NEXT文では、変数指定の必要はない。
・TOで指定された値と同一にならないと、停止しない。例えば、「FOR A=0 TO 9 STEP 2」などとすると、永久ループになる。
・上記の性質と関係するが、例えば「FOR A=10 TO 9」などと記述すると、ループの中身が65536回実行される。
FOR文、NEXT文のコンパイルルーチンは、次のとおり。
char compileFor(){ char e; int variableAddress, *XX, *YY; // init statement while ((e=source[0])==' ') source++; variableAddress=(int)(&g_variables[(e-'A')*2]); e=compileLet(); if (e) return e; // TO statement if (strncmp(source,"TO ",3)) return 1; source+=3; e=compileInt(); if (e) return e; // STEP statement while (source[0]==' ') source++; if (!strncmp(source,"STEP ",5)) { source+=5; object[0]=0xD5; // PUSH DE object++; e=compileInt(); if (e) return e; memcpy(object,"\xED\x53\x00\x00\xE1\x19",6); // LD (yyyy),DE; POP HL; ADD HL,DE YY=(int*)(object+2); // See below object+=6; } else { // STEP 1 YY=0; memcpy(object,"\xEB\x23",2); // EX DE,HL; INC HL object+=2; } object[0]=0x22; // LD (xxxx),HL XX=(int*)(object+1); // See below object+=3; // FOR statement main routine follows. memcpy(object, "\x18\x12" // JR skip: "\x2A\x34\x12" // LD HL,(1234) "\x11\x01\x00" // LD DE,0001 "\x19" // ADD HL,DE "\x22\x34\x12" // LD (1234),HL "\xAF" // XOR A "\x11\x34\x12" // LD DE,XXXX "\xED\x52" // SBC HL,DE "\xC8" // RET Z "\xE1" // POP HL "\x21\x34\x12" // skip: LD HL,1234 "\xE5" // PUSH HL ,24); *XX=(int)object+14; if (YY) *YY=(int)object+6; object+=3; ((int*)object)[0]=variableAddress; object+=7; ((int*)object)[0]=variableAddress; object+=11; ((int*)object)[0]=(int)object-19; object+=3; return 0; } char compileNext(){ memcpy(object, "\xE1" // POP HL "\x18\x01" // JR skip: "\xE9" // back: JP (HL) "\xCD\x34\x12" // skip: CALL back: ,7); object+=5; ((int*)object)[0]=(int)object-2; object+=2; return 0; }
離れた場所にあるFOR文とNEXT文の間でのプロセスの移動には、スタックを用いている。なので、FORループの中でGOTOを用いたりRETURNしたりすると、暴走することになる。まぁ、そういう仕様と言うことで。
ちなみに、memcpy()にはZ80のブロック命令が用いられているので、ここの部分は結構高速である。いずれにせよ、一通り使えるようになってから、速度向上とファイルサイズの圧縮のために、記述方法を全体的に見直すつもりにはしている。
出来上がったFOR文で一万回ループを実行してみると、凡そ0.5秒ほどだった。普通のBASICインタープリターの20倍ほどの速度である。