BASIC compiler/interpreter for PIC32MX/MZ-80K
Révision | 78cdb09623dbbe94001c56e078c809a92af1a17e (tree) |
---|---|
l'heure | 2019-02-18 09:24:53 |
Auteur | Katsumi <kmorimatsu@sour...> |
Commiter | Katsumi |
Update zoea.
@@ -790,6 +790,7 @@ char* static_method(char type){ | ||
790 | 790 | // Check class name |
791 | 791 | i=check_var_name(); |
792 | 792 | if (i<65536) return ERR_SYNTAX; |
793 | + record[0]=i; | |
793 | 794 | // Check if the class exists |
794 | 795 | cmpdata_reset(); |
795 | 796 | while(data=cmpdata_find(CMPDATA_CLASS)){ |
@@ -799,7 +800,6 @@ char* static_method(char type){ | ||
799 | 800 | break; |
800 | 801 | } |
801 | 802 | } |
802 | - record[0]=i; | |
803 | 803 | // Check '::' |
804 | 804 | if (g_source[g_srcpos]!=':') return ERR_SYNTAX; |
805 | 805 | g_srcpos++; |
@@ -844,7 +844,7 @@ char* static_method(char type){ | ||
844 | 844 | // label2: |
845 | 845 | // Register CMPDATA if required. |
846 | 846 | if (!data) { |
847 | - cmpdata_insert(CMPDATA_UNSOLVED,CMPTYPE_STATIC_METHOD,(int*)record[0],3); | |
847 | + cmpdata_insert(CMPDATA_UNSOLVED,CMPTYPE_STATIC_METHOD,(int*)&record[0],3); | |
848 | 848 | g_allow_shift_obj=0; |
849 | 849 | } |
850 | 850 | // Remove stack |
@@ -119,8 +119,8 @@ DELETEするだけではこれらの領域は破棄されません。その場 | ||
119 | 119 | <フィールドへのアクセス方法> |
120 | 120 | |
121 | 121 | パブリックフィールドへアクセスする場合は、オブジェクトを含む変数に続けて「.」と |
122 | -フィールド名を記述して下さい。フィールドが文字列の場合は「$」を後ろに付けて下さ | |
123 | -い。 | |
122 | +フィールド名を記述して下さい。フィールドが文字列の場合は「$」を、実数の場合は | |
123 | +「#」を、それぞれ後ろに付けて下さい。 | |
124 | 124 | |
125 | 125 | 記述例: |
126 | 126 | USECLASS CLASS1 |
@@ -132,8 +132,8 @@ DELETEするだけではこれらの領域は破棄されません。その場 | ||
132 | 132 | |
133 | 133 | パブリックメソッドへアクセスする場合は、オブジェクトを含む変数に続けて「.」と |
134 | 134 | メソッド名、続けて「( )」を記述して下さい。メソッドが戻り値として文字列を返す場 |
135 | -合、メソッド名の後ろに「$」を付けて下さい。メソッドは関数と同じ扱いですが、戻 | |
136 | -り値を利用しない場合は、CALL命令により呼び出す事も出来ます。 | |
135 | +合、メソッド名の後ろに「$」を付けて下さい(実数の場合は「#」)。メソッドは関数 | |
136 | +と同じ扱いですが、戻り値を利用しない場合は、CALL命令により呼び出す事も出来ます。 | |
137 | 137 | |
138 | 138 | CALL x |
139 | 139 | xで指定されたオブジェクトのメソッドを呼び出す。 |
@@ -32,7 +32,8 @@ const unsigned char _debug_filename[] __attribute__((address(FILENAME_FLASH_ADDR | ||
32 | 32 | |
33 | 33 | static const char initext[]; |
34 | 34 | static const char bastext[]; |
35 | -static const char classtext[]; | |
35 | +static const char class1text[]; | |
36 | +static const char class2text[]; | |
36 | 37 | |
37 | 38 | static char* readtext; |
38 | 39 | static int filepos; |
@@ -130,10 +131,12 @@ FSFILE* FSfopen(const char * fileName, const char *mode){ | ||
130 | 131 | // INI file |
131 | 132 | readtext=(char*)&initext[0]; |
132 | 133 | } else if (fileName[i+1]=='B' && fileName[i+2]=='A' && fileName[i+3]=='S') { |
133 | - // BAS file | |
134 | + // Select BAS file | |
134 | 135 | if (fileName[i-6]=='C' && fileName[i-5]=='L' && fileName[i-4]=='A' && |
135 | - fileName[i-3]=='S' && fileName[i-2]=='S' && fileName[i-1]=='1') { | |
136 | - readtext=(char*)&classtext[0]; | |
136 | + fileName[i-3]=='S' && fileName[i-2]=='S') { | |
137 | + if (fileName[i-1]=='1') readtext=(char*)&class1text[0]; | |
138 | + else if (fileName[i-1]=='2') readtext=(char*)&class2text[0]; | |
139 | + else readtext=(char*)&bastext[0]; | |
137 | 140 | } else { |
138 | 141 | readtext=(char*)&bastext[0]; |
139 | 142 | } |
@@ -228,19 +231,39 @@ static const char initext[]= | ||
228 | 231 | static const char bastext[]= |
229 | 232 | "USECLASS CLASS1\n" |
230 | 233 | "CLS\n" |
231 | -"a=new(CLASS1)\n" | |
232 | -"print a.T3()\n" | |
233 | -"\n" | |
234 | -"\n" | |
235 | -"\n" | |
234 | +"dim o(9)\n" | |
235 | +"for j=1 to 100\n" | |
236 | +" cursor 0,0\n" | |
237 | +" for i=1 to 9\n" | |
238 | +" o(i)=new(CLASS1)\n" | |
239 | +" next\n" | |
240 | +" for i=1 to 9\n" | |
241 | +" a=o(i)\n" | |
242 | +" print hex$(a),\n" | |
243 | +" delete a\n" | |
244 | +" next\n" | |
245 | +"next\n" | |
236 | 246 | "\n" |
237 | 247 | "\n" |
238 | 248 | "\n"; |
239 | 249 | |
250 | +static const char class1text[]= | |
251 | +"STATIC T1\n" | |
252 | +"useclass CLASS2\n" | |
253 | +"method T3\n" | |
254 | +" return CLASS2::T2\n" | |
255 | +"method T5\n" | |
256 | +" return T1\n" | |
257 | +"\n" | |
258 | +"\n"; | |
240 | 259 | |
241 | -static const char classtext[]= | |
242 | -"METHOD T3\n" | |
243 | -" return 123\n" | |
260 | +static const char class2text[]= | |
261 | +"STATIC T2\n" | |
262 | +"useclass CLASS1\n" | |
263 | +"method T4\n" | |
264 | +" return CLASS1::T1\n" | |
265 | +"method T6\n" | |
266 | +" return T2\n" | |
244 | 267 | "\n" |
245 | 268 | "\n" |
246 | 269 | "\n" |
@@ -109,7 +109,7 @@ char* compile_file(){ | ||
109 | 109 | } |
110 | 110 | |
111 | 111 | int compile_and_link_file(char* buff,char* appname){ |
112 | - int i; | |
112 | + int i,j; | |
113 | 113 | char* err; |
114 | 114 | |
115 | 115 | while(1){ |
@@ -129,7 +129,9 @@ int compile_and_link_file(char* buff,char* appname){ | ||
129 | 129 | |
130 | 130 | // If compiling a class file is required, do it. |
131 | 131 | if (err==ERR_COMPILE_CLASS) { |
132 | + j=g_compiling_class; | |
132 | 133 | i=compile_and_link_class(buff, g_class); |
134 | + g_compiling_class=j; | |
133 | 135 | if (i) return i; |
134 | 136 | // Continue compiling current file from the beginning. |
135 | 137 | continue; |
@@ -127,6 +127,12 @@ PCG x,y,z | ||
127 | 127 | ターデーター。詳細は、下記<PCG>の項を参照。 |
128 | 128 | POKE x,y |
129 | 129 | xで示される物理的アドレスに、yで示される値(1バイト値)を書き込む。 |
130 | +PEEK16(x) | |
131 | + xで示される物理アドレスに、yで示される値(16ビット値)を書き込む。xが奇数値の | |
132 | + 場合、例外停止するので注意。 | |
133 | +PEEK32(x) | |
134 | + xで示される物理アドレスに、yで示される値(32ビット値)を書き込む。xが4の倍数で | |
135 | + 無い場合、例外停止するので注意。 | |
130 | 136 | PRINT [ xまたはx$またはx# [ ,または; [ yまたはy$またはy# [ ... ]]]] |
131 | 137 | ディスプレイに、整数値または文字列を表示する。「;」を使用した場 |
132 | 138 | 合、次の表示が続けて行われる。「,」を使用した場合、10文字ずつ |
@@ -237,8 +243,11 @@ FSEEK x | ||
237 | 243 | ABS(x) |
238 | 244 | xの絶対値を返す。 |
239 | 245 | ARGS(x) |
240 | - サブルーチン中で、GOSUBに渡されたx番目の引数を整数値として取り出す。x=0の場 | |
241 | - 合、引数の数を返す(引数がない時は、0)。 | |
246 | + サブルーチン中で、GOSUBもしくはメソッドに渡されたx番目の引数を整数値として取 | |
247 | + り出す。但し、 | |
248 | + ARGS(0)は、引数の数を返す。 | |
249 | + ARGS(-1)は、一つ前に使われた引数を格納する配列へのポインターを返す。 | |
250 | + ARGS(-2)は、クラスで用いられた場合、オブジェクトへのポインターを返す。 | |
242 | 251 | ASC(x$) |
243 | 252 | 文字列の最初の一文字の、アスキーコードを返す。 |
244 | 253 | CREAD() |
@@ -285,6 +294,12 @@ NOT(x) | ||
285 | 294 | x=0の場合に1を、そうでない場合に0を返す。 |
286 | 295 | PEEK(x) |
287 | 296 | xで示される物理アドレスから1バイト読み取り、返す。 |
297 | +PEEK16(x) | |
298 | + xで示される物理アドレスから2バイト読み取り、16ビット値で返す。xが奇数値の場 | |
299 | + 合、例外停止するので注意。 | |
300 | +PEEK32(x) | |
301 | + xで示される物理アドレスから4バイト読み取り、32ビット値で返す。xが4の倍数で | |
302 | + 無い場合、例外停止するので注意。 | |
288 | 303 | PLAYWAVE([x]) |
289 | 304 | xを指定しない場合、もしくは0を指定した場合、再生中のWAVEファイルの残りサン |
290 | 305 | プリング数を返す。1を指定した場合、現在再生中のサンプリング番号を、2を指 |
@@ -310,7 +325,8 @@ VAL(x$) | ||
310 | 325 | ACOS#(x#) |
311 | 326 | x# の逆余弦を実数値で返す。 |
312 | 327 | ARGS#(x) |
313 | - サブルーチン中で、GOSUBに渡されたx番目の引数を実数値として取り出す。 | |
328 | + サブルーチン中で、GOSUBもしくはメソッドに渡されたx番目の引数を実数値として取 | |
329 | + り出す。 | |
314 | 330 | ASIN#(x#) |
315 | 331 | x# の逆正弦を実数値で返す。 |
316 | 332 | ATAN#(x#) |
@@ -367,7 +383,8 @@ A$(x [,y])など | ||
367 | 383 | xの値が負のとき、文字列の右側x文字を返す。 |
368 | 384 | yが指定された場合、y文字分の文字列を返す。 |
369 | 385 | ARGS$(x) |
370 | - サブルーチン中で、GOSUBに渡されたx番目の引数を文字列として取り出す。 | |
386 | + サブルーチン中で、GOSUBもしくはメソッドに渡されたx番目の引数を文字列として取 | |
387 | + り出す。 | |
371 | 388 | CHR$(x) |
372 | 389 | xをアスキーコードとする文字を返す。 |
373 | 390 | DEC$(x) |
@@ -394,6 +411,8 @@ READ$() | ||
394 | 411 | DATA文の後から、一つずつ文字列データーを読み出す。 |
395 | 412 | |
396 | 413 | <整数演算子> |
414 | +&x | |
415 | + 変数xの格納アドレス(ポインター) | |
397 | 416 | -x |
398 | 417 | 符号を反転 |
399 | 418 | x + y |
@@ -431,7 +450,7 @@ x XOR y | ||
431 | 450 | |
432 | 451 | なお、整数演算子の優先順位は、優先度が高いものから以下の順です。 |
433 | 452 | |
434 | -+ - (単項演算子) | |
453 | ++ - (単項演算子) & | |
435 | 454 | * / % |
436 | 455 | + - (加算・減算) |
437 | 456 | << >> |
@@ -608,6 +627,10 @@ FIELD [PUBLIC] x[,y[,z[, ... ]]] | ||
608 | 627 | FIELD PRIVATE x[,y[,z[, ... ]]] |
609 | 628 | クラスファイル中で、プライベートフィールドを宣言する。x,y,z等はフィールド |
610 | 629 | 名を6文字以内の英数字で指定。 |
630 | +STATIC [PUBLIC] x[,y[,z[, ... ]]] | |
631 | + クラスファイル中で、パブリックスなタティック変数を宣言する。"PUBLIC"は省略可。 | |
632 | +STATIC PRIVATE x[,y[,z[, ... ]]] | |
633 | + クラスファイル中で、プライベートなスタティック変数を宣言する。USEVARと同じ。 | |
611 | 634 | METHOD x |
612 | 635 | クラスファイル中で、メソッドを宣言する。xは、メソッド名を6文字以内の英 |
613 | 636 | 数字で指定。 |
@@ -620,10 +643,10 @@ CALL x | ||
620 | 643 | xで指定されたオブジェクトのメソッドを呼び出す。 |
621 | 644 | |
622 | 645 | <ヒント> |
623 | -FOR-NEXTループ、WHILE-WENDループ、DO-LOOPループの途中で、GOTO文でループの | |
624 | -外に飛んだり、RETURN文を実行したりすると、予期せぬ結果(機器のリセット等)を | |
625 | -引き起こします。ただし、GOSUB文でサブルーチンを呼んだり、別のループをネスト | |
626 | -して使う事は可能です。 | |
646 | +KM-1207以降、FOR-NEXTループ、WHILE-WENDループ、DO-LOOPループの途中で、 | |
647 | +RETURN文が使えるようになりました。ただし、GOTO文でループの外に飛ぶと、予期せぬ結 | |
648 | +果(機器のリセット等)を引き起こします。ただし、GOSUB文でサブルーチンを呼んだり、別の | |
649 | +ループをネストして使う事は可能です。 | |
627 | 650 | |
628 | 651 | ON GOTO分やON GOSUB文はサポートしていません。ただし、例えば次のように記述す |
629 | 652 | ることで、同様の動作をさせることは可能です。 |
@@ -639,11 +662,12 @@ ON GOTO分やON GOSUB文はサポートしていません。ただし、例え | ||
639 | 662 | てみて下さい。 |
640 | 663 | |
641 | 664 | <バージョン履歴> |
642 | -・KM-1207 20xx年x月公開。 | |
643 | -TODO: | |
644 | - 1.PUTBMPの第5引数に長文字変数が使えないとのバグ報告有り。 | |
645 | - | |
646 | - | |
665 | +・KM-1207 2019年x月公開。 | |
666 | + 1.PUTBMPの第5引数に長い名前の変数が使えなかったバグの修正 | |
667 | + 2.オブジェクト指向プログラミングに対応 | |
668 | + 3.args(0)で引数の数を取得できるようにした | |
669 | + 4.POKE16, POKE32, PEEK16(), PEEK32()を追加 | |
670 | + 5.&演算子を追加 | |
647 | 671 | ・KM-1206 2018年8月公開。 |
648 | 672 | 1.WAVEファイルの再生に対応。 |
649 | 673 | ・KM-1205 2018年2月公開。 |
@@ -8,7 +8,7 @@ | ||
8 | 8 | #define ZOEA |
9 | 9 | #define SYSVER1 "Zoea" |
10 | 10 | #define SYSVER2 "1.08" |
11 | -#define BASVER "KM-1206" | |
11 | +#define BASVER "KM-1207" | |
12 | 12 | |
13 | 13 | #define INIFILE "MACHIKAZ.INI" // 初期設定ファイル |
14 | 14 | #define HEXFILE "MACHIKAZ.HEX" // 実行中HEXファイル名がこれと一致した場合はエディタ起動 |
@@ -26,22 +26,33 @@ | ||
26 | 26 | */ |
27 | 27 | |
28 | 28 | static int g_temp_var_num_candidate=ALLOC_PERM_BLOCK; |
29 | -static int g_last_deleted_pointer; | |
30 | -static int g_last_deleted_size=0; | |
31 | 29 | |
32 | -#define register_deleted_block(x,y) \ | |
33 | - do {\ | |
34 | - g_last_deleted_pointer=(x);\ | |
35 | - g_last_deleted_size=(y);\ | |
36 | - } while(0) | |
30 | +#define DELETE_LIST_SIZE 10 | |
31 | +static int g_deleted_num; | |
32 | +static int g_deleted_pointer[DELETE_LIST_SIZE]; | |
33 | +static int g_deleted_size[DELETE_LIST_SIZE]; | |
34 | + | |
35 | +void register_deleted_block(int pointer, int size){ | |
36 | + // There is maximum | |
37 | + if (DELETE_LIST_SIZE<=g_deleted_num) return; | |
38 | + if (g_deleted_num) { | |
39 | + // Avoid duplication | |
40 | + if (g_deleted_pointer[g_deleted_num-1]==pointer) return; | |
41 | + } | |
42 | + g_deleted_pointer[g_deleted_num]=pointer; | |
43 | + g_deleted_size[g_deleted_num]=size; | |
44 | + g_deleted_num++; | |
45 | +} | |
37 | 46 | |
38 | 47 | void set_free_area(void* begin, void* end){ |
48 | + // Initialize heap area | |
39 | 49 | int i; |
40 | 50 | for(i=0;i<ALLOC_BLOCK_NUM;i++){ |
41 | 51 | g_var_size[i]=0; |
42 | 52 | } |
43 | 53 | g_heap_mem=(int*)begin; |
44 | 54 | g_max_mem=(int)((end-begin)/4); |
55 | + g_deleted_num=0; | |
45 | 56 | } |
46 | 57 | |
47 | 58 | void* calloc_memory(int size, int var_num){ |
@@ -97,14 +108,23 @@ void* _alloc_memory_main(int size, int var_num){ | ||
97 | 108 | g_var_size[var_num]=0; |
98 | 109 | g_var_pointer[var_num]=0; |
99 | 110 | while(1){ |
100 | - // Try the block previously deleted | |
101 | - if (size<=g_last_deleted_size) { | |
102 | - g_last_deleted_size=0; | |
103 | - candidate=g_last_deleted_pointer; | |
104 | - break; | |
105 | - } else { | |
106 | - // Last deleted block is a candidate only once | |
107 | - g_last_deleted_size=0; | |
111 | + // Try the block previously deleted, not for temporary block. | |
112 | + // This is for fast allocation of memory for class object. | |
113 | + if (var_num<26 || ALLOC_VAR_NUM<=var_num) { | |
114 | + candidate=0; | |
115 | + while(g_deleted_num){ | |
116 | + // Check if the last deleted block fits | |
117 | + // If not, these cannot be used anymore | |
118 | + g_deleted_num--; | |
119 | + if (size<=g_deleted_size[g_deleted_num]) { | |
120 | + candidate=g_deleted_pointer[g_deleted_num]; | |
121 | + break; | |
122 | + } | |
123 | + } | |
124 | + if (candidate || g_deleted_num) { | |
125 | + // Candidate found | |
126 | + break; | |
127 | + } | |
108 | 128 | } |
109 | 129 | // Try the block after last block |
110 | 130 | candidate=0; |
@@ -114,7 +134,29 @@ void* _alloc_memory_main(int size, int var_num){ | ||
114 | 134 | candidate=g_var_pointer[i]+g_var_size[i]; |
115 | 135 | } |
116 | 136 | } |
117 | - if (candidate+size<=g_max_mem) break; | |
137 | + if (candidate+size<=g_max_mem) { | |
138 | + // Check after deleted block | |
139 | + j=candidate; | |
140 | + for(i=0;i<g_deleted_num;i++){ | |
141 | + if (j<g_deleted_pointer[i]+g_deleted_size[i]) { | |
142 | + j=g_deleted_pointer[i]+g_deleted_size[i]; | |
143 | + } | |
144 | + } | |
145 | + if (j+size<=g_max_mem) { | |
146 | + // Candidate block found after previously deleted blokcs | |
147 | + candidate=j; | |
148 | + break; | |
149 | + } else { | |
150 | + // Candidate is before previously deleted blocks, | |
151 | + // and there is no candidate block after previously deleted blocks. | |
152 | + // Therefore, use the current candidate, which may invade previously | |
153 | + // deleted blocks. Therefore, erase the previously deleted blocks list. | |
154 | + g_deleted_num=0; | |
155 | + break; | |
156 | + } | |
157 | + } | |
158 | + // Peviously deleted blocks cannot be used any more | |
159 | + g_deleted_num=0; | |
118 | 160 | // Check between blocks |
119 | 161 | // Note that there is at least one block with zero pointer and zero size (see above). |
120 | 162 | for(i=0;i<ALLOC_BLOCK_NUM;i++){ |
@@ -178,7 +220,7 @@ void free_non_temp_str(char* str){ | ||
178 | 220 | } |
179 | 221 | } |
180 | 222 | for(i=ALLOC_VAR_NUM;i<ALLOC_BLOCK_NUM;i++){ |
181 | - if (g_var_pointer[i]==pointer && g_var_size[i]) { | |
223 | + if (g_var_pointer[i]==pointer) { | |
182 | 224 | if (g_var_size[i] && g_var_mem[i]==(int)str) { |
183 | 225 | register_deleted_block(pointer,g_var_size[i]); |
184 | 226 | g_var_size[i]=0; |