• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

BASIC compiler/interpreter for PIC32MX/MZ-80K


Commit MetaInfo

Révision5025b7002e63c4f661ea6926925df1a3f09d6f92 (tree)
l'heure2019-01-17 07:46:56
AuteurKatsumi <kmorimatsu@sour...>
CommiterKatsumi

Message de Log

Allow using string in fields, and dimension in private fields.
Methods returning strings.
Allow inserting space(s) in integer/float literals.

Change Summary

Modification

--- a/mips/megalopa/class.c
+++ b/mips/megalopa/class.c
@@ -124,7 +124,7 @@ char* construct_class_structure(int class){
124124 num=((num>>8)&0xff)+(num&0xff);
125125 for(i=1;i<=num;i++){
126126 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
128128 )<ALLOC_LNV_BLOCK) return ERR_UNKNOWN;
129129 }
130130 return 0;
@@ -246,7 +246,18 @@ char* field_statement(){
246246 // Register varname
247247 err=register_var_name(i);
248248 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+ }
250261 // Register field
251262 data[0]=i;
252263 if (is_private) {
@@ -330,23 +341,40 @@ char* obj_method(int method){
330341
331342 /*
332343 char* integer_obj_field();
344+ char* string_obj_field();
345+ char* float_obj_field();
333346 Implementation of access to field of object.
334347 This feature is recursive. When an object is applied to the field of another object,
335348 following expression is possible (for example):
336349 obj1.field1.field2
337350
338351 */
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){
340358 // $v0 contains the address of object.
341359 int i;
342360 char* err;
343361 do {
344362 i=check_var_name(); // TODO: consider accepting reserbed var names for field name
345363 if (i<65536) return ERR_SYNTAX;
346- if (g_source[g_srcpos]=='(') {
364+ if (g_source[g_srcpos]=='(' && mode==OBJ_FIELD_INTEGER) {
347365 // This is a method
348366 g_srcpos++;
349367 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;
350378 }
351379 check_obj_space(2);
352380 g_object[g_objpos++]=0x3C050000|((i>>16)&0x0000FFFF); // lui a1,xxxx
@@ -360,10 +388,27 @@ char* integer_obj_field(){
360388 continue;
361389 }
362390 } 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;
364397 }
365398
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){
367412 int* class;
368413 int i,numfield;
369414 // Check if this is an object (if within the RAM).
@@ -377,7 +422,21 @@ unsigned long long lib_obj_field(int* object, int fieldname){
377422 }
378423 if (i==numfield) err_not_field(fieldname,class[0]);
379424 // 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;
381440 }
382441
383442 /*
@@ -398,12 +457,16 @@ int lib_pre_method(int* object, int methodname){
398457 // Public fields
399458 class+=2;
400459 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]);
401462 }
402463 num+=(nums>>8)&0xff;
403464 for(i=i;i<num;i++){
404465 // Private fields
405466 class+=2;
406467 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]);
407470 }
408471 // Seek method
409472 num+=(nums>>16)&0xff;
@@ -432,12 +495,20 @@ int lib_post_method(int* object, int methodname, int v0){
432495 // Public fields
433496 class+=2;
434497 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+ }
435502 }
436503 num+=(nums>>8)&0xff;
437504 for(i=i;i<num;i++){
438505 // Private fields
439506 class+=2;
440507 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+ }
441512 }
442513 // all done
443514 return v0;
--- /dev/null
+++ b/mips/megalopa/class.txt
@@ -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月公開。
--- a/mips/megalopa/compiler.h
+++ b/mips/megalopa/compiler.h
@@ -282,10 +282,12 @@ void call_library(void);
282282 void reset_dataread();
283283
284284 void free_temp_str(char* str);
285+void free_perm_str(char* str);
285286 void* alloc_memory(int size, int var_num);
286287 void* calloc_memory(int size, int var_num);
287288 void move_to_perm_block(int var_num);
288289 void move_from_perm_block(int var_num);
290+int move_from_perm_block_if_exists(int var_num);
289291 int get_permanent_var_num(void);
290292 int get_varnum_from_address(void* address);
291293 void* lib_calloc_memory(int size);
@@ -335,12 +337,15 @@ void delete_cmpdata_for_class();
335337 char* new_function();
336338 char* field_statement();
337339 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);
339343 int lib_pre_method(int* object, int methodname);
340344 int lib_post_method(int* object, int methodname, int v0);
341345 char* method_statement();
342346 char* delete_statement();
343347 char* call_statement();
348+void lib_let_str_field(char* str, char* prev_str);
344349
345350 /* Error messages */
346351 #define ERR_SYNTAX (char*)(g_err_str[0])
--- a/mips/megalopa/debug.c
+++ b/mips/megalopa/debug.c
@@ -227,13 +227,17 @@ static const char initext[]=
227227
228228 static const char bastext[]=
229229 "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"
235233 "\n"
236234 "\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"
237241 "\n"
238242 "\n"
239243 "\n"
@@ -242,15 +246,17 @@ static const char bastext[]=
242246
243247 static const char classtext[]=
244248 "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"
251250 "METHOD INIT\n"
252-"PRINT \"INIT\"\n"
251+"TEST$=\"MachiKania\"\n"
252+"TEST3#=1.2345\n"
253253 "return\n"
254+"METHOD TEST2\n"
255+"return \"Objective\"\n"
256+"METHOD TEST4\n"
257+"return PI#\n"
258+"\n"
259+"\n"
254260 "\n"
255261 "\n";
256262
@@ -265,9 +271,7 @@ static const void* debugjumptable[]={
265271
266272 int _debug_test(int a0, int a1, int a2, int a3, int param4, int param5){
267273 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)");
271275 asm volatile("nop");
272276 asm volatile("nop");
273277 asm volatile("nop");
--- a/mips/megalopa/error.c
+++ b/mips/megalopa/error.c
@@ -187,7 +187,7 @@ void err_not_obj(void){
187187 void err_not_field(int fieldname, int classname){
188188 printstr(resolve_label(classname));
189189 printchar('.');
190- printstr(resolve_label(fieldname));
190+ printstr(resolve_label(fieldname & 0x7FFFFFFF));
191191 printstr(ERR_NOT_FIELD);
192192 end_exec();
193193 }
--- a/mips/megalopa/float.c
+++ b/mips/megalopa/float.c
@@ -68,6 +68,13 @@ char* get_simple_float(void){
6868 // Must be a function.
6969 return float_function();
7070 }
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+ }
7178 if (g_source[g_srcpos]!='#') return ERR_SYNTAX;
7279 g_srcpos++;
7380 if (g_source[g_srcpos]=='(') {
--- a/mips/megalopa/help.txt
+++ b/mips/megalopa/help.txt
@@ -127,6 +127,12 @@ PCG x,y,z
127127 ターデーター。詳細は、下記<PCG>の項を参照。
128128 POKE x,y
129129 xで示される物理的アドレスに、yで示される値(1バイト値)を書き込む。
130+PEEK16(x)
131+ xで示される物理アドレスに、yで示される値(16ビット値)を書き込む。xが奇数値の
132+ 場合、例外停止するので注意。
133+PEEK32(x)
134+ xで示される物理アドレスに、yで示される値(32ビット値)を書き込む。xが4の倍数で
135+ 無い場合、例外停止するので注意。
130136 PRINT [ xまたはx$またはx# [ ,または; [ yまたはy$またはy# [ ... ]]]]
131137 ディスプレイに、整数値または文字列を表示する。「;」を使用した場
132138 合、次の表示が続けて行われる。「,」を使用した場合、10文字ずつ
@@ -287,6 +293,12 @@ NOT(x)
287293 x=0の場合に1を、そうでない場合に0を返す。
288294 PEEK(x)
289295 xで示される物理アドレスから1バイト読み取り、返す。
296+PEEK16(x)
297+ xで示される物理アドレスから2バイト読み取り、16ビット値で返す。xが奇数値の場
298+ 合、例外停止するので注意。
299+PEEK32(x)
300+ xで示される物理アドレスから4バイト読み取り、32ビット値で返す。xが4の倍数で
301+ 無い場合、例外停止するので注意。
290302 PLAYWAVE([x])
291303 xを指定しない場合、もしくは0を指定した場合、再生中のWAVEファイルの残りサン
292304 プリング数を返す。1を指定した場合、現在再生中のサンプリング番号を、2を指
@@ -396,6 +408,8 @@ READ$()
396408 DATA文の後から、一つずつ文字列データーを読み出す。
397409
398410 <整数演算子>
411+&x
412+ 変数xの格納アドレス(ポインター)
399413 -x
400414 符号を反転
401415 x + y
@@ -433,7 +447,7 @@ x XOR y
433447
434448 なお、整数演算子の優先順位は、優先度が高いものから以下の順です。
435449
436-+ - (単項演算子)
450++ - (単項演算子) &
437451 * / %
438452 + - (加算・減算)
439453 << >>
@@ -710,6 +724,11 @@ ON GOTO分やON GOSUB文はサポートしていません。ただし、例え
710724 てみて下さい。
711725
712726 <バージョン履歴>
727+・KM-1302 2019年xx月公開。
728+ ・オブジェクト指向プログラミングに対応
729+ ・args(0)で引数の数を取得できるようにした
730+ ・POKE16, POKE32, PEEK16(), PEEK32()を追加
731+ ・&演算子を追加
713732 ・KM-1301 2018年12月公開。
714733  ・I2C機能を搭載
715734  ・SPI機能を搭載
--- a/mips/megalopa/megalopa.mcp
+++ b/mips/megalopa/megalopa.mcp
@@ -68,6 +68,7 @@ file_040=.
6868 file_041=.
6969 file_042=.
7070 file_043=.
71+file_044=.
7172 [GENERATED_FILES]
7273 file_000=no
7374 file_001=no
@@ -113,6 +114,7 @@ file_040=no
113114 file_041=no
114115 file_042=no
115116 file_043=no
117+file_044=no
116118 [OTHER_FILES]
117119 file_000=no
118120 file_001=no
@@ -158,6 +160,7 @@ file_040=no
158160 file_041=no
159161 file_042=yes
160162 file_043=yes
163+file_044=yes
161164 [FILE_INFO]
162165 file_000=compiler.c
163166 file_001=debug.c
@@ -203,6 +206,7 @@ file_040=lib_videoout_megalopa.X.a
203206 file_041=app_p32MX370F512H.ld
204207 file_042=help.txt
205208 file_043=reservednames.js
209+file_044=class.txt
206210 [SUITE_INFO]
207211 suite_guid={62D235D8-2DB2-49CD-AF24-5489A6015337}
208212 suite_state=
--- a/mips/megalopa/memory.c
+++ b/mips/megalopa/memory.c
@@ -17,11 +17,9 @@
1717 This number also includes temporary area used for string construction etc.
1818 Temporary area is cleared every line of BASIC code in alloc_memory().
1919 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.
2122 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
2523 ALLOC_PERM_BLOCK: Start # of permanent blocks.
2624 The blocks after this number is permanently stored.
2725 Therefore, it must be released when it's not used any more.
@@ -144,6 +142,20 @@ void free_temp_str(char* str){
144142 }
145143 }
146144
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+
147159 void move_to_perm_block(int var_num){
148160 int i;
149161 // Find available permanent block
@@ -161,7 +173,7 @@ void move_to_perm_block(int var_num){
161173 g_var_mem[var_num]=0;
162174 }
163175
164-void move_from_perm_block(int var_num){
176+int move_from_perm_block_if_exists(int var_num){
165177 int i,pointer;
166178 pointer=(int)g_var_mem[var_num]-(int)g_heap_mem;
167179 pointer>>=2;
@@ -169,13 +181,19 @@ void move_from_perm_block(int var_num){
169181 for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){
170182 if (0<g_var_size[i] && g_var_pointer[i]==pointer) break;
171183 }
172- if (ALLOC_BLOCK_NUM<=i) err_unknown(); // Not found
184+ if (ALLOC_BLOCK_NUM<=i) return 0; // Not found
173185 // Stored block found.
174186 // Replace pointer
175187 g_var_size[var_num]=g_var_size[i];
176188 g_var_pointer[var_num]=g_var_pointer[i];
177189 // Clear block
178190 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
179197 }
180198
181199 int get_permanent_var_num(){
--- a/mips/megalopa/statement.c
+++ b/mips/megalopa/statement.c
@@ -18,7 +18,7 @@ char* rem_statement(){
1818 // Delete $s6-setting command if exists.
1919 if ((g_object[g_objpos-1]&0xffff0000)==0x34160000) g_objpos--;
2020 }
21- while(0x20<=g_source[g_srcpos]){
21+ while(0xE0 & g_source[g_srcpos]){
2222 g_srcpos++;
2323 }
2424 return 0;
@@ -641,7 +641,7 @@ char* let_dim_sub(int i){
641641 char* let_statement(){
642642 char* err;
643643 char b2,b3;
644- int i;
644+ int i,spos,opos;
645645 next_position();
646646 i=get_var_number();
647647 if (i<0) return ERR_SYNTAX;
@@ -706,23 +706,61 @@ char* let_statement(){
706706 g_srcpos++;
707707 check_obj_space(1);
708708 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+ }
711729 // $v1 is address to store value. Save it in stack.
712730 check_obj_space(1);
713731 g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
714732 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+ }
720755 if (err) return err;
721756 // Store in field of object
722- check_obj_space(3);
757+ check_obj_space(4);
723758 g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp)
724759 g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4
760+ g_object[g_objpos++]=0x8C640000; // lw a0,0(v1)
725761 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);
726764 } else {
727765 // Integer A-Z
728766 next_position();
--- a/mips/megalopa/string.c
+++ b/mips/megalopa/string.c
@@ -92,6 +92,13 @@ char* simple_string(void){
9292 g_temp_area_used=1;
9393 return 0;
9494 }
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+ }
95102 if (g_source[g_srcpos]!='$') return ERR_SYNTAX;
96103 g_srcpos++;
97104 // String variable
--- a/mips/megalopa/value.c
+++ b/mips/megalopa/value.c
@@ -103,7 +103,7 @@ char* get_simple_value(void){
103103 } else if ('A'<=b1 && b1<='F') {
104104 i*=16;
105105 i+=b1-'A'+0x0A;
106- } else {
106+ } else if (b1!=' ') { // Skip ' '
107107 break;
108108 }
109109 g_srcpos++;
@@ -127,7 +127,7 @@ char* get_simple_value(void){
127127 if ('0'<=b1 && b1<='9') {
128128 i*=10;
129129 i+=b1-'0';
130- } else {
130+ } else if (b1!=' ') { // Skip ' '
131131 break;
132132 }
133133 g_srcpos++;