BASIC compiler/interpreter for PIC32MX/MZ-80K
Révision | 5025b7002e63c4f661ea6926925df1a3f09d6f92 (tree) |
---|---|
l'heure | 2019-01-17 07:46:56 |
Auteur | Katsumi <kmorimatsu@sour...> |
Commiter | Katsumi |
Allow using string in fields, and dimension in private fields.
Methods returning strings.
Allow inserting space(s) in integer/float literals.
@@ -124,7 +124,7 @@ char* construct_class_structure(int class){ | ||
124 | 124 | num=((num>>8)&0xff)+(num&0xff); |
125 | 125 | for(i=1;i<=num;i++){ |
126 | 126 | if (( |
127 | - g_class_structure[i*2+1]=search_var_name(g_class_structure[i*2])+ALLOC_LNV_BLOCK | |
127 | + g_class_structure[i*2+1]=search_var_name(0x7FFFFFFF & g_class_structure[i*2])+ALLOC_LNV_BLOCK | |
128 | 128 | )<ALLOC_LNV_BLOCK) return ERR_UNKNOWN; |
129 | 129 | } |
130 | 130 | return 0; |
@@ -246,7 +246,18 @@ char* field_statement(){ | ||
246 | 246 | // Register varname |
247 | 247 | err=register_var_name(i); |
248 | 248 | if (err) return err; |
249 | - if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') g_srcpos++; | |
249 | + if (g_source[g_srcpos]=='#') { | |
250 | + g_srcpos++; | |
251 | + } else if (g_source[g_srcpos]=='$') { | |
252 | + // String field. Raise 31st bit. | |
253 | + g_srcpos++; | |
254 | + i|=0x80000000; | |
255 | + } else if (g_source[g_srcpos]=='(' && g_source[g_srcpos+1]==')' && is_private) { | |
256 | + // Dimension field (private only). Raise 31st bit. | |
257 | + g_srcpos++; | |
258 | + g_srcpos++; | |
259 | + i|=0x80000000; | |
260 | + } | |
250 | 261 | // Register field |
251 | 262 | data[0]=i; |
252 | 263 | if (is_private) { |
@@ -330,23 +341,40 @@ char* obj_method(int method){ | ||
330 | 341 | |
331 | 342 | /* |
332 | 343 | char* integer_obj_field(); |
344 | + char* string_obj_field(); | |
345 | + char* float_obj_field(); | |
333 | 346 | Implementation of access to field of object. |
334 | 347 | This feature is recursive. When an object is applied to the field of another object, |
335 | 348 | following expression is possible (for example): |
336 | 349 | obj1.field1.field2 |
337 | 350 | |
338 | 351 | */ |
339 | -char* integer_obj_field(){ | |
352 | + | |
353 | +#define OBJ_FIELD_INTEGER 0 | |
354 | +#define OBJ_FIELD_STRING '$' | |
355 | +#define OBJ_FIELD_FLOAT '#' | |
356 | + | |
357 | +char* _obj_field(char mode){ | |
340 | 358 | // $v0 contains the address of object. |
341 | 359 | int i; |
342 | 360 | char* err; |
343 | 361 | do { |
344 | 362 | i=check_var_name(); // TODO: consider accepting reserbed var names for field name |
345 | 363 | if (i<65536) return ERR_SYNTAX; |
346 | - if (g_source[g_srcpos]=='(') { | |
364 | + if (g_source[g_srcpos]=='(' && mode==OBJ_FIELD_INTEGER) { | |
347 | 365 | // This is a method |
348 | 366 | g_srcpos++; |
349 | 367 | return obj_method(i); |
368 | + } else if (g_source[g_srcpos+1]=='(') { | |
369 | + if (g_source[g_srcpos]==mode) { | |
370 | + // This is a string/float method | |
371 | + g_srcpos++; | |
372 | + g_srcpos++; | |
373 | + return obj_method(i); | |
374 | + } | |
375 | + } else if (g_source[g_srcpos]==mode && mode==OBJ_FIELD_STRING) { | |
376 | + // This is a string field. Raise 31st bit. | |
377 | + i|=0x80000000; | |
350 | 378 | } |
351 | 379 | check_obj_space(2); |
352 | 380 | g_object[g_objpos++]=0x3C050000|((i>>16)&0x0000FFFF); // lui a1,xxxx |
@@ -360,10 +388,27 @@ char* integer_obj_field(){ | ||
360 | 388 | continue; |
361 | 389 | } |
362 | 390 | } while(0); |
363 | - return 0; | |
391 | + // All done. Check variable type | |
392 | + if (mode==OBJ_FIELD_INTEGER) return 0; | |
393 | + else if (g_source[g_srcpos]==mode) { | |
394 | + g_srcpos++; | |
395 | + return 0; | |
396 | + } else return ERR_SYNTAX; | |
364 | 397 | } |
365 | 398 | |
366 | -unsigned long long lib_obj_field(int* object, int fieldname){ | |
399 | +char* integer_obj_field(){ | |
400 | + return _obj_field(OBJ_FIELD_INTEGER); | |
401 | +} | |
402 | + | |
403 | +char* string_obj_field(){ | |
404 | + return _obj_field(OBJ_FIELD_STRING); | |
405 | +} | |
406 | + | |
407 | +char* float_obj_field(){ | |
408 | + return _obj_field(OBJ_FIELD_FLOAT); | |
409 | +} | |
410 | + | |
411 | +int lib_obj_field(int* object, int fieldname){ | |
367 | 412 | int* class; |
368 | 413 | int i,numfield; |
369 | 414 | // Check if this is an object (if within the RAM). |
@@ -377,7 +422,21 @@ unsigned long long lib_obj_field(int* object, int fieldname){ | ||
377 | 422 | } |
378 | 423 | if (i==numfield) err_not_field(fieldname,class[0]); |
379 | 424 | // Got address of field. Return value as $v0 and address as $v1. |
380 | - return (((unsigned long long)(unsigned long)(&object[1+i]))<<32) | (unsigned long long)object[1+i]; | |
425 | + g_temp=(int)(&object[1+i]); | |
426 | + asm volatile("la $v1,%0"::"i"(&g_temp)); | |
427 | + asm volatile("lw $v1,0($v1)"); | |
428 | + return object[1+i]; | |
429 | +} | |
430 | + | |
431 | +/* | |
432 | + Library for letting string field | |
433 | +*/ | |
434 | + | |
435 | +void lib_let_str_field(char* prev_str, char* new_str){ | |
436 | + int var_num=get_permanent_var_num(); | |
437 | + free_perm_str(prev_str); | |
438 | + lib_let_str(new_str,var_num); | |
439 | + return; | |
381 | 440 | } |
382 | 441 | |
383 | 442 | /* |
@@ -398,12 +457,16 @@ int lib_pre_method(int* object, int methodname){ | ||
398 | 457 | // Public fields |
399 | 458 | class+=2; |
400 | 459 | g_var_mem[class[1]]=object[i+1]; |
460 | + // When string, move from permanent block | |
461 | + if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]); | |
401 | 462 | } |
402 | 463 | num+=(nums>>8)&0xff; |
403 | 464 | for(i=i;i<num;i++){ |
404 | 465 | // Private fields |
405 | 466 | class+=2; |
406 | 467 | g_var_mem[class[1]]=object[i+1]; |
468 | + // When string/dimension, move from permanent block | |
469 | + if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]); | |
407 | 470 | } |
408 | 471 | // Seek method |
409 | 472 | num+=(nums>>16)&0xff; |
@@ -432,12 +495,20 @@ int lib_post_method(int* object, int methodname, int v0){ | ||
432 | 495 | // Public fields |
433 | 496 | class+=2; |
434 | 497 | object[i+1]=g_var_mem[class[1]]; |
498 | + // When string, move to permanent block | |
499 | + if (0x80000000&class[0]) { | |
500 | + if (g_var_size[class[1]]) move_to_perm_block(class[1]); | |
501 | + } | |
435 | 502 | } |
436 | 503 | num+=(nums>>8)&0xff; |
437 | 504 | for(i=i;i<num;i++){ |
438 | 505 | // Private fields |
439 | 506 | class+=2; |
440 | 507 | object[i+1]=g_var_mem[class[1]]; |
508 | + // When string/dimension, move to permanent block | |
509 | + if (0x80000000&class[0]) { | |
510 | + if (g_var_size[class[1]]) move_to_perm_block(class[1]); | |
511 | + } | |
441 | 512 | } |
442 | 513 | // all done |
443 | 514 | return v0; |
@@ -0,0 +1,129 @@ | ||
1 | +<クラスとオブジェクトの利用方法> | |
2 | + | |
3 | +ここでは、オブジェクト指向プログラミングについて述べます。MachiKaniaでは、クラス | |
4 | +ベースのオブジェクト指向プログラミングが可能です。次のような特徴があります。 | |
5 | + | |
6 | + 1)オブジェクトは、フィールド(public もしくは private)とメソッド(public のみ) | |
7 | + を持つ。 | |
8 | + 2)クラスの記述は別ファイルに於いて行ない、1ファイルに1クラスの記述とする。 | |
9 | + 3)複数のクラスを利用出来る。また、クラス中で別のクラスを利用出来る。 | |
10 | + 4)クラスの継承は、未実装。 | |
11 | + 5)フィールド名とメソッド名には、6文字以内の英数字が指定出来る。 | |
12 | + | |
13 | +別ファイルとしてクラスを記述し、このファイルをクラス指定する事で、複数のファイル | |
14 | +からなるプログラムを作成する事が可能です。クラス間の接続はフィールドとメソッドを | |
15 | +介してのみ行なわれます。したがって、同じ名前の変数やラベルが複数のファイルに於い | |
16 | +て存在していたとしても、それぞれファイルごとに制御が行なわれますので、名前の衝突 | |
17 | +が起きる事はありません。 | |
18 | + | |
19 | +<クラスの記述の仕方> | |
20 | + | |
21 | +クラスを作成するには、"クラス名.BAS"の名でテキストファイルを準備します。ただし、 | |
22 | +クラス名は6文字以内の英数字です。クラスファイルでは、FIELDとMETHODの2種類の命 | |
23 | +令が必須です(どちらか一方だけでも使えます)。 | |
24 | + | |
25 | +FIELD [PUBLIC] x[,y[,z[, ... ]]] | |
26 | + クラスファイル中で、パブリックフィールドを宣言する。"PUBLIC"は省略可。 | |
27 | + x,y,z等はフィールド名を6文字以内の英数字で指定。 | |
28 | +FIELD PRIVATE x[,y[,z[, ... ]]] | |
29 | + クラスファイル中で、プライベートフィールドを宣言する。x,y,z等はフィールド | |
30 | + 名を6文字以内の英数字で指定。 | |
31 | +METHOD x | |
32 | + クラスファイル中で、メソッドを宣言する。xは、メソッド名を6文字以内の英 | |
33 | + 数字で指定。 | |
34 | + | |
35 | +クラスファイル中でフィールド値(パブリック・プライベートの両方)にアクセスする場 | |
36 | +合は、FIELD指定した長い名前の変数に直接アクセス(読み込み及び書き込み)して下さい。 | |
37 | +「THIS」などの表記は必要ありません。 | |
38 | + | |
39 | +オブジェクトのフィールドではないスタティックな変数を扱いたい時は、USEVAR命令を | |
40 | +使って下さい。ここで使用した長い名前の変数は、他のファイルでの同一名の変数の値に | |
41 | +影響しません。ただし、変数A-Zの読み出し・変更は、他のファイルで使用する値に影響し | |
42 | +ます。 | |
43 | + | |
44 | +METHOD命令で宣言されたメソッドは、すべてパブリックです。プライベートなサブルー | |
45 | +チン呼び出しには、LABEL命令とGOSUB命令/関数を用いて下さい。メソッド呼び出しの際 | |
46 | +の引数は、ARGS()関数で取り出す事が可能です。 | |
47 | + | |
48 | +コンストラクターを指定する場合は、「METHOD INIT」として下さい。このようにINIT | |
49 | +メソッドが指定された場合、オブジェクト作成時に、このメソッドが呼ばれます。INIT | |
50 | +メソッドに引数を与える事も可能です(引数は必須ではありません)。 | |
51 | + | |
52 | +記述例(CLASS1.BASの名前で保存): | |
53 | + FIELD PUBLIC TEST1,TEST2 | |
54 | + FIELD PRIVATE TEST3 | |
55 | + METHOD INIT | |
56 | + IF ARGS(0)=2 THEN | |
57 | + TEST1=ARGS(1) | |
58 | + TEST2=ARGS(2) | |
59 | + ENDIF | |
60 | + RETURN | |
61 | + METHOD TEST4 | |
62 | + TEST1=ARGS(1) | |
63 | + TEST2=ARGS(2) | |
64 | + RETURN | |
65 | + METHOD TEST5 | |
66 | + TEST3=TEST1+TEST2 | |
67 | + RETURN | |
68 | + METHOD TEST6 | |
69 | + RETURN TEST3 | |
70 | + | |
71 | +<オブジェクトの作成方法> | |
72 | + | |
73 | +オブジェクトを作成するためには、まずUSECLASS命令で使用するクラスを指定し、次に | |
74 | +NEW関数を用います。 | |
75 | + | |
76 | +USECLASS x[,y[,z[, ... ]]] | |
77 | + クラスの利用を宣言する。x,y,z等は、クラス名を6文字以内の英数字で指定。 | |
78 | +NEW(x[,y[,z[, ... ]]]) | |
79 | + クラスオブジェクトを作成し、オブジェクトへのポインターを返す。xはクラス名 | |
80 | + を指定。y,z等はコンストラクターがある際に利用される引数。 | |
81 | + | |
82 | +記述例1: | |
83 | + USECLASS CLASS1 | |
84 | + A=NEW(CLASS1) | |
85 | + | |
86 | +記述例2(コンストラクターに引数を指定する場合): | |
87 | + USECLASS CLASS1 | |
88 | + A=NEW(CLASS1,123,456) | |
89 | + | |
90 | +<オブジェクトの破棄方法> | |
91 | + | |
92 | +作成したオブジェクトは、DELETE命令を用いて破棄する事も出来ます。ただし、デストラ | |
93 | +クターは実装していませんので、必要ならば、それ用のメソッドを作成して破棄する直前に | |
94 | +呼び出して下さい。 | |
95 | + | |
96 | +記述例: | |
97 | + USECLASS CLASS1 | |
98 | + A=NEW(CLASS1) | |
99 | + DELETE A | |
100 | + | |
101 | +<フィールドへのアクセス方法> | |
102 | + | |
103 | +パブリックフィールドへアクセスする場合は、オブジェクトを含む変数に続けて「.」と | |
104 | +フィールド名を記述して下さい。 | |
105 | + | |
106 | +記述例: | |
107 | + USECLASS CLASS1 | |
108 | + A=NEW(CLASS1) | |
109 | + A.TEST1=123 | |
110 | + PRINT A.TEST2 | |
111 | + | |
112 | +<メソッドへのアクセス方法> | |
113 | + | |
114 | +パブリックメソッドへアクセスする場合は、オブジェクトを含む変数に続けて「.」と | |
115 | +メソッド名、続けて「( )」を記述して下さい。メソッドは関数と同じ扱いですが、戻 | |
116 | +り値を利用しない場合は、CALL命令により呼び出す事も出来ます。 | |
117 | + | |
118 | +CALL x | |
119 | + xで指定されたオブジェクトのメソッドを呼び出す。 | |
120 | + | |
121 | +記述例(579が表示される): | |
122 | + USECLASS CLASS1 | |
123 | + A=NEW(CLASS1) | |
124 | + CALL A.TEST4(123,456) | |
125 | + CALL A.TEST5() | |
126 | + PRINT A.TEST6() | |
127 | + | |
128 | +<バージョン履歴> | |
129 | +・KM-1207/KM1302 20xx年x月公開。 |
@@ -282,10 +282,12 @@ void call_library(void); | ||
282 | 282 | void reset_dataread(); |
283 | 283 | |
284 | 284 | void free_temp_str(char* str); |
285 | +void free_perm_str(char* str); | |
285 | 286 | void* alloc_memory(int size, int var_num); |
286 | 287 | void* calloc_memory(int size, int var_num); |
287 | 288 | void move_to_perm_block(int var_num); |
288 | 289 | void move_from_perm_block(int var_num); |
290 | +int move_from_perm_block_if_exists(int var_num); | |
289 | 291 | int get_permanent_var_num(void); |
290 | 292 | int get_varnum_from_address(void* address); |
291 | 293 | void* lib_calloc_memory(int size); |
@@ -335,12 +337,15 @@ void delete_cmpdata_for_class(); | ||
335 | 337 | char* new_function(); |
336 | 338 | char* field_statement(); |
337 | 339 | char* integer_obj_field(); |
338 | -unsigned long long lib_obj_field(int* object, int fieldname); | |
340 | +char* string_obj_field(); | |
341 | +char* float_obj_field(); | |
342 | +int lib_obj_field(int* object, int fieldname); | |
339 | 343 | int lib_pre_method(int* object, int methodname); |
340 | 344 | int lib_post_method(int* object, int methodname, int v0); |
341 | 345 | char* method_statement(); |
342 | 346 | char* delete_statement(); |
343 | 347 | char* call_statement(); |
348 | +void lib_let_str_field(char* str, char* prev_str); | |
344 | 349 | |
345 | 350 | /* Error messages */ |
346 | 351 | #define ERR_SYNTAX (char*)(g_err_str[0]) |
@@ -227,13 +227,17 @@ static const char initext[]= | ||
227 | 227 | |
228 | 228 | static const char bastext[]= |
229 | 229 | "CLS\n" |
230 | -"dim a(0)\n" | |
231 | -"a(0)=0x89ABCDEF\n" | |
232 | -"print hex$(peek(a)),\n" | |
233 | -"print hex$(peek16(a)),\n" | |
234 | -"print hex$(peek32(a)),\n" | |
230 | +"print 12 345.6,12 345 678,hex$(0x0ABC 123),hex$(0x0123 CDEF)\n" | |
231 | +"end\n" | |
232 | +"REM \x80\n" | |
235 | 233 | "\n" |
236 | 234 | "\n" |
235 | +"USECLASS CLASS1\n" | |
236 | +"a=new(CLASS1)\n" | |
237 | +"print a.TEST$,a.TEST2$(),\n" | |
238 | +"a.TEST$=\"ABC\"\n" | |
239 | +"print a.TEST$,\n" | |
240 | +"\n" | |
237 | 241 | "\n" |
238 | 242 | "\n" |
239 | 243 | "\n" |
@@ -242,15 +246,17 @@ static const char bastext[]= | ||
242 | 246 | |
243 | 247 | static const char classtext[]= |
244 | 248 | "REM\n" |
245 | -"FIELD test,test2\n" | |
246 | -"FIELD PRIVATE test3,test4\n" | |
247 | -"METHOD mtest\n" | |
248 | -"PRINT ARGS(0),ARGS(1),ARGS(2)\n" | |
249 | -"test2=7890\n" | |
250 | -"return test+10000\n" | |
249 | +"FIELD TEST$,TEST3\n" | |
251 | 250 | "METHOD INIT\n" |
252 | -"PRINT \"INIT\"\n" | |
251 | +"TEST$=\"MachiKania\"\n" | |
252 | +"TEST3#=1.2345\n" | |
253 | 253 | "return\n" |
254 | +"METHOD TEST2\n" | |
255 | +"return \"Objective\"\n" | |
256 | +"METHOD TEST4\n" | |
257 | +"return PI#\n" | |
258 | +"\n" | |
259 | +"\n" | |
254 | 260 | "\n" |
255 | 261 | "\n"; |
256 | 262 |
@@ -265,9 +271,7 @@ static const void* debugjumptable[]={ | ||
265 | 271 | |
266 | 272 | int _debug_test(int a0, int a1, int a2, int a3, int param4, int param5){ |
267 | 273 | asm volatile(".set noreorder"); |
268 | - asm volatile("lbu $v0,0($v0)"); | |
269 | - asm volatile("lhu $v0,0($v0)"); | |
270 | - asm volatile("lw $v0,0($v0)"); | |
274 | + asm volatile("lw $a0,0($v1)"); | |
271 | 275 | asm volatile("nop"); |
272 | 276 | asm volatile("nop"); |
273 | 277 | asm volatile("nop"); |
@@ -187,7 +187,7 @@ void err_not_obj(void){ | ||
187 | 187 | void err_not_field(int fieldname, int classname){ |
188 | 188 | printstr(resolve_label(classname)); |
189 | 189 | printchar('.'); |
190 | - printstr(resolve_label(fieldname)); | |
190 | + printstr(resolve_label(fieldname & 0x7FFFFFFF)); | |
191 | 191 | printstr(ERR_NOT_FIELD); |
192 | 192 | end_exec(); |
193 | 193 | } |
@@ -68,6 +68,13 @@ char* get_simple_float(void){ | ||
68 | 68 | // Must be a function. |
69 | 69 | return float_function(); |
70 | 70 | } |
71 | + if (g_source[g_srcpos]=='.') { | |
72 | + // This is an object field or method to return string | |
73 | + check_obj_space(1); | |
74 | + g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
75 | + g_srcpos++; | |
76 | + return float_obj_field(); | |
77 | + } | |
71 | 78 | if (g_source[g_srcpos]!='#') return ERR_SYNTAX; |
72 | 79 | g_srcpos++; |
73 | 80 | if (g_source[g_srcpos]=='(') { |
@@ -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文字ずつ |
@@ -287,6 +293,12 @@ NOT(x) | ||
287 | 293 | x=0の場合に1を、そうでない場合に0を返す。 |
288 | 294 | PEEK(x) |
289 | 295 | xで示される物理アドレスから1バイト読み取り、返す。 |
296 | +PEEK16(x) | |
297 | + xで示される物理アドレスから2バイト読み取り、16ビット値で返す。xが奇数値の場 | |
298 | + 合、例外停止するので注意。 | |
299 | +PEEK32(x) | |
300 | + xで示される物理アドレスから4バイト読み取り、32ビット値で返す。xが4の倍数で | |
301 | + 無い場合、例外停止するので注意。 | |
290 | 302 | PLAYWAVE([x]) |
291 | 303 | xを指定しない場合、もしくは0を指定した場合、再生中のWAVEファイルの残りサン |
292 | 304 | プリング数を返す。1を指定した場合、現在再生中のサンプリング番号を、2を指 |
@@ -396,6 +408,8 @@ READ$() | ||
396 | 408 | DATA文の後から、一つずつ文字列データーを読み出す。 |
397 | 409 | |
398 | 410 | <整数演算子> |
411 | +&x | |
412 | + 変数xの格納アドレス(ポインター) | |
399 | 413 | -x |
400 | 414 | 符号を反転 |
401 | 415 | x + y |
@@ -433,7 +447,7 @@ x XOR y | ||
433 | 447 | |
434 | 448 | なお、整数演算子の優先順位は、優先度が高いものから以下の順です。 |
435 | 449 | |
436 | -+ - (単項演算子) | |
450 | ++ - (単項演算子) & | |
437 | 451 | * / % |
438 | 452 | + - (加算・減算) |
439 | 453 | << >> |
@@ -710,6 +724,11 @@ ON GOTO分やON GOSUB文はサポートしていません。ただし、例え | ||
710 | 724 | てみて下さい。 |
711 | 725 | |
712 | 726 | <バージョン履歴> |
727 | +・KM-1302 2019年xx月公開。 | |
728 | + ・オブジェクト指向プログラミングに対応 | |
729 | + ・args(0)で引数の数を取得できるようにした | |
730 | + ・POKE16, POKE32, PEEK16(), PEEK32()を追加 | |
731 | + ・&演算子を追加 | |
713 | 732 | ・KM-1301 2018年12月公開。 |
714 | 733 | ・I2C機能を搭載 |
715 | 734 | ・SPI機能を搭載 |
@@ -68,6 +68,7 @@ file_040=. | ||
68 | 68 | file_041=. |
69 | 69 | file_042=. |
70 | 70 | file_043=. |
71 | +file_044=. | |
71 | 72 | [GENERATED_FILES] |
72 | 73 | file_000=no |
73 | 74 | file_001=no |
@@ -113,6 +114,7 @@ file_040=no | ||
113 | 114 | file_041=no |
114 | 115 | file_042=no |
115 | 116 | file_043=no |
117 | +file_044=no | |
116 | 118 | [OTHER_FILES] |
117 | 119 | file_000=no |
118 | 120 | file_001=no |
@@ -158,6 +160,7 @@ file_040=no | ||
158 | 160 | file_041=no |
159 | 161 | file_042=yes |
160 | 162 | file_043=yes |
163 | +file_044=yes | |
161 | 164 | [FILE_INFO] |
162 | 165 | file_000=compiler.c |
163 | 166 | file_001=debug.c |
@@ -203,6 +206,7 @@ file_040=lib_videoout_megalopa.X.a | ||
203 | 206 | file_041=app_p32MX370F512H.ld |
204 | 207 | file_042=help.txt |
205 | 208 | file_043=reservednames.js |
209 | +file_044=class.txt | |
206 | 210 | [SUITE_INFO] |
207 | 211 | suite_guid={62D235D8-2DB2-49CD-AF24-5489A6015337} |
208 | 212 | suite_state= |
@@ -17,11 +17,9 @@ | ||
17 | 17 | This number also includes temporary area used for string construction etc. |
18 | 18 | Temporary area is cleared every line of BASIC code in alloc_memory(). |
19 | 19 | ALLOC_BLOCK_NUM: # of blocks that can be used for memory allocation. |
20 | - This # also includes the ones for ALLOC_VAR_NUM. | |
20 | + This # includes the ones for ALLOC_VAR_NUM, ALLOC_PCG_BLOCK etc, ALLOC_LNV_BLOCK, | |
21 | + ALLOC_PERM_BLOCK. | |
21 | 22 | After ALLOC_VAR_NUM area, dedicated memory area and permanent area follows. |
22 | - Currently, only PCG is used for permanent pourpose. | |
23 | - 10 permanant blocks can be used. | |
24 | - Therefore, ALLOC_VAR_NUM+11 == ALLOC_BLOCK_NUM | |
25 | 23 | ALLOC_PERM_BLOCK: Start # of permanent blocks. |
26 | 24 | The blocks after this number is permanently stored. |
27 | 25 | Therefore, it must be released when it's not used any more. |
@@ -144,6 +142,20 @@ void free_temp_str(char* str){ | ||
144 | 142 | } |
145 | 143 | } |
146 | 144 | |
145 | +void free_perm_str(char* str){ | |
146 | + int i,pointer; | |
147 | + if (!str) return; | |
148 | + pointer=(int)str-(int)g_heap_mem; | |
149 | + pointer>>=2; | |
150 | + // Search permanent block and delete a block if found. | |
151 | + for(i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){ | |
152 | + if (g_var_pointer[i]==pointer) { | |
153 | + g_var_size[i]=0; | |
154 | + break; | |
155 | + } | |
156 | + } | |
157 | +} | |
158 | + | |
147 | 159 | void move_to_perm_block(int var_num){ |
148 | 160 | int i; |
149 | 161 | // Find available permanent block |
@@ -161,7 +173,7 @@ void move_to_perm_block(int var_num){ | ||
161 | 173 | g_var_mem[var_num]=0; |
162 | 174 | } |
163 | 175 | |
164 | -void move_from_perm_block(int var_num){ | |
176 | +int move_from_perm_block_if_exists(int var_num){ | |
165 | 177 | int i,pointer; |
166 | 178 | pointer=(int)g_var_mem[var_num]-(int)g_heap_mem; |
167 | 179 | pointer>>=2; |
@@ -169,13 +181,19 @@ void move_from_perm_block(int var_num){ | ||
169 | 181 | for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){ |
170 | 182 | if (0<g_var_size[i] && g_var_pointer[i]==pointer) break; |
171 | 183 | } |
172 | - if (ALLOC_BLOCK_NUM<=i) err_unknown(); // Not found | |
184 | + if (ALLOC_BLOCK_NUM<=i) return 0; // Not found | |
173 | 185 | // Stored block found. |
174 | 186 | // Replace pointer |
175 | 187 | g_var_size[var_num]=g_var_size[i]; |
176 | 188 | g_var_pointer[var_num]=g_var_pointer[i]; |
177 | 189 | // Clear block |
178 | 190 | g_var_size[i]=0; |
191 | + return 1; | |
192 | +} | |
193 | + | |
194 | +void move_from_perm_block(int var_num){ | |
195 | + if (move_from_perm_block_if_exists(var_num)) return; // Found | |
196 | + err_unknown(); // Not found | |
179 | 197 | } |
180 | 198 | |
181 | 199 | int get_permanent_var_num(){ |
@@ -18,7 +18,7 @@ char* rem_statement(){ | ||
18 | 18 | // Delete $s6-setting command if exists. |
19 | 19 | if ((g_object[g_objpos-1]&0xffff0000)==0x34160000) g_objpos--; |
20 | 20 | } |
21 | - while(0x20<=g_source[g_srcpos]){ | |
21 | + while(0xE0 & g_source[g_srcpos]){ | |
22 | 22 | g_srcpos++; |
23 | 23 | } |
24 | 24 | return 0; |
@@ -641,7 +641,7 @@ char* let_dim_sub(int i){ | ||
641 | 641 | char* let_statement(){ |
642 | 642 | char* err; |
643 | 643 | char b2,b3; |
644 | - int i; | |
644 | + int i,spos,opos; | |
645 | 645 | next_position(); |
646 | 646 | i=get_var_number(); |
647 | 647 | if (i<0) return ERR_SYNTAX; |
@@ -706,23 +706,61 @@ char* let_statement(){ | ||
706 | 706 | g_srcpos++; |
707 | 707 | check_obj_space(1); |
708 | 708 | g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) |
709 | - err=integer_obj_field(); | |
710 | - if (err) return err; | |
709 | + spos=g_srcpos; | |
710 | + opos=g_objpos; | |
711 | + // Try string field, first | |
712 | + err=string_obj_field(); | |
713 | + if (err) { | |
714 | + // Integer or float field | |
715 | + g_srcpos=spos; | |
716 | + g_objpos=opos; | |
717 | + err=integer_obj_field(); | |
718 | + if (err) return err; | |
719 | + b3=g_source[g_srcpos]; | |
720 | + if (b3=='#') g_srcpos++; | |
721 | + } else { | |
722 | + // String field | |
723 | + b3='$'; | |
724 | + } | |
725 | + if (g_source[g_srcpos-1]==')') { | |
726 | + // This is a CALL statement | |
727 | + return 0; | |
728 | + } | |
711 | 729 | // $v1 is address to store value. Save it in stack. |
712 | 730 | check_obj_space(1); |
713 | 731 | g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 |
714 | 732 | g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) |
715 | - // Get value | |
716 | - next_position(); | |
717 | - if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
718 | - g_srcpos++; | |
719 | - err=get_value(); | |
733 | + if (b3=='$') { | |
734 | + // String field | |
735 | + // Get value | |
736 | + next_position(); | |
737 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
738 | + g_srcpos++; | |
739 | + err=get_string(); | |
740 | + } else if (b3=='#') { | |
741 | + // Float field | |
742 | + // Get value | |
743 | + next_position(); | |
744 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
745 | + g_srcpos++; | |
746 | + err=get_float(); | |
747 | + } else { | |
748 | + // Integer field | |
749 | + // Get value | |
750 | + next_position(); | |
751 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
752 | + g_srcpos++; | |
753 | + err=get_value(); | |
754 | + } | |
720 | 755 | if (err) return err; |
721 | 756 | // Store in field of object |
722 | - check_obj_space(3); | |
757 | + check_obj_space(4); | |
723 | 758 | g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) |
724 | 759 | g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 |
760 | + g_object[g_objpos++]=0x8C640000; // lw a0,0(v1) | |
725 | 761 | g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) |
762 | + // Handle permanent block for string field | |
763 | + if (b3=='$') call_quicklib_code(lib_let_str_field,ASM_ADDU_A1_V0_ZERO); | |
726 | 764 | } else { |
727 | 765 | // Integer A-Z |
728 | 766 | next_position(); |
@@ -92,6 +92,13 @@ char* simple_string(void){ | ||
92 | 92 | g_temp_area_used=1; |
93 | 93 | return 0; |
94 | 94 | } |
95 | + if (g_source[g_srcpos]=='.') { | |
96 | + // This is an object field or method to return string | |
97 | + check_obj_space(1); | |
98 | + g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
99 | + g_srcpos++; | |
100 | + return string_obj_field(); | |
101 | + } | |
95 | 102 | if (g_source[g_srcpos]!='$') return ERR_SYNTAX; |
96 | 103 | g_srcpos++; |
97 | 104 | // String variable |
@@ -103,7 +103,7 @@ char* get_simple_value(void){ | ||
103 | 103 | } else if ('A'<=b1 && b1<='F') { |
104 | 104 | i*=16; |
105 | 105 | i+=b1-'A'+0x0A; |
106 | - } else { | |
106 | + } else if (b1!=' ') { // Skip ' ' | |
107 | 107 | break; |
108 | 108 | } |
109 | 109 | g_srcpos++; |
@@ -127,7 +127,7 @@ char* get_simple_value(void){ | ||
127 | 127 | if ('0'<=b1 && b1<='9') { |
128 | 128 | i*=10; |
129 | 129 | i+=b1-'0'; |
130 | - } else { | |
130 | + } else if (b1!=' ') { // Skip ' ' | |
131 | 131 | break; |
132 | 132 | } |
133 | 133 | g_srcpos++; |