BASIC compiler/interpreter for PIC32MX/MZ-80K
Revisión | 0d0d0b27966a8db911d5bc2bf806885f30ed03a8 (tree) |
---|---|
Tiempo | 2019-04-15 13:34:35 |
Autor | Katsumi <kmorimatsu@sour...> |
Commiter | Katsumi |
Fast field access implementation.
@@ -33,6 +33,14 @@ static int* g_class_structure; | ||
33 | 33 | record[1]: field/method name as integer |
34 | 34 | record[2]: pointer to method |
35 | 35 | */ |
36 | +/* | |
37 | + CMPDATA_FASTFIELD structure | |
38 | + type: CMPDATA_FASTFIELD | |
39 | + len: 2 | |
40 | + data16: number of position of public field in object | |
41 | + 0 for multiple usage of the same public field name | |
42 | + record[1]: field name as integer | |
43 | +*/ | |
36 | 44 | |
37 | 45 | /* |
38 | 46 | CMPDATA_STATIC structure |
@@ -62,6 +70,24 @@ static int* g_class_structure; | ||
62 | 70 | */ |
63 | 71 | |
64 | 72 | /* |
73 | + About fast field access | |
74 | + When a public field name used only once with a class, | |
75 | + the address of this field of an object is defined quickly when compiling. | |
76 | + This logic is always true when there is only a class. | |
77 | + | |
78 | + However, if there are more than two classes and the field name is used | |
79 | + by only a class, this logic is true only when the BASIC code does not have | |
80 | + error. If there is an error in BASIC code, this type of error cannot be | |
81 | + found by compiler and when executing. | |
82 | + | |
83 | + Therefore, only use this logic when the number of class is one, and/or | |
84 | + OPTION FASTFIELD is defined. | |
85 | + | |
86 | + This logic is useless for public method, because library must be always called | |
87 | + before calling public method. | |
88 | +*/ | |
89 | + | |
90 | +/* | |
65 | 91 | Local prototyping |
66 | 92 | */ |
67 | 93 | char* obj_method(int method); |
@@ -259,10 +285,36 @@ char* construct_class_structure(int class){ | ||
259 | 285 | |
260 | 286 | void delete_cmpdata_for_class(int class){ |
261 | 287 | int* record; |
288 | + int i; | |
289 | + short pos; | |
262 | 290 | // Delete field/method data |
263 | 291 | cmpdata_reset(); |
292 | + pos=0; // # of position of public field | |
264 | 293 | while(record=cmpdata_find(CMPDATA_FIELD)){ |
265 | - cmpdata_delete(record); | |
294 | + if ((record[0]&0xffff)==CMPTYPE_PUBLIC_FIELD) { | |
295 | + pos++; | |
296 | + i=record[1]; // Field name | |
297 | + cmpdata_delete(record); | |
298 | + // Construct or disable CMPDATA_FASTFIELD | |
299 | + // Note that the sequence of public fields here is the same | |
300 | + // as that in the function, construct_class_struction(). | |
301 | + cmpdata_reset(); | |
302 | + while(record=cmpdata_find(CMPDATA_FASTFIELD)){ | |
303 | + if (record[1]==i) break; | |
304 | + } | |
305 | + if (record) { | |
306 | + // Multiple definition of field name | |
307 | + // Clear data16 if the position is different | |
308 | + if (pos!=(record[0]&0xffff)) record[0]&=0xffff0000; | |
309 | + } else { | |
310 | + // Previous CMPDATA_FASTFIELD not found | |
311 | + // Create now one for fast field implementation | |
312 | + g_temp=i; | |
313 | + cmpdata_insert(CMPDATA_FASTFIELD,pos,&g_temp,1); | |
314 | + } | |
315 | + } else { | |
316 | + cmpdata_delete(record); | |
317 | + } | |
266 | 318 | cmpdata_reset(); |
267 | 319 | } |
268 | 320 | // Delete longvar data |
@@ -488,6 +540,8 @@ char* _obj_field(char mode){ | ||
488 | 540 | // $v0 contains the address of object. |
489 | 541 | int i; |
490 | 542 | char* err; |
543 | + int* record; | |
544 | + char fastfield; | |
491 | 545 | do { |
492 | 546 | i=check_var_name(); |
493 | 547 | if (i<65536) return ERR_SYNTAX; |
@@ -506,11 +560,38 @@ char* _obj_field(char mode){ | ||
506 | 560 | // This is a string field. Raise 31st bit. |
507 | 561 | i|=0x80000000; |
508 | 562 | } |
509 | - check_obj_space(2); | |
510 | - g_object[g_objpos++]=0x3C050000|((i>>16)&0x0000FFFF); // lui a1,xxxx | |
511 | - g_object[g_objpos++]=0x34A50000|(i&0x0000FFFF); // ori a1,a1,xxxx | |
512 | - // First and second arguments are address of object and field name, respectively. | |
513 | - call_quicklib_code(lib_obj_field,ASM_ADDU_A0_V0_ZERO); | |
563 | + // Check if Fast Field Access can be used. | |
564 | + cmpdata_reset(); | |
565 | + while(record=cmpdata_find(CMPDATA_FASTFIELD)){ | |
566 | + if (record[1]==(i&0x7FFFFFFF)) break; | |
567 | + } | |
568 | + if (!record) { | |
569 | + // Record wasn't found | |
570 | + fastfield=0; | |
571 | + } else if (1!=g_num_classes && !g_option_fastfield) { | |
572 | + // No fast field opttion | |
573 | + fastfield=0; | |
574 | + } else if (!(record[0]&0xffff)) { | |
575 | + // The same field name used twice at the different positions | |
576 | + fastfield=0; | |
577 | + } else { | |
578 | + // All requirements passed | |
579 | + fastfield=1; | |
580 | + } | |
581 | + // Generate code here | |
582 | + if (fastfield) { | |
583 | + // Get field value in $v0 and address in $v1 | |
584 | + i=(record[0]&0xffff)*4; | |
585 | + check_obj_space(2); | |
586 | + g_object[g_objpos++]=0x24430004|i; // addiu v1,v0,xxxx | |
587 | + g_object[g_objpos++]=0x8C620000; // lw v0,0(v1) | |
588 | + } else { | |
589 | + check_obj_space(2); | |
590 | + g_object[g_objpos++]=0x3C050000|((i>>16)&0x0000FFFF); // lui a1,xxxx | |
591 | + g_object[g_objpos++]=0x34A50000|(i&0x0000FFFF); // ori a1,a1,xxxx | |
592 | + // First and second arguments are address of object and field name, respectively. | |
593 | + call_quicklib_code(lib_obj_field,ASM_ADDU_A0_V0_ZERO); | |
594 | + } | |
514 | 595 | // Check if "." follows |
515 | 596 | if (g_source[g_srcpos]=='.') { |
516 | 597 | // "." found. $v0 is adress of an object. See the field. |
@@ -56,9 +56,6 @@ METHOD命令で宣言されたメソッドは、すべてパブリックです | ||
56 | 56 | メソッドが指定された場合、オブジェクト作成時に、このメソッドが呼ばれます。INIT |
57 | 57 | メソッドに引数を与える事も可能です(引数は必須ではありません)。 |
58 | 58 | |
59 | -クラス中でオブジェクトへのポインターが必要な場合は、ARGS(-2)で取り出す事が出来 | |
60 | -ます。 | |
61 | - | |
62 | 59 | 記述例(CLASS1.BASの名前で保存): |
63 | 60 | FIELD PUBLIC TEST1,TEST2 |
64 | 61 | FIELD PRIVATE TEST3 |
@@ -163,7 +163,7 @@ char* compile_line(void){ | ||
163 | 163 | printstr(resolve_label(g_line)); |
164 | 164 | return ERR_MULTIPLE_LABEL; |
165 | 165 | } |
166 | - if (!g_nolinenum) { | |
166 | + if (!g_option_nolinenum) { | |
167 | 167 | check_obj_space(1); |
168 | 168 | g_object[g_objpos++]=0x34160000|g_line; //ori s6,zero,xxxx; |
169 | 169 | } |
@@ -213,7 +213,7 @@ extern int g_var_mem[ALLOC_BLOCK_NUM]; | ||
213 | 213 | extern unsigned short g_var_pointer[ALLOC_BLOCK_NUM]; |
214 | 214 | extern unsigned short g_var_size[ALLOC_BLOCK_NUM]; |
215 | 215 | extern char g_temp_area_used; |
216 | -extern char g_nolinenum; | |
216 | +extern char g_option_nolinenum; | |
217 | 217 | extern int* g_heap_mem; |
218 | 218 | extern int g_max_mem; |
219 | 219 | extern char g_disable_break; |
@@ -225,6 +225,8 @@ extern int g_long_name_var_num; | ||
225 | 225 | extern char g_music_active; |
226 | 226 | extern int g_class; |
227 | 227 | extern int g_compiling_class; |
228 | +extern unsigned char g_num_classes; | |
229 | +extern char g_option_fastfield; | |
228 | 230 | extern int g_temp; |
229 | 231 | |
230 | 232 | /* Prototypes */ |
@@ -412,13 +414,14 @@ char* interrupt_statement(); | ||
412 | 414 | #define ERR_NO_INIT (char*)(g_err_str[28]) |
413 | 415 | |
414 | 416 | /* compile data type numbers */ |
415 | -#define CMPDATA_RESERVED 0 | |
416 | -#define CMPDATA_USEVAR 1 | |
417 | -#define CMPDATA_CLASS 2 | |
418 | -#define CMPDATA_FIELD 3 | |
419 | -#define CMPDATA_STATIC 4 | |
420 | -#define CMPDATA_UNSOLVED 5 | |
421 | -#define CMPDATA_TEMP 6 | |
417 | +#define CMPDATA_RESERVED 0 | |
418 | +#define CMPDATA_USEVAR 1 | |
419 | +#define CMPDATA_CLASS 2 | |
420 | +#define CMPDATA_FIELD 3 | |
421 | +#define CMPDATA_STATIC 4 | |
422 | +#define CMPDATA_UNSOLVED 5 | |
423 | +#define CMPDATA_TEMP 6 | |
424 | +#define CMPDATA_FASTFIELD 7 | |
422 | 425 | // Sub types follow |
423 | 426 | #define CMPTYPE_PUBLIC_FIELD 0 |
424 | 427 | #define CMPTYPE_PRIVATE_FIELD 1 |
@@ -228,32 +228,28 @@ static const char initext[]= | ||
228 | 228 | "#PRINT\n"; |
229 | 229 | |
230 | 230 | static const char bastext[]= |
231 | +"USECLASS CLASS1,CLASS2\n" | |
232 | +"OPTION FASTFIELD\n" | |
231 | 233 | "CLS\n" |
232 | -"LABEL TEST_:i=0/0\n" | |
233 | -"\n" | |
234 | -"\n" | |
234 | +"o=new(CLASS1)\n" | |
235 | +"o.T1=123\n" | |
236 | +"print o.T2()\n" | |
235 | 237 | "\n" |
236 | 238 | "\n" |
237 | 239 | "\n" |
238 | 240 | "\n"; |
239 | 241 | |
240 | 242 | static const char class1text[]= |
241 | -"STATIC T1\n" | |
242 | -"useclass CLASS2\n" | |
243 | -"method T3\n" | |
244 | -" return CLASS2::T2\n" | |
245 | -"method T5\n" | |
246 | -" return T1\n" | |
243 | +"FIELD T1\n" | |
244 | +"method T2\n" | |
245 | +" return T1+100\n" | |
247 | 246 | "\n" |
248 | 247 | "\n"; |
249 | 248 | |
250 | 249 | static const char class2text[]= |
251 | -"STATIC T2\n" | |
252 | -"useclass CLASS1\n" | |
253 | -"method T4\n" | |
254 | -" return CLASS1::T1\n" | |
250 | +"FIELD T3\n" | |
255 | 251 | "method T6\n" |
256 | -" return T2\n" | |
252 | +" return T3+100\n" | |
257 | 253 | "\n" |
258 | 254 | "\n" |
259 | 255 | "\n" |
@@ -124,7 +124,8 @@ int compile_and_link_file(char* buff,char* appname){ | ||
124 | 124 | } |
125 | 125 | |
126 | 126 | // Option initialization(s) |
127 | - g_nolinenum=0; | |
127 | + g_option_nolinenum=0; | |
128 | + g_option_fastfield=0; | |
128 | 129 | |
129 | 130 | // Compile the file |
130 | 131 | err=compile_file(); |
@@ -181,6 +182,7 @@ int compile_and_link_class(char* buff,int class){ | ||
181 | 182 | int data[2]; |
182 | 183 | unsigned short cwd_id; |
183 | 184 | int* record; |
185 | + g_num_classes++; | |
184 | 186 | while(1){ |
185 | 187 | // Begin compiling class |
186 | 188 | err=begin_compiling_class(class); |
@@ -250,7 +252,10 @@ int compile_and_link_class(char* buff,int class){ | ||
250 | 252 | |
251 | 253 | int compile_and_link_main_file(char* buff,char* appname){ |
252 | 254 | int i; |
255 | + // Reset parameters | |
253 | 256 | g_compiling_class=0; |
257 | + g_num_classes=0; | |
258 | + // Compile the file | |
254 | 259 | i=compile_and_link_file(buff,appname); |
255 | 260 | if (i) return i; |
256 | 261 | return 0; |
@@ -56,7 +56,7 @@ unsigned short g_var_size[ALLOC_BLOCK_NUM]; | ||
56 | 56 | char g_temp_area_used; |
57 | 57 | |
58 | 58 | // Flag to use option nolinenum |
59 | -char g_nolinenum; | |
59 | +char g_option_nolinenum; | |
60 | 60 | |
61 | 61 | // Heap area |
62 | 62 | int* g_heap_mem; |
@@ -88,8 +88,12 @@ char g_music_active; | ||
88 | 88 | |
89 | 89 | // Class name being compiled |
90 | 90 | int g_class; |
91 | -// Flag to compile class file | |
91 | +// Flag (and class name) to compile class file | |
92 | 92 | int g_compiling_class; |
93 | +// Number of classes used | |
94 | +unsigned char g_num_classes; | |
95 | +// OPTION FASTFIELD | |
96 | +char g_option_fastfield; | |
93 | 97 | |
94 | 98 | // General purpose integer used for asigning value with pointer |
95 | 99 | int g_temp; |
@@ -635,11 +635,13 @@ SYSTEM関数及びSYSTEMステートメントを用いて、各種システム | ||
635 | 635 | SYSTEM$(0) |
636 | 636 | MachiKania バージョン文字列、"Zoea"等を返す。 |
637 | 637 | SYSTEM$(1) |
638 | - MachiKania バージョン文字列、"1.0"等を返す。 | |
638 | + MachiKania バージョン文字列、"1.2"等を返す。 | |
639 | 639 | SYSTEM$(2) |
640 | - BASIC バージョン文字列、"KM-1200"等を返す。 | |
640 | + BASIC バージョン文字列、"KM-1208"等を返す。 | |
641 | 641 | SYSTEM$(3) |
642 | 642 | 現在実行中のHEXファイル名、"ZOEA.HEX"等を返す。 |
643 | +SYSTEM(4) | |
644 | + 現在実行中のCPUのクロック周波数を返す。 | |
643 | 645 | SYSTEM(20) |
644 | 646 | キャラクターディスプレイ横幅を返す。 |
645 | 647 | SYSTEM(21) |
@@ -817,7 +819,7 @@ CALL x | ||
817 | 819 | <ヒント> |
818 | 820 | MachiKania ver 1.2 以降、FOR-NEXTループ、WHILE-WENDループ、DO-LOOPループの途中で、 |
819 | 821 | RETURN文が使えるようになりました。ただし、GOTO文でループの外に飛ぶと、予期せぬ結 |
820 | -果(機器のリセット等)を引き起こします。ただし、GOSUB文でサブルーチンを呼んだり、別の | |
822 | +果(機器のリセット等)を引き起こします。また、GOSUB文でサブルーチンを呼んだり、別の | |
821 | 823 | ループをネストして使う事は可能です。 |
822 | 824 | |
823 | 825 | ON GOTO分やON GOSUB文はサポートしていません。ただし、例えば次のように記述す |
@@ -841,6 +843,7 @@ ON GOTO分やON GOSUB文はサポートしていません。ただし、例え | ||
841 | 843 | ・オプション機能(OPTIONステートメント)を追加。 |
842 | 844 | ・アイドル機能(IDLEステートメント)を追加。 |
843 | 845 | ・EXEC()関数を追加。 |
846 | + ・変数名などで、英数字に加えてアンダースコアーが使用可能に。 | |
844 | 847 | ・KM-1302 2019年3月公開。 |
845 | 848 | ・オブジェクト指向プログラミングに対応 |
846 | 849 | ・args(0)で引数の数を取得できるようにした |
@@ -1568,7 +1568,9 @@ char* option_statement(){ | ||
1568 | 1568 | while(1){ |
1569 | 1569 | next_position(); |
1570 | 1570 | if (nextCodeIs("NOLINENUM")) { |
1571 | - g_nolinenum=1; | |
1571 | + g_option_nolinenum=1; | |
1572 | + } else if (nextCodeIs("FASTFIELD")) { | |
1573 | + g_option_fastfield=1; | |
1572 | 1574 | } else { |
1573 | 1575 | return ERR_SYNTAX; |
1574 | 1576 | } |