• 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évisionff96d68c21430719766477129a3fa47f9c5f400f (tree)
l'heure2019-02-11 12:43:51
AuteurKatsumi <kmorimatsu@sour...>
CommiterKatsumi

Message de Log

Update help texts. Update Zoea.

Change Summary

Modification

--- a/mips/megalopa/class.txt
+++ b/mips/megalopa/class.txt
@@ -56,6 +56,9 @@ METHOD命令で宣言されたメソッドは、すべてパブリックです
5656 メソッドが指定された場合、オブジェクト作成時に、このメソッドが呼ばれます。INIT
5757 メソッドに引数を与える事も可能です(引数は必須ではありません)。
5858
59+クラス中でオブジェクトへのポインターが必要な場合は、ARGS(-2)で取り出す事が出来
60+ます。
61+
5962 記述例(CLASS1.BASの名前で保存):
6063  FIELD PUBLIC TEST1,TEST2
6164  FIELD PRIVATE TEST3
--- a/mips/megalopa/debug.c
+++ b/mips/megalopa/debug.c
@@ -229,10 +229,7 @@ static const char bastext[]=
229229 "USECLASS CLASS1\n"
230230 "CLS\n"
231231 "a=new(CLASS1)\n"
232-"b=a.T3()\n"
233-"c=b.T3()\n"
234-"print a,b,c\n"
235-"print a.T4(),b.T4(),c.T4()\n"
232+"print a.T3()\n"
236233 "\n"
237234 "\n"
238235 "\n"
@@ -242,17 +239,8 @@ static const char bastext[]=
242239
243240
244241 static const char classtext[]=
245-"REM\n"
246-"STATIC T1,T2\n"
247-"FIELD PUBLIC T6\n"
248-"METHOD INIT\n"
249-" T6=rnd()\n"
250-" return\n"
251242 "METHOD T3\n"
252-" o=new(CLASS1)\n"
253-" return o\n"
254-"METHOD T4\n"
255-" return T6\n"
243+" return 123\n"
256244 "\n"
257245 "\n"
258246 "\n"
--- a/mips/megalopa/file.c
+++ b/mips/megalopa/file.c
@@ -192,6 +192,7 @@ int compile_and_link_class(char* buff,int class){
192192 err=end_compiling_class(class);
193193 if (err) break;
194194 // Initial assembly is a jump statement to jump to the end of class file
195+ // Note that there is at least a code (set line # to $s6) before reaching here
195196 g_object[0]=0x08000000 | ((((int)(&g_object[g_objpos]))&0x0FFFFFFF)>>2); // j xxxxxxxx
196197 // In the next link, current region of object is ignored.
197198 g_object+=g_objpos;
--- a/mips/megalopa/help.txt
+++ b/mips/megalopa/help.txt
@@ -246,7 +246,11 @@ FSEEK x
246246 ABS(x)
247247 xの絶対値を返す。
248248 ARGS(x)
249- サブルーチン中で、GOSUBに渡されたx番目の引数を整数値として取り出す。
249+ サブルーチン中で、GOSUBもしくはメソッドに渡されたx番目の引数を整数値として取
250+ り出す。但し、
251+ ARGS(0)は、引数の数を返す。
252+ ARGS(-1)は、一つ前に使われた引数を格納する配列へのポインターを返す。
253+ ARGS(-2)は、クラスで用いられた場合、オブジェクトへのポインターを返す。
250254 ASC(x$)
251255 文字列の最初の一文字の、アスキーコードを返す。
252256 CREAD()
@@ -324,7 +328,8 @@ VAL(x$)
324328 ACOS#(x#)
325329 x# の逆余弦を実数値で返す。
326330 ARGS#(x)
327- サブルーチン中で、GOSUBに渡されたx番目の引数を実数値として取り出す。
331+ サブルーチン中で、GOSUBもしくはメソッドに渡されたx番目の引数を実数値として取
332+ り出す。
328333 ASIN#(x#)
329334 x# の逆正弦を実数値で返す。
330335 ATAN#(x#)
@@ -381,7 +386,8 @@ A$(x [,y])など
381386 xの値が負のとき、文字列の右側x文字を返す。
382387 yが指定された場合、y文字分の文字列を返す。
383388 ARGS$(x)
384- サブルーチン中で、GOSUBに渡されたx番目の引数を文字列として取り出す。
389+ サブルーチン中で、GOSUBもしくはメソッドに渡されたx番目の引数を文字列として取
390+ り出す。
385391 CHR$(x)
386392 xをアスキーコードとする文字を返す。
387393 DEC$(x)
--- a/mips/megalopa/sharedfiles.js
+++ b/mips/megalopa/sharedfiles.js
@@ -10,6 +10,7 @@
1010 */
1111
1212 var filearray=[
13+ 'args.c',
1314 'class.c',
1415 'cmpdata.c',
1516 'compiler.c',
--- /dev/null
+++ b/mips/zoea/args.c
@@ -0,0 +1,106 @@
1+/*
2+ This file is provided under the LGPL license ver 2.1.
3+ Written by Katsumi.
4+ http://hp.vector.co.jp/authors/VA016157/
5+ kmorimatsu@users.sourceforge.jp
6+*/
7+
8+/*
9+ This file is shared by Megalopa and Zoea
10+*/
11+
12+#include "compiler.h"
13+
14+const unsigned int g_initial_s5_stack[3]={
15+ 0, // -8($s5): no object
16+ (unsigned int) &g_initial_s5_stack[2], // -4($s5): previous $s5 (recursive)
17+ 0 // 0($s5): no parameter
18+};
19+
20+static int g_args_stack;
21+/*
22+ See ARGS_SP_XXXX and ARGS_S5_XXXX in compiler.h
23+ At least 4 stacks are needed even without argument
24+ 4($sp) = -12($s5): $sp
25+ 8($sp) = -8($s5): $v0 - pointer to object or previous -8($s5)
26+ 12($sp) = -4($s5): previous $s5
27+ 16($sp) = 0($s5): number of arguments
28+ 20($sp) = 4($s5): first argument
29+ $v0 must be the pointer to an object before comming to this code.
30+ After this code, -12($s5) must be set to $sp: 0xAEBDFFF4 sw sp,-12(s5)
31+*/
32+char* prepare_args_stack(char start_char){
33+ // start_char is either ',' or '('
34+ // When ',' mode, there must be a ',' if argument(s) exist(s).
35+ // When '(' mode, there shouldn't be a '(', because this character has passed.
36+ char* err;
37+ int opos,stack;
38+ stack=0;
39+ opos=g_objpos;
40+ check_obj_space(2);
41+ g_object[g_objpos++]=0x27BD0000; // addiu sp,sp,-xx
42+ // 8(sp) is for $v0, which is pointer to an object
43+ g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp)
44+ next_position();
45+ do {
46+ if (!stack) {
47+ // First parameter if exists
48+ stack=16;
49+ if (start_char==','){
50+ if (g_source[g_srcpos]!=',') break;
51+ } else if (start_char=='('){
52+ next_position();
53+ if (g_source[g_srcpos]==')') break;
54+ g_srcpos--;
55+ } else {
56+ return ERR_UNKNOWN;
57+ }
58+ }
59+ g_srcpos++;
60+ stack+=4;
61+ err=get_stringFloatOrValue();
62+ if (err) return err;
63+ check_obj_space(1);
64+ g_object[g_objpos++]=0xAFA20000|stack; // sw v0,xx(sp)
65+ next_position();
66+ } while (g_source[g_srcpos]==',');
67+ // 12(sp) is for $s5, 16(sp) is for # of parameters
68+ check_obj_space(5);
69+ g_object[g_objpos++]=0xAFB5000C; // sw s5,12(sp)
70+ g_object[g_objpos++]=0x34020000|(stack/4-4); // ori v0,zero,xx
71+ g_object[g_objpos++]=0xAFA20010; // sw v0,16(sp)
72+ g_object[g_objpos++]=0x27B50010; // addiu s5,sp,16
73+ g_object[opos]|=((0-stack)&0xFFFF); // addiu sp,sp,-xx (See above)
74+ // All done. Register # of stacks to global var.
75+ g_args_stack=stack;
76+ return 0;
77+}
78+
79+char* remove_args_stack(void){
80+ // Remove stack
81+ check_obj_space(2);
82+ g_object[g_objpos++]=0x8FB5000C; // lw s5,12(sp)
83+ g_object[g_objpos++]=0x27BD0000|g_args_stack; // addiu sp,sp,xx
84+ return 0;
85+}
86+
87+char* args_function_main(void){
88+ char* err;
89+ int i;
90+ err=get_value();
91+ if (err) return err;
92+ i=g_object[g_objpos-1];
93+ if ((i>>16)==0x3402) {
94+ // Previous object is "ori v0,zero,xxxx".
95+ i&=0xffff;
96+ i=i<<2;
97+ g_object[g_objpos-1]=0x8EA20000|i; // lw v0,xx(s5)
98+ } else {
99+ check_obj_space(3);
100+ g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2
101+ g_object[g_objpos++]=0x02A21021; // addu v0,s5,v0
102+ g_object[g_objpos++]=0x8C420000; // lw v0,0(v0)
103+ }
104+ return 0;
105+}
106+
--- a/mips/zoea/basic.mcp
+++ b/mips/zoea/basic.mcp
@@ -67,6 +67,7 @@ file_039=.
6767 file_040=.
6868 file_041=.
6969 file_042=.
70+file_043=.
7071 [GENERATED_FILES]
7172 file_000=no
7273 file_001=no
@@ -111,6 +112,7 @@ file_039=no
111112 file_040=no
112113 file_041=no
113114 file_042=no
115+file_043=no
114116 [OTHER_FILES]
115117 file_000=no
116118 file_001=no
@@ -150,11 +152,12 @@ file_034=no
150152 file_035=no
151153 file_036=no
152154 file_037=no
153-file_038=yes
155+file_038=no
154156 file_039=yes
155157 file_040=yes
156158 file_041=yes
157159 file_042=yes
160+file_043=yes
158161 [FILE_INFO]
159162 file_000=compiler.c
160163 file_001=editor.c
@@ -180,25 +183,26 @@ file_020=cmpdata.c
180183 file_021=varname.c
181184 file_022=envspecific.c
182185 file_023=class.c
183-file_024=api.h
184-file_025=compiler.h
185-file_026=editor.h
186-file_027=keyinput.h
187-file_028=main.h
188-file_029=ps2keyboard.h
189-file_030=SDFSIO.h
190-file_031=videoout.h
191-file_032=debug.h
192-file_033=envspecific.h
193-file_034=lib_videoout_machikania.X.a
194-file_035=libsdfsio.a
195-file_036=ps2keyboard.X.a
196-file_037=App_32MX170F256B.ld
197-file_038=help.txt
198-file_039=MACHIKAN.INI
199-file_040=reservednames.js
200-file_041=class.txt
201-file_042=sharedfiles.js
186+file_024=args.c
187+file_025=api.h
188+file_026=compiler.h
189+file_027=editor.h
190+file_028=keyinput.h
191+file_029=main.h
192+file_030=ps2keyboard.h
193+file_031=SDFSIO.h
194+file_032=videoout.h
195+file_033=debug.h
196+file_034=envspecific.h
197+file_035=lib_videoout_machikania.X.a
198+file_036=libsdfsio.a
199+file_037=ps2keyboard.X.a
200+file_038=App_32MX170F256B.ld
201+file_039=help.txt
202+file_040=MACHIKAN.INI
203+file_041=reservednames.js
204+file_042=class.txt
205+file_043=sharedfiles.js
202206 [SUITE_INFO]
203207 suite_guid={62D235D8-2DB2-49CD-AF24-5489A6015337}
204208 suite_state=
--- a/mips/zoea/class.c
+++ b/mips/zoea/class.c
@@ -1,822 +1,920 @@
1-/*
2- This file is provided under the LGPL license ver 2.1.
3- Written by K.Tanaka & Katsumi
4- http://www.ze.em-net.ne.jp/~kenken/index.html
5- http://hp.vector.co.jp/authors/VA016157/
6-*/
7-
8-/*
9- This file is shared by Megalopa and Zoea
10-*/
11-
12-#include "compiler.h"
13-
14-static int* g_class_structure;
15-
16-/*
17- CMPDATA_CLASS structure
18- type: CMPDATA_CLASS (2)
19- len: 3
20- data16: n/a (0)
21- record[1]: class name as integer
22- record[2]: pointer to class structure
23-*/
24-
25-/*
26- CMPDATA_FIELD structure
27- type: CMPDATA_FIELD (3)
28- len: 2 or 3 (2: field; 3: method)
29- data16: field or method
30- 0: public field
31- 1: private field
32- 2: public method
33- 3: reserved
34- record[1]: field/method name as integer
35- record[2]: pointer to method
36-*/
37-
38-/*
39- CMPDATA_STATIC structure
40- type: CMPDATA_STATIC (4)
41- len: 3
42- data16: variable number; add ALLOC_LNV_BLOCK when using
43- record[1]: class name as integer
44- record[2]: variable name as integer
45-*/
46-
47-
48-#define PUBLIC_FIELD 0
49-#define PRIVATE_FIELD 1
50-#define PUBLIC_METHOD 2
51-
52-/*
53- Local prototyping
54-*/
55-char* obj_method(int method);
56-
57-char* begin_compiling_class(int class){
58- // Initialize parameters
59- g_compiling_class=class;
60- g_class_structure=0;
61- // Register the class to cmpdata without class structure
62- return update_class_info(class);
63-}
64-
65-char* end_compiling_class(int class){
66- char* err;
67- g_compiling_class=0;
68- // Construct class structure
69- err=construct_class_structure(class);
70- if (err) return err;
71- // Uppdate class information.
72- err=update_class_info(class);
73- if (err) return err;
74- // Delete some cmpdata.
75- delete_cmpdata_for_class();
76- return 0;
77-}
78-
79-
80-char* update_class_info(int class){
81- int* record;
82- int data[2];
83- // Update record if exist.
84- cmpdata_reset();
85- while(record=cmpdata_find(CMPDATA_CLASS)){
86- if (record[1]==class) {
87- record[2]=(int)g_class_structure;
88- return 0;
89- }
90- }
91- // No record of this class yet. Insert a record.
92- data[0]=class;
93- data[1]=(int)g_class_structure;
94- return cmpdata_insert(CMPDATA_CLASS,0,&data[0],2);
95-}
96-
97-/*
98- Class structure:
99- cstruct[0]: class name as integer
100- cstruct[1]: number of fields and methods:
101- bit 0-7: # of public fields
102- bit 8-15: # of private fields
103- bit 16-23: # of public methods
104- bit 24-31: reserved
105- cstruct[x]: public field name
106- cstruct[x+1]: public field var number
107- cstruct[y]: private field name
108- cstruct[y+1]: private field var number
109- cstruct[z]: public method name
110- cstruct[z+1]: public method pointer
111-*/
112-
113-char* construct_class_structure(int class){
114- int* record;
115- int i;
116- int num=0;
117- // Register current address to global var
118- g_class_structure=&g_object[g_objpos];
119- // Construct a class structure in object area in following lines
120- // Class name
121- check_obj_space(2);
122- g_object[g_objpos++]=class; // Class name
123- g_objpos++; // Number of fields/methods
124- // Public fields
125- cmpdata_reset();
126- while(record=cmpdata_find(CMPDATA_FIELD)){
127- if ((record[0]&0xffff)==PUBLIC_FIELD) {
128- num+=1<<0;
129- check_obj_space(2);
130- g_object[g_objpos++]=record[1]; // Field name
131- g_objpos++; // Var number (see below)
132- }
133- }
134- // Private fields
135- cmpdata_reset();
136- while(record=cmpdata_find(CMPDATA_FIELD)){
137- if ((record[0]&0xffff)==PRIVATE_FIELD) {
138- num+=1<<8;
139- check_obj_space(2);
140- g_object[g_objpos++]=record[1]; // Field name
141- g_objpos++; // Var number (see below)
142- }
143- }
144- // Public methods
145- cmpdata_reset();
146- while(record=cmpdata_find(CMPDATA_FIELD)){
147- if ((record[0]&0xffff)==PUBLIC_METHOD) {
148- num+=1<<16;
149- check_obj_space(2);
150- g_object[g_objpos++]=record[1]; // Method name
151- g_object[g_objpos++]=record[2]; // pointer
152- }
153- }
154- // Update number info
155- g_class_structure[1]=num;
156- // Update var numbers of fields
157- num=((num>>8)&0xff)+(num&0xff);
158- for(i=1;i<=num;i++){
159- if ((
160- g_class_structure[i*2+1]=search_var_name(0x7FFFFFFF & g_class_structure[i*2])+ALLOC_LNV_BLOCK
161- )<ALLOC_LNV_BLOCK) return ERR_UNKNOWN;
162- }
163- return 0;
164-}
165-
166-void delete_cmpdata_for_class(){
167- int* record;
168- // Delete field/method data
169- cmpdata_reset();
170- while(record=cmpdata_find(CMPDATA_FIELD)){
171- cmpdata_delete(record);
172- cmpdata_reset();
173- }
174- // Delete longvar data
175- cmpdata_reset();
176- while(record=cmpdata_find(CMPDATA_USEVAR)){
177- cmpdata_delete(record);
178- cmpdata_reset();
179- }
180-}
181-
182-void* search_method(int* classdata,int method){
183- int pos,i;
184- int nums=classdata[1];
185-
186- classdata+=2; // exclude first 2 words
187- classdata+=2*(nums&0xff); // exclude public field
188- classdata+=2*((nums>>8)&0xff); // exclude private field
189- nums=(nums>>16)&0xff; // number of methods
190- for(i=0;i<nums;i++){
191- if (classdata[0]==method) return (void*)classdata[1];
192- classdata+=2;
193- }
194- return 0; // not found
195-}
196-
197-int object_size(int* classdata){
198- int nums=classdata[1];
199- int size=nums&0xff; // public field
200- size+=(nums>>8)&0xff; // private
201- return size;
202-}
203-
204-char* new_function(){
205- char* err;
206- int class,size;
207- int i,stack, opos;
208- int* data;
209- int* classdata;
210- void* init_method;
211- // Resolve class name
212- err=get_label();
213- if (err) return err;
214- if (!g_label) return ERR_SYNTAX;
215- class=g_label;
216- next_position();
217- // Get class data from cmpdata
218- // Note that the address of class structure can be resolved
219- // by using cmpdata when compiling NEW function but not running.
220- // Therefore, class table is not requred when running.
221- cmpdata_reset();
222- while(data=cmpdata_find(CMPDATA_CLASS)){
223- if (data[1]==class) break;
224- }
225- if (!data) return ERR_NO_CLASS;
226- classdata=(int*)data[2];
227- size=object_size(classdata);
228- // Create object
229- call_quicklib_code(lib_calloc_memory,ASM_ORI_A0_ZERO_|(size+1));
230- // First word of object is pointer to classdata
231- check_obj_space(3);
232- g_object[g_objpos++]=0x3C080000|(((unsigned int)classdata)>>16); // lui t0,xxxx
233- g_object[g_objpos++]=0x35080000|(((unsigned int)classdata)&0x0000FFFF); // ori t0,t0,xxxx
234- g_object[g_objpos++]=0xAC480000; // sw t0,0(v0)
235- // Check if INIT method exists
236- init_method=search_method(classdata,LABEL_INIT);
237- if (!init_method) {
238- // All done
239- // Note that $v0 is address of object here.
240- // There should not be parameter(s).
241- if (g_source[g_srcpos]==',') return ERR_NO_INIT;
242- return 0;
243- }
244- // INIT method exists. Note that $v0 is address of object here.
245- if (g_source[g_srcpos]==',') g_srcpos++;
246- else if (g_source[g_srcpos]!=')') return ERR_SYNTAX;
247- check_obj_space(2);
248- g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
249- g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp)
250- err=obj_method(LABEL_INIT);
251- if (err) return err;
252- g_srcpos--; // Leave ')' character for detecting end of "new" function
253- check_obj_space(2);
254- g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp)
255- g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4
256- // All done
257- // Note that $v0 is address of object here.
258- return 0;
259-}
260-
261-char* field_statement(){
262- char* err;
263- int i;
264- int data[1];
265- int is_private=0;
266- // This statement is valid only in class file.
267- if (!g_compiling_class) return ERR_INVALID_NON_CLASS;
268- // Check which private or public
269- next_position();
270- if (nextCodeIs("PRIVATE ")) {
271- is_private=1;
272- } else if (nextCodeIs("PUBLIC ")) {
273- is_private=0;
274- }
275- do {
276- next_position();
277- i=check_var_name();
278- if (i<65536) return ERR_SYNTAX;
279- // Register varname
280- err=register_var_name(i);
281- if (err) return err;
282- if (g_source[g_srcpos]=='#') {
283- g_srcpos++;
284- } else if (g_source[g_srcpos]=='$') {
285- // String field. Raise 31st bit.
286- g_srcpos++;
287- i|=0x80000000;
288- } else if (g_source[g_srcpos]=='(' && g_source[g_srcpos+1]==')' && is_private) {
289- // Dimension field (private only). Raise 31st bit.
290- g_srcpos++;
291- g_srcpos++;
292- i|=0x80000000;
293- }
294- // Register field
295- data[0]=i;
296- if (is_private) {
297- err=cmpdata_insert(CMPDATA_FIELD,PRIVATE_FIELD,(int*)&data[0],1);
298- } else {
299- err=cmpdata_insert(CMPDATA_FIELD,PUBLIC_FIELD,(int*)&data[0],1);
300- }
301- next_position();
302- if (g_source[g_srcpos]==',') {
303- g_srcpos++;
304- } else {
305- break;
306- }
307- } while(1);
308- return 0;
309-}
310-
311-/*
312- char* obj_method(int method);
313- Implementation of access to method of object.
314-*/
315-char* obj_method(int method){
316- // $v0 contains the address of object.
317- char* err;
318- int stack,opos;
319- // Parameters preparation (to $s5) here.
320- next_position();
321- opos=g_objpos;
322-
323- // Begin parameter(s) construction routine
324- // Note that this comment must be copied
325- // when inserting simiar routine to source
326-
327- stack=12;
328- g_object[g_objpos++]=0x27BD0000; // addiu sp,sp,-xx
329- // 4(sp) is for $v0 (pointer to object)
330- g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp)
331- if (g_source[g_srcpos]!=')') {
332- g_srcpos--;
333- do {
334- g_srcpos++;
335- stack+=4;
336- err=get_stringFloatOrValue();
337- if (err) return err;
338- check_obj_space(1);
339- g_object[g_objpos++]=0xAFA20000|stack; // sw v0,xx(sp)
340- next_position();
341- } while(g_source[g_srcpos]==',');
342- }
343- if (g_source[g_srcpos]!=')') return ERR_SYNTAX;
344- g_srcpos++;
345- // 8(sp) is for $s5, 12(sp) is for # of arguments
346- check_obj_space(4);
347- g_object[g_objpos++]=0xAFB50008; // sw s5,8(sp)
348- g_object[g_objpos++]=0x34020000|(stack/4-3); // ori v0,zero,xx
349- g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp)
350- g_object[g_objpos++]=0x27B50008; // addiu s5,sp,8
351- g_object[opos]|=((0-stack)&0xFFFF); // addiu sp,sp,-xx (See above)
352-
353- // End parameter(s) construction routine
354- // Note that this comment must be copied
355- // when inserting simiar routine to source
356-
357- // Determine address of method and store fields to local variables.
358- check_obj_space(3);
359- g_object[g_objpos++]=0x8FA20004; // lw v0,4(sp)
360- g_object[g_objpos++]=0x3C050000|((method>>16)&0x0000FFFF); // lui a1,xxxx
361- g_object[g_objpos++]=0x34A50000|(method&0x0000FFFF); // ori a1,a1,xxxx
362- call_quicklib_code(lib_pre_method,ASM_ADDU_A0_V0_ZERO);
363- // Call method address here. Same routine for GOSUB statement with integer value is used.
364- check_obj_space(6);
365- g_object[g_objpos++]=0x04130003; // bgezall zero,label1
366- g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
367- g_object[g_objpos++]=0x10000003; // beq zero,zero,label2
368- g_object[g_objpos++]=0x00000000; // nop
369- // label1:
370- g_object[g_objpos++]=0x00400008; // jr v0
371- g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) // label2:
372- // Restore fields from local variables.
373- check_obj_space(3);
374- g_object[g_objpos++]=0x8FA40004; // lw a0,4(sp)
375- g_object[g_objpos++]=0x3C050000|((method>>16)&0x0000FFFF); // lui a1,xxxx
376- g_object[g_objpos++]=0x34A50000|(method&0x0000FFFF); // ori a1,a1,xxxx
377- call_quicklib_code(lib_post_method,ASM_ADDU_A2_V0_ZERO);
378- // Remove stack
379- check_obj_space(2);
380- g_object[g_objpos++]=0x8FB50008; // lw s5,8(sp)
381- g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx
382- return 0;
383-}
384-
385-/*
386- char* integer_obj_field();
387- char* string_obj_field();
388- char* float_obj_field();
389- Implementation of access to field of object.
390- This feature is recursive. When an object is applied to the field of another object,
391- following expression is possible (for example):
392- obj1.field1.field2
393-
394-*/
395-
396-#define OBJ_FIELD_INTEGER 0
397-#define OBJ_FIELD_STRING '$'
398-#define OBJ_FIELD_FLOAT '#'
399-
400-char* _obj_field(char mode){
401- // $v0 contains the address of object.
402- int i;
403- char* err;
404- do {
405- i=check_var_name(); // TODO: consider accepting reserbed var names for field name
406- if (i<65536) return ERR_SYNTAX;
407- if (g_source[g_srcpos]=='(' && mode==OBJ_FIELD_INTEGER) {
408- // This is a method
409- g_srcpos++;
410- return obj_method(i);
411- } else if (g_source[g_srcpos+1]=='(') {
412- if (g_source[g_srcpos]==mode) {
413- // This is a string/float method
414- g_srcpos++;
415- g_srcpos++;
416- return obj_method(i);
417- }
418- } else if (g_source[g_srcpos]==mode && mode==OBJ_FIELD_STRING) {
419- // This is a string field. Raise 31st bit.
420- i|=0x80000000;
421- }
422- check_obj_space(2);
423- g_object[g_objpos++]=0x3C050000|((i>>16)&0x0000FFFF); // lui a1,xxxx
424- g_object[g_objpos++]=0x34A50000|(i&0x0000FFFF); // ori a1,a1,xxxx
425- // First and second arguments are address of object and field name, respectively.
426- call_quicklib_code(lib_obj_field,ASM_ADDU_A0_V0_ZERO);
427- // Check if "." follows
428- if (g_source[g_srcpos]=='.') {
429- // "." found. $v0 is adress of an object. See the field.
430- g_srcpos++;
431- continue;
432- }
433- } while(0);
434- // All done. Check variable type
435- if (mode==OBJ_FIELD_INTEGER) return 0;
436- else if (g_source[g_srcpos]==mode) {
437- g_srcpos++;
438- return 0;
439- } else return ERR_SYNTAX;
440-}
441-
442-char* integer_obj_field(){
443- return _obj_field(OBJ_FIELD_INTEGER);
444-}
445-
446-char* string_obj_field(){
447- return _obj_field(OBJ_FIELD_STRING);
448-}
449-
450-char* float_obj_field(){
451- return _obj_field(OBJ_FIELD_FLOAT);
452-}
453-
454-int lib_obj_field(int* object, int fieldname){
455- int* class;
456- int i,numfield;
457- // Check if this is an object (if within the RAM).
458- if (!withinRAM(object)) err_not_obj();
459- class=(int*)object[0];
460- if (!withinRAM(class)) err_not_obj();
461- // Obtain # of public field
462- numfield=class[1]&0xff;
463- for(i=0;i<numfield;i++){
464- if (class[2+i*2]==fieldname) break;
465- }
466- if (i==numfield) err_not_field(fieldname,class[0]);
467- // Got address of field. Return value as $v0 and address as $v1.
468- g_temp=(int)(&object[1+i]);
469- asm volatile("la $v1,%0"::"i"(&g_temp));
470- asm volatile("lw $v1,0($v1)");
471- return object[1+i];
472-}
473-
474-/*
475- Library for letting string field
476-*/
477-
478-void lib_let_str_field(char* prev_str, char* new_str){
479- int var_num=get_permanent_var_num();
480- free_perm_str(prev_str);
481- lib_let_str(new_str,var_num);
482- return;
483-}
484-
485-/*
486- Library for calling method statement
487-*/
488-
489-// Return code used for calling null method
490-static const unsigned int g_return_code[]={
491- 0x8FA30004, // lw v1,4(sp)
492- 0x00600008, // jr v1
493- 0x27BD0004, // addiu sp,sp,4
494-};
495-
496-int lib_pre_method(int* object, int methodname){
497- int i,num,nums;
498- int* class;
499- // Check if this is an object (if within the RAM).
500- if (!withinRAM(object)) err_not_obj();
501- class=(int*)object[0];
502- if (!withinRAM(class)) err_not_obj();
503- // Save object field values in local variables in class
504- nums=class[1];
505- num=nums&0xff;
506- for(i=0;i<num;i++){
507- // Public fields
508- class+=2;
509- g_var_mem[class[1]]=object[i+1];
510- // When string, move from permanent block
511- if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]);
512- }
513- num+=(nums>>8)&0xff;
514- for(i=i;i<num;i++){
515- // Private fields
516- class+=2;
517- g_var_mem[class[1]]=object[i+1];
518- // When string/dimension, move from permanent block
519- if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]);
520- }
521- // Seek method
522- num+=(nums>>16)&0xff;
523- for(i=i;i<num;i++){
524- class+=2;
525- if (class[0]==methodname) break;
526- }
527- if (i==num) {
528- // Method not found
529- if (methodname==LABEL_INIT) {
530- // INIT method not found
531- // Call null function
532- return (int)(&g_return_code[0]);
533- } else {
534- class=(int*)object[0];
535- err_not_field(methodname,class[0]);
536- }
537- }
538- // Method found. return it.
539- return class[1];
540-}
541-
542-int lib_post_method(int* object, int methodname, int v0){
543- // Note that existence of the method was checked in above function before reaching this function.
544- int i,num,nums;
545- int* class;
546- // Restore local variables to object field values
547- class=(int*)object[0];
548- nums=class[1];
549- num=nums&0xff;
550- for(i=0;i<num;i++){
551- // Public fields
552- class+=2;
553- object[i+1]=g_var_mem[class[1]];
554- // When string, move to permanent block
555- if (0x80000000&class[0]) {
556- if (g_var_size[class[1]]) move_to_perm_block(class[1]);
557- }
558- }
559- num+=(nums>>8)&0xff;
560- for(i=i;i<num;i++){
561- // Private fields
562- class+=2;
563- object[i+1]=g_var_mem[class[1]];
564- // When string/dimension, move to permanent block
565- if (0x80000000&class[0]) {
566- if (g_var_size[class[1]]) move_to_perm_block(class[1]);
567- }
568- }
569- // all done
570- return v0;
571-}
572-
573-/*
574- Method statement
575-*/
576-
577-char* method_statement(){
578- char* err;
579- int data[2];
580- int opos=g_objpos;
581- // This statement is valid only in class file.
582- if (!g_compiling_class) return ERR_INVALID_NON_CLASS;
583- // Insert label for setting $s6
584- err=label_statement();
585- if (err) return err;
586- // Register cmpdata
587- data[0]=g_label;
588- data[1]=(int)(&g_object[opos]);
589- return cmpdata_insert(CMPDATA_FIELD,PUBLIC_METHOD,(int*)&data[0],2);
590-}
591-
592-/*
593- Delete statement
594-*/
595-
596-char* delete_statement(){
597- char* err;
598- next_position();
599- g_srcpos--;
600- do{
601- g_srcpos++;
602- err=get_value();
603- if (err) return err;
604- call_quicklib_code(lib_delete,ASM_ADDU_A0_V0_ZERO);
605- next_position();
606- } while (g_source[g_srcpos]==',');
607- return 0;
608-}
609-
610-/*
611- Call statement
612-*/
613-
614-char* call_statement(){
615- // Just get an integer value. That is it.
616- return get_value();
617-}
618-
619-/*
620- Static statement
621-*/
622-
623-char* static_statement(){
624- char* err;
625- int data[2];
626- int i;
627- int is_private=0;
628- // This statement is valid only in class file.
629- if (!g_compiling_class) return ERR_INVALID_NON_CLASS;
630- // Check which private or public
631- next_position();
632- if (nextCodeIs("PRIVATE ")) {
633- is_private=1;
634- } else if (nextCodeIs("PUBLIC ")) {
635- is_private=0;
636- }
637- do {
638- next_position();
639- i=check_var_name();
640- if (i<65536) return ERR_SYNTAX;
641- // Register varname
642- err=register_var_name(i);
643- if (err) return err;
644- if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') {
645- g_srcpos++;
646- }
647- // Register public static field
648- if (!is_private) {
649- data[0]=g_compiling_class; // class name as integer
650- data[1]=i; // static var name as integer
651- i=search_var_name(i); // var number of this static field
652- if (i<0) return ERR_UNKNOWN;
653- err=cmpdata_insert(CMPDATA_STATIC,i,(int*)&data[0],2);
654- if (err) return err;
655- }
656- next_position();
657- if (g_source[g_srcpos]==',') {
658- g_srcpos++;
659- } else {
660- break;
661- }
662- } while(1);
663- return 0;
664-
665-}
666-
667-/*
668- Static method
669- Type is either 0, '$', or '#',
670- for integer, string, or float
671-*/
672-
673-char* static_method(char type){
674- char* err;
675- int* data;
676- int i,opos,method,stack;
677- next_position();
678- // Check class name
679- i=check_var_name();
680- if (i<65536) return ERR_SYNTAX;
681- // Check if the class exists
682- cmpdata_reset();
683- while(data=cmpdata_find(CMPDATA_CLASS)){
684- if (data[1]==i) {
685- // The class was already defined.
686- i=0;
687- break;
688- }
689- }
690- // Check '::'
691- if (g_source[g_srcpos]!=':') return ERR_SYNTAX;
692- g_srcpos++;
693- if (g_source[g_srcpos]!=':') return ERR_SYNTAX;
694- g_srcpos++;
695- if (i) return ERR_NO_CLASS;
696- data=(int*)data[2];
697- // Check method
698- i=check_var_name();
699- if (i<65536) return ERR_SYNTAX;
700- method=(int)search_method(data,i);
701- if (!method) return ERR_NOT_FIELD;
702- // Check type and '('
703- if (type) {// Either 0, '$', or '#'
704- if (g_source[g_srcpos]!=type) return ERR_SYNTAX;
705- g_srcpos++;
706-
707- }
708- if (g_source[g_srcpos]!='(') return ERR_SYNTAX;
709- g_srcpos++;
710-
711- // Begin parameter(s) construction routine
712- // Note that this comment must be copied
713- // when inserting simiar routine to source
714-
715- stack=8;
716- opos=g_objpos;
717- g_object[g_objpos++]=0x27BD0000; // addiu sp,sp,-xx
718- while(g_source[g_srcpos]==',') {
719- g_srcpos++;
720- stack+=4;
721- err=get_stringFloatOrValue();
722- if (err) return err;
723- check_obj_space(1);
724- g_object[g_objpos++]=0xAFA20000|stack; // sw v0,xx(sp)
725- next_position();
726- }
727- // 4(sp) is for $s5, 8(sp) is for # of parameters
728- check_obj_space(5);
729- g_object[g_objpos++]=0xAFB50004; // sw s5,4(sp)
730- g_object[g_objpos++]=0x34020000|(stack/4-2); // ori v0,zero,xx
731- g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp)
732- g_object[g_objpos++]=0x27B50004; // addiu s5,sp,4
733- g_object[opos]|=((0-stack)&0xFFFF); // addiu sp,sp,-xx (See above)
734-
735- // End parameter(s) construction routine
736- // Note that this comment must be copied
737- // when inserting simiar routine to source
738-
739- // Calling subroutine, which is static method of class
740- check_obj_space(6);
741- g_object[g_objpos++]=0x04130003; // bgezall zero,label1
742- g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
743- g_object[g_objpos++]=0x10000003; // beq zero,zero,label2
744- g_object[g_objpos++]=0x00000000; // nop
745- // label1:
746- g_object[g_objpos++]=0x08000000|((method&0x0FFFFFFF)>>2); // j xxxx
747- g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp)
748- // label2:
749- // Remove stack
750- check_obj_space(2);
751- g_object[g_objpos++]=0x8FB50004; // lw s5,4(sp)
752- g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx
753-
754- return 0;
755-}
756-
757-/*
758- Let object.field statement
759-*/
760-
761-char* let_object_field(){
762- char* err;
763- char b3;
764- int spos,opos;
765- // $v0 contains the pointer to object
766- spos=g_srcpos;
767- opos=g_objpos;
768- // Try string field, first
769- err=string_obj_field();
770- if (err) {
771- // Integer or float field
772- g_srcpos=spos;
773- g_objpos=opos;
774- err=integer_obj_field();
775- if (err) return err;
776- b3=g_source[g_srcpos];
777- if (b3=='#') g_srcpos++;
778- } else {
779- // String field
780- b3='$';
781- }
782- if (g_source[g_srcpos-1]==')') {
783- // This is a CALL statement
784- return 0;
785- }
786- // $v1 is address to store value. Save it in stack.
787- check_obj_space(1);
788- g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
789- g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp)
790- if (b3=='$') {
791- // String field
792- // Get value
793- next_position();
794- if (g_source[g_srcpos]!='=') return ERR_SYNTAX;
795- g_srcpos++;
796- err=get_string();
797- } else if (b3=='#') {
798- // Float field
799- // Get value
800- next_position();
801- if (g_source[g_srcpos]!='=') return ERR_SYNTAX;
802- g_srcpos++;
803- err=get_float();
804- } else {
805- // Integer field
806- // Get value
807- next_position();
808- if (g_source[g_srcpos]!='=') return ERR_SYNTAX;
809- g_srcpos++;
810- err=get_value();
811- }
812- if (err) return err;
813- // Store in field of object
814- check_obj_space(4);
815- g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp)
816- g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4
817- g_object[g_objpos++]=0x8C640000; // lw a0,0(v1)
818- g_object[g_objpos++]=0xAC620000; // sw v0,0(v1)
819- // Handle permanent block for string field
820- if (b3=='$') call_quicklib_code(lib_let_str_field,ASM_ADDU_A1_V0_ZERO);
821- return 0;
1+/*
2+ This file is provided under the LGPL license ver 2.1.
3+ Written by K.Tanaka & Katsumi
4+ http://www.ze.em-net.ne.jp/~kenken/index.html
5+ http://hp.vector.co.jp/authors/VA016157/
6+*/
7+
8+/*
9+ This file is shared by Megalopa and Zoea
10+*/
11+
12+#include "compiler.h"
13+
14+static int* g_class_structure;
15+
16+/*
17+ CMPDATA_CLASS structure
18+ type: CMPDATA_CLASS (2)
19+ len: 3
20+ data16: n/a (0)
21+ record[1]: class name as integer
22+ record[2]: pointer to class structure
23+*/
24+
25+/*
26+ CMPDATA_FIELD structure
27+ type: CMPDATA_FIELD (3)
28+ len: 2 or 3 (2: field; 3: method)
29+ data16: field or method
30+ CMPTYPE_PUBLIC_FIELD: 0
31+ CMPTYPE_PRIVATE_FIELD: 1
32+ CMPTYPE_PUBLIC_METHOD: 2
33+ record[1]: field/method name as integer
34+ record[2]: pointer to method
35+*/
36+
37+/*
38+ CMPDATA_STATIC structure
39+ type: CMPDATA_STATIC (4)
40+ len: 3
41+ data16: variable number; add ALLOC_LNV_BLOCK when using
42+ record[1]: class name as integer
43+ record[2]: variable name as integer
44+*/
45+
46+/*
47+ CMPDATA_UNSOLVED structure
48+ type: CMPDATA_UNSOLVED (5)
49+ len: 4
50+ data16: CMPTYPE_NEW_FUNCTION (0)
51+ record[1]: class name as integer
52+ record[2]: address of code for pointer to class structure
53+ record[3]: address of code for size definition
54+
55+ type: CMPDATA_UNSOLVED (5)
56+ len: 4
57+ data16: CMPTYPE_STATIC_METHOD (1)
58+ record[1]: class name as integer
59+ record[2]: method name as integer
60+ record[3]: address of code for pointer to method
61+
62+*/
63+
64+/*
65+ Local prototyping
66+*/
67+char* obj_method(int method);
68+
69+/*
70+ Return code used for calling null method
71+*/
72+static const unsigned int g_return_code[]={
73+ 0x8FA30004, // lw v1,4(sp)
74+ 0x00600008, // jr v1
75+ 0x27BD0004, // addiu sp,sp,4
76+};
77+
78+
79+
80+char* begin_compiling_class(int class){
81+ // Initialize parameters
82+ g_compiling_class=class;
83+ g_class_structure=0;
84+ // Register the class to cmpdata without class structure
85+ return update_class_info(class);
86+}
87+
88+char* end_compiling_class(int class){
89+ char* err;
90+ g_compiling_class=0;
91+ // Construct class structure
92+ err=construct_class_structure(class);
93+ if (err) return err;
94+ // Uppdate class information.
95+ err=update_class_info(class);
96+ if (err) return err;
97+ // Resolve CMPDATA_UNSOLVED.
98+ err=resolve_unresolved(class);
99+ if (err) return err;
100+ // Delete some cmpdata.
101+ delete_cmpdata_for_class(class);
102+ return 0;
103+}
104+
105+void* search_method(int* classdata,int method){
106+ int pos,i;
107+ int nums=classdata[1];
108+
109+ classdata+=2; // exclude first 2 words
110+ classdata+=2*(nums&0xff); // exclude public field
111+ classdata+=2*((nums>>8)&0xff); // exclude private field
112+ nums=(nums>>16)&0xff; // number of methods
113+ for(i=0;i<nums;i++){
114+ if (classdata[0]==method) return (void*)classdata[1];
115+ classdata+=2;
116+ }
117+ return 0; // not found
118+}
119+
120+char* resolve_unresolved(int class){
121+ int* classdata;
122+ int* record;
123+ int* code;
124+ int i;
125+ // Get class structure
126+ cmpdata_reset();
127+ while(record=cmpdata_find(CMPDATA_CLASS)){
128+ if (record[1]==class) break;
129+ }
130+ if (!record) return ERR_UNKNOWN;
131+ classdata=(int*)record[2];
132+ // Explore CMPDATA_UNSOLVED
133+ cmpdata_reset();
134+ while(record=cmpdata_find(CMPDATA_UNSOLVED)){
135+ // Note: don't use cmpdata_find() again in the loop.
136+ // If used, the solved CMPDATA_UNSOLVED must be removed before.
137+ if (record[1]!=class) continue;
138+ switch (record[0]&0xffff) {
139+ case CMPTYPE_NEW_FUNCTION:
140+ // Resolve address of code for pointer to class structure
141+ code=(int*)(record[2]);
142+ code[0]=(code[0]&0xFFFF0000) | (((unsigned int)classdata)>>16);
143+ code[1]=(code[1]&0xFFFF0000) | (((unsigned int)classdata) & 0x0000FFFF);
144+ // Resolve size of object
145+ code=(int*)(record[3]);
146+ code[0]=(code[0]&0xFFFF0000) | (object_size(classdata) & 0x0000FFFF);
147+ // All done
148+ break;
149+ case CMPTYPE_STATIC_METHOD:
150+ // Resolve address of code for pointer to method
151+ // Find method
152+ i=(int)search_method(classdata,record[2]);
153+ if (!i) return ERR_NOT_FIELD;
154+ code=(int*)(record[3]);
155+ code[0]=(code[0]&0xFC000000)|((i&0x0FFFFFFF)>>2);
156+ // All done
157+ break;
158+ default:
159+ return ERR_UNKNOWN;
160+ } }
161+ return 0;
162+}
163+
164+char* update_class_info(int class){
165+ int* record;
166+ int data[2];
167+ // Update record if exist.
168+ cmpdata_reset();
169+ while(record=cmpdata_find(CMPDATA_CLASS)){
170+ if (record[1]==class) {
171+ record[2]=(int)g_class_structure;
172+ return 0;
173+ }
174+ }
175+ // No record of this class yet. Insert a record.
176+ data[0]=class;
177+ data[1]=(int)g_class_structure;
178+ return cmpdata_insert(CMPDATA_CLASS,0,&data[0],2);
179+}
180+
181+/*
182+ Class structure:
183+ cstruct[0]: class name as integer
184+ cstruct[1]: number of fields and methods:
185+ bit 0-7: # of public fields
186+ bit 8-15: # of private fields
187+ bit 16-23: # of public methods
188+ bit 24-31: reserved
189+ cstruct[x]: public field name
190+ cstruct[x+1]: public field var number
191+ cstruct[y]: private field name
192+ cstruct[y+1]: private field var number
193+ cstruct[z]: public method name
194+ cstruct[z+1]: public method pointer
195+*/
196+
197+char* construct_class_structure(int class){
198+ int* record;
199+ int i;
200+ int num=0;
201+ // Register current address to global var
202+ g_class_structure=&g_object[g_objpos];
203+ // Construct a class structure in object area in following lines
204+ // Class name
205+ check_obj_space(2);
206+ g_object[g_objpos++]=class; // Class name
207+ g_objpos++; // Number of fields/methods
208+ // Public fields
209+ cmpdata_reset();
210+ while(record=cmpdata_find(CMPDATA_FIELD)){
211+ if ((record[0]&0xffff)==CMPTYPE_PUBLIC_FIELD) {
212+ num+=1<<0;
213+ check_obj_space(2);
214+ g_object[g_objpos++]=record[1]; // Field name
215+ g_objpos++; // Var number (see below)
216+ }
217+ }
218+ // Private fields
219+ cmpdata_reset();
220+ while(record=cmpdata_find(CMPDATA_FIELD)){
221+ if ((record[0]&0xffff)==CMPTYPE_PRIVATE_FIELD) {
222+ num+=1<<8;
223+ check_obj_space(2);
224+ g_object[g_objpos++]=record[1]; // Field name
225+ g_objpos++; // Var number (see below)
226+ }
227+ }
228+ // Public methods
229+ cmpdata_reset();
230+ while(record=cmpdata_find(CMPDATA_FIELD)){
231+ if ((record[0]&0xffff)==CMPTYPE_PUBLIC_METHOD) {
232+ num+=1<<16;
233+ check_obj_space(2);
234+ g_object[g_objpos++]=record[1]; // Method name
235+ g_object[g_objpos++]=record[2]; // pointer
236+ }
237+ }
238+ // Update number info
239+ g_class_structure[1]=num;
240+ // Update var numbers of fields
241+ num=((num>>8)&0xff)+(num&0xff);
242+ for(i=1;i<=num;i++){
243+ if ((
244+ g_class_structure[i*2+1]=search_var_name(0x7FFFFFFF & g_class_structure[i*2])+ALLOC_LNV_BLOCK
245+ )<ALLOC_LNV_BLOCK) return ERR_UNKNOWN;
246+ }
247+ return 0;
248+}
249+
250+void delete_cmpdata_for_class(int class){
251+ int* record;
252+ // Delete field/method data
253+ cmpdata_reset();
254+ while(record=cmpdata_find(CMPDATA_FIELD)){
255+ cmpdata_delete(record);
256+ cmpdata_reset();
257+ }
258+ // Delete longvar data
259+ cmpdata_reset();
260+ while(record=cmpdata_find(CMPDATA_USEVAR)){
261+ cmpdata_delete(record);
262+ cmpdata_reset();
263+ }
264+ // Delete solved class codes
265+ cmpdata_reset();
266+ while(record=cmpdata_find(CMPDATA_UNSOLVED)){
267+ if (record[1]!=class) continue;
268+ cmpdata_delete(record);
269+ cmpdata_reset();
270+ }
271+}
272+
273+int object_size(int* classdata){
274+ int nums=classdata[1];
275+ int size=nums&0xff; // public field
276+ size+=(nums>>8)&0xff; // private
277+ // Add 1 for pointer to class data.
278+ return size+1;
279+}
280+
281+char* new_function(){
282+ char* err;
283+ int class,size;
284+ int i,stack, opos;
285+ int* data;
286+ int* classdata;
287+ int record[3];
288+ void* init_method;
289+ // Resolve class name
290+ err=get_label();
291+ if (err) return err;
292+ if (!g_label) return ERR_SYNTAX;
293+ class=g_label;
294+ record[0]=class;
295+ next_position();
296+ // Get class data from cmpdata
297+ // Note that the address of class structure can be resolved
298+ // by using cmpdata when compiling NEW function but not running.
299+ // Therefore, class table is not requred when running.
300+ cmpdata_reset();
301+ while(data=cmpdata_find(CMPDATA_CLASS)){
302+ if (data[1]==class) break;
303+ }
304+ if (!data) return ERR_NO_CLASS;
305+ classdata=(int*)data[2];
306+ if (classdata) {
307+ size=object_size(classdata);
308+ } else {
309+ // Class structure is unsolved.
310+ size=0;
311+ }
312+ // Create object
313+ record[2]=(int)&g_object[g_objpos+3];
314+ call_quicklib_code(lib_calloc_memory,ASM_ORI_A0_ZERO_|size);
315+ // First word of object is pointer to classdata
316+ check_obj_space(3);
317+ record[1]=(int)&g_object[g_objpos];
318+ g_object[g_objpos++]=0x3C080000|(((unsigned int)classdata)>>16); // lui t0,xxxx
319+ g_object[g_objpos++]=0x35080000|(((unsigned int)classdata)&0x0000FFFF); // ori t0,t0,xxxx
320+ g_object[g_objpos++]=0xAC480000; // sw t0,0(v0)
321+ // Check if INIT method exists
322+ if (classdata) {
323+ init_method=search_method(classdata,LABEL_INIT);
324+ } else {
325+ // Class structure is unknown. Use null method.
326+ init_method=(int*)&g_return_code[0];
327+ // Register CMPDATA
328+ cmpdata_insert(CMPDATA_UNSOLVED,CMPTYPE_NEW_FUNCTION,(int*)&record[0],3);
329+ g_allow_shift_obj=0;
330+ }
331+ if (!init_method) {
332+ // All done
333+ // Note that $v0 is address of object here.
334+ // There should not be parameter(s).
335+ if (g_source[g_srcpos]==',') return ERR_NO_INIT;
336+ return 0;
337+ }
338+ // INIT method exists. Note that $v0 is address of object here.
339+ if (g_source[g_srcpos]==',') g_srcpos++;
340+ else if (g_source[g_srcpos]!=')') return ERR_SYNTAX;
341+ check_obj_space(2);
342+ g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
343+ g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp)
344+ err=obj_method(LABEL_INIT);
345+ if (err) return err;
346+ g_srcpos--; // Leave ')' character for detecting end of "new" function
347+ check_obj_space(2);
348+ g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp)
349+ g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4
350+ // All done
351+ // Note that $v0 is address of object here.
352+ return 0;
353+}
354+
355+char* field_statement(){
356+ char* err;
357+ int i;
358+ int data[1];
359+ int is_private=0;
360+ // This statement is valid only in class file.
361+ if (!g_compiling_class) return ERR_INVALID_NON_CLASS;
362+ // Check which private or public
363+ next_position();
364+ if (nextCodeIs("PRIVATE ")) {
365+ is_private=1;
366+ } else if (nextCodeIs("PUBLIC ")) {
367+ is_private=0;
368+ }
369+ do {
370+ next_position();
371+ i=check_var_name();
372+ if (i<65536) return ERR_SYNTAX;
373+ // Register varname
374+ err=register_var_name(i);
375+ if (err) return err;
376+ if (g_source[g_srcpos]=='#') {
377+ g_srcpos++;
378+ } else if (g_source[g_srcpos]=='$') {
379+ // String field. Raise 31st bit.
380+ g_srcpos++;
381+ i|=0x80000000;
382+ } else if (g_source[g_srcpos]=='(' && g_source[g_srcpos+1]==')' && is_private) {
383+ // Dimension field (private only). Raise 31st bit.
384+ g_srcpos++;
385+ g_srcpos++;
386+ i|=0x80000000;
387+ }
388+ // Register field
389+ data[0]=i;
390+ if (is_private) {
391+ err=cmpdata_insert(CMPDATA_FIELD,CMPTYPE_PRIVATE_FIELD,(int*)&data[0],1);
392+ } else {
393+ err=cmpdata_insert(CMPDATA_FIELD,CMPTYPE_PUBLIC_FIELD,(int*)&data[0],1);
394+ }
395+ next_position();
396+ if (g_source[g_srcpos]==',') {
397+ g_srcpos++;
398+ } else {
399+ break;
400+ }
401+ } while(1);
402+ return 0;
403+}
404+
405+/*
406+ char* obj_method(int method);
407+ Implementation of access to method of object.
408+*/
409+char* obj_method(int method){
410+ // $v0 contains the address of object.
411+ // Note that '(' has been passed.
412+ char* err;
413+ int stack,opos;
414+ // When method of an object is called from object,
415+ // current variables must be saved to object fields
416+ if (g_compiling_class) {
417+ check_obj_space(1);
418+ g_object[g_objpos++]=0x00402821; // addu a1,v0,zero
419+ call_quicklib_code(lib_save_vars_to_fields,ASM_LW_A0_XXXX_S5|ARGS_S5_V0_OBJ);
420+ }
421+ // Parameters preparation (to $s5) here.
422+ next_position();
423+ opos=g_objpos;
424+ // Begin parameter(s) construction routine
425+ err=prepare_args_stack('(');
426+ if (err) return err;
427+ if (g_source[g_srcpos]!=')') return ERR_SYNTAX;
428+ g_srcpos++;
429+ // Determine address of method and store fields to local variables.
430+ check_obj_space(3);
431+ g_object[g_objpos++]=0x8FA20000|ARGS_SP_V0_OBJ; // lw v0,8(sp)
432+ g_object[g_objpos++]=0x3C050000|((method>>16)&0x0000FFFF); // lui a1,xxxx
433+ g_object[g_objpos++]=0x34A50000|(method&0x0000FFFF); // ori a1,a1,xxxx
434+ call_quicklib_code(lib_pre_method,ASM_ADDU_A0_V0_ZERO);
435+ // Call method address here. Same routine for GOSUB statement with integer value is used.
436+ check_obj_space(6);
437+ g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
438+ g_object[g_objpos++]=0x04130003; // bgezall zero,label1
439+ g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5)
440+ g_object[g_objpos++]=0x10000003; // beq zero,zero,label2
441+ g_object[g_objpos++]=0x00000000; // nop
442+ // label1:
443+ g_object[g_objpos++]=0x00400008; // jr v0
444+ g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) // label2:
445+ // Restore fields from local variables.
446+ check_obj_space(3);
447+ g_object[g_objpos++]=0x8FA40008; // lw a0,8(sp)
448+ call_quicklib_code(lib_post_method,ASM_ADDU_A1_V0_ZERO);
449+ // Remove stack
450+ err=remove_args_stack();
451+ if (err) return err;
452+ // When method of an object is called from object,
453+ // current variables must be saved to object fields
454+ if (g_compiling_class) {
455+ check_obj_space(1);
456+ g_object[g_objpos++]=0x00402821; // addu a1,v0,zero
457+ call_quicklib_code(lib_load_vars_from_fields,ASM_LW_A0_XXXX_S5|ARGS_S5_V0_OBJ);
458+ }
459+ return 0;
460+}
461+
462+/*
463+ char* integer_obj_field();
464+ char* string_obj_field();
465+ char* float_obj_field();
466+ Implementation of access to field of object.
467+ This feature is recursive. When an object is applied to the field of another object,
468+ following expression is possible (for example):
469+ obj1.field1.field2
470+
471+*/
472+
473+#define OBJ_FIELD_INTEGER 0
474+#define OBJ_FIELD_STRING '$'
475+#define OBJ_FIELD_FLOAT '#'
476+
477+char* _obj_field(char mode){
478+ // $v0 contains the address of object.
479+ int i;
480+ char* err;
481+ do {
482+ i=check_var_name();
483+ if (i<65536) return ERR_SYNTAX;
484+ if (g_source[g_srcpos]=='(' && mode==OBJ_FIELD_INTEGER) {
485+ // This is a method
486+ g_srcpos++;
487+ return obj_method(i);
488+ } else if (g_source[g_srcpos+1]=='(') {
489+ if (g_source[g_srcpos]==mode) {
490+ // This is a string/float method
491+ g_srcpos++;
492+ g_srcpos++;
493+ return obj_method(i);
494+ }
495+ } else if (g_source[g_srcpos]==mode && mode==OBJ_FIELD_STRING) {
496+ // This is a string field. Raise 31st bit.
497+ i|=0x80000000;
498+ }
499+ check_obj_space(2);
500+ g_object[g_objpos++]=0x3C050000|((i>>16)&0x0000FFFF); // lui a1,xxxx
501+ g_object[g_objpos++]=0x34A50000|(i&0x0000FFFF); // ori a1,a1,xxxx
502+ // First and second arguments are address of object and field name, respectively.
503+ call_quicklib_code(lib_obj_field,ASM_ADDU_A0_V0_ZERO);
504+ // Check if "." follows
505+ if (g_source[g_srcpos]=='.') {
506+ // "." found. $v0 is adress of an object. See the field.
507+ g_srcpos++;
508+ continue;
509+ }
510+ } while(0);
511+ // All done. Check variable type
512+ if (mode==OBJ_FIELD_INTEGER) return 0;
513+ else if (g_source[g_srcpos]==mode) {
514+ g_srcpos++;
515+ return 0;
516+ } else return ERR_SYNTAX;
517+}
518+
519+char* integer_obj_field(){
520+ return _obj_field(OBJ_FIELD_INTEGER);
521+}
522+
523+char* string_obj_field(){
524+ return _obj_field(OBJ_FIELD_STRING);
525+}
526+
527+char* float_obj_field(){
528+ return _obj_field(OBJ_FIELD_FLOAT);
529+}
530+
531+int lib_obj_field(int* object, int fieldname){
532+ int* class;
533+ int i,numfield;
534+ // Check if this is an object (if within the RAM).
535+ if (!withinRAM(object)) err_not_obj();
536+ class=(int*)object[0];
537+ if (!withinRAM(class)) err_not_obj();
538+ // Obtain # of public field
539+ numfield=class[1]&0xff;
540+ for(i=0;i<numfield;i++){
541+ if (class[2+i*2]==fieldname) break;
542+ }
543+ if (i==numfield) err_not_field(fieldname,class[0]);
544+ // Got address of field. Return value as $v0 and address as $v1.
545+ g_temp=(int)(&object[1+i]);
546+ asm volatile("la $v1,%0"::"i"(&g_temp));
547+ asm volatile("lw $v1,0($v1)");
548+ return object[1+i];
549+}
550+
551+/*
552+ Library for letting string field
553+*/
554+
555+void lib_let_str_field(char* prev_str, char* new_str){
556+ int var_num=get_permanent_var_num();
557+ free_perm_str(prev_str);
558+ lib_let_str(new_str,var_num);
559+ return;
560+}
561+
562+/*
563+ Library for calling method statement
564+*/
565+
566+int lib_load_vars_from_fields(int* object, int v0){
567+ // Do nothing if no object
568+ if (object) lib_pre_method(object,LABEL_INIT);
569+ return v0;
570+}
571+
572+int lib_pre_method(int* object, int methodname){
573+ int i,num,nums;
574+ int* class;
575+ // Check if this is an object (if within the RAM).
576+ if (!withinRAM(object)) err_not_obj();
577+ class=(int*)object[0];
578+ if (!withinRAM(class)) err_not_obj();
579+ // Save object field values in local variables in class
580+ nums=class[1];
581+ num=nums&0xff;
582+ for(i=0;i<num;i++){
583+ // Public fields
584+ class+=2;
585+ g_var_mem[class[1]]=object[i+1];
586+ // When string, move from permanent block
587+ if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]);
588+ }
589+ num+=(nums>>8)&0xff;
590+ for(i=i;i<num;i++){
591+ // Private fields
592+ class+=2;
593+ g_var_mem[class[1]]=object[i+1];
594+ // When string/dimension, move from permanent block
595+ if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]);
596+ }
597+ // Seek method
598+ num+=(nums>>16)&0xff;
599+ for(i=i;i<num;i++){
600+ class+=2;
601+ if (class[0]==methodname) break;
602+ }
603+ if (i==num) {
604+ // Method not found
605+ if (methodname==LABEL_INIT) {
606+ // INIT method not found
607+ // Call null function
608+ return (int)(&g_return_code[0]);
609+ } else {
610+ class=(int*)object[0];
611+ err_not_field(methodname,class[0]);
612+ }
613+ }
614+ // Method found. return it.
615+ return class[1];
616+}
617+
618+int lib_save_vars_to_fields(int* object,int v0){
619+ int* class;
620+ // Do nothing if no object
621+ if (!object) return;
622+ // Check if this is an object (if within the RAM).
623+ if (!withinRAM(object)) err_not_obj();
624+ class=(int*)object[0];
625+ if (!withinRAM(class)) err_not_obj();
626+ // save vars
627+ lib_post_method(object,0);
628+ return v0;
629+}
630+
631+int lib_post_method(int* object, int v0){
632+ // Note that v0 (a1) contains the return value from a method.
633+ int i,num,nums;
634+ int* class;
635+ // Restore local variables to object field values
636+ class=(int*)object[0];
637+ nums=class[1];
638+ num=nums&0xff;
639+ for(i=0;i<num;i++){
640+ // Public fields
641+ class+=2;
642+ object[i+1]=g_var_mem[class[1]];
643+ // When string, move to permanent block
644+ if (0x80000000&class[0]) {
645+ if (g_var_size[class[1]]) move_to_perm_block(class[1]);
646+ }
647+ }
648+ num+=(nums>>8)&0xff;
649+ for(i=i;i<num;i++){
650+ // Private fields
651+ class+=2;
652+ object[i+1]=g_var_mem[class[1]];
653+ // When string/dimension, move to permanent block
654+ if (0x80000000&class[0]) {
655+ if (g_var_size[class[1]]) move_to_perm_block(class[1]);
656+ }
657+ }
658+ // all done
659+ return v0;
660+}
661+
662+/*
663+ Method statement
664+*/
665+
666+char* method_statement(){
667+ char* err;
668+ int data[2];
669+ int opos=g_objpos;
670+ // This statement is valid only in class file.
671+ if (!g_compiling_class) return ERR_INVALID_NON_CLASS;
672+ // Insert label for setting $s6
673+ err=label_statement();
674+ if (err) return err;
675+ // Register cmpdata
676+ data[0]=g_label;
677+ data[1]=(int)(&g_object[opos]);
678+ return cmpdata_insert(CMPDATA_FIELD,CMPTYPE_PUBLIC_METHOD,(int*)&data[0],2);
679+}
680+
681+/*
682+ Delete statement
683+*/
684+
685+char* delete_statement(){
686+ char* err;
687+ next_position();
688+ g_srcpos--;
689+ do{
690+ g_srcpos++;
691+ err=get_value();
692+ if (err) return err;
693+ call_quicklib_code(lib_delete,ASM_ADDU_A0_V0_ZERO);
694+ next_position();
695+ } while (g_source[g_srcpos]==',');
696+ return 0;
697+}
698+
699+/*
700+ Call statement
701+*/
702+
703+char* call_statement(){
704+ // Just get an integer value. That is it.
705+ return get_value();
706+}
707+
708+/*
709+ Static statement
710+*/
711+
712+char* static_statement(){
713+ char* err;
714+ int* record;
715+ int data[2];
716+ int i;
717+ int is_private=0;
718+ // This statement is valid only in class file.
719+ if (!g_compiling_class) return ERR_INVALID_NON_CLASS;
720+ // Check which private or public
721+ next_position();
722+ if (nextCodeIs("PRIVATE ")) {
723+ is_private=1;
724+ } else if (nextCodeIs("PUBLIC ")) {
725+ is_private=0;
726+ }
727+ do {
728+ next_position();
729+ i=check_var_name();
730+ if (i<65536) return ERR_SYNTAX;
731+ if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') {
732+ g_srcpos++;
733+ }
734+ // Register public static field
735+ if (is_private) {
736+ // This is the same as USEVAR
737+ // Register varname
738+ err=register_var_name(i);
739+ if (err) return err;
740+ } else {
741+ // Check if there is already a CMPDATA record
742+ cmpdata_reset();
743+ while(record=cmpdata_find(CMPDATA_STATIC)){
744+ if (record[1]!=g_compiling_class) continue;
745+ if (record[2]!=i) continue;
746+ break;
747+ }
748+ if (record) {
749+ // There is already a record.
750+ // Do not allocate new number but use the registered number;
751+ i=record[0]&0xffff;
752+ err=cmpdata_insert(CMPDATA_USEVAR,i,&record[2],1);
753+ if (err) return err;
754+ } else {
755+ // Register varname
756+ err=register_var_name(i);
757+ if (err) return err;
758+ // Insert a CMDATA_STATIC record
759+ data[0]=g_compiling_class; // class name as integer
760+ data[1]=i; // static var name as integer
761+ i=search_var_name(i); // var number of this static field
762+ if (i<0) return ERR_UNKNOWN;
763+ err=cmpdata_insert(CMPDATA_STATIC,i,(int*)&data[0],2);
764+ if (err) return err;
765+ }
766+ }
767+ next_position();
768+ if (g_source[g_srcpos]==',') {
769+ g_srcpos++;
770+ } else {
771+ break;
772+ }
773+ } while(1);
774+ return 0;
775+
776+}
777+
778+/*
779+ Static method
780+ Type is either 0, '$', or '#',
781+ for integer, string, or float
782+*/
783+
784+char* static_method(char type){
785+ char* err;
786+ int* data;
787+ int record[3];
788+ int i,opos,method,stack;
789+ next_position();
790+ // Check class name
791+ i=check_var_name();
792+ if (i<65536) return ERR_SYNTAX;
793+ // Check if the class exists
794+ cmpdata_reset();
795+ while(data=cmpdata_find(CMPDATA_CLASS)){
796+ if (data[1]==i) {
797+ // The class was already defined.
798+ i=0;
799+ break;
800+ }
801+ }
802+ record[0]=i;
803+ // Check '::'
804+ if (g_source[g_srcpos]!=':') return ERR_SYNTAX;
805+ g_srcpos++;
806+ if (g_source[g_srcpos]!=':') return ERR_SYNTAX;
807+ g_srcpos++;
808+ if (i) return ERR_NO_CLASS;
809+ data=(int*)data[2];
810+ // Check method
811+ i=check_var_name();
812+ if (i<65536) return ERR_SYNTAX;
813+ if (data) {
814+ method=(int)search_method(data,i);
815+ if (!method) return ERR_NOT_FIELD;
816+ } else {
817+ method=(int)&g_return_code[0];
818+ record[1]=i;
819+ }
820+ // Check type and '('
821+ if (type) {// Either 0, '$', or '#'
822+ if (g_source[g_srcpos]!=type) return ERR_SYNTAX;
823+ g_srcpos++;
824+
825+ }
826+ if (g_source[g_srcpos]!='(') return ERR_SYNTAX;
827+ // Begin parameter(s) construction routine
828+ check_obj_space(1);
829+ g_object[g_objpos++]=0x34020000; // ori v0,zero,0
830+ err=prepare_args_stack('(');
831+ if (err) return err;
832+ // Calling subroutine, which is static method of class
833+ record[2]=(int)&g_object[g_objpos+5];
834+ check_obj_space(7);
835+ g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
836+ g_object[g_objpos++]=0x04130003; // bgezall zero,label1
837+ g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5)
838+ g_object[g_objpos++]=0x10000003; // beq zero,zero,label2
839+ g_object[g_objpos++]=0x00000000; // nop
840+ // label1:
841+ g_object[g_objpos++]=0x08000000|((method&0x0FFFFFFF)>>2); // j xxxx
842+ g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp)
843+ // label2:
844+ // Register CMPDATA if required.
845+ if (!data) {
846+ cmpdata_insert(CMPDATA_UNSOLVED,CMPTYPE_STATIC_METHOD,(int*)record[0],3);
847+ g_allow_shift_obj=0;
848+ }
849+ // Remove stack
850+ err=remove_args_stack();
851+ if (err) return err;
852+ return 0;
853+}
854+
855+/*
856+ Let object.field statement
857+*/
858+
859+char* let_object_field(){
860+ char* err;
861+ char b3;
862+ int spos,opos;
863+ // $v0 contains the pointer to object
864+ spos=g_srcpos;
865+ opos=g_objpos;
866+ // Try string field, first
867+ err=string_obj_field();
868+ if (err) {
869+ // Integer or float field
870+ g_srcpos=spos;
871+ g_objpos=opos;
872+ err=integer_obj_field();
873+ if (err) return err;
874+ b3=g_source[g_srcpos];
875+ if (b3=='#') g_srcpos++;
876+ } else {
877+ // String field
878+ b3='$';
879+ }
880+ if (g_source[g_srcpos-1]==')') {
881+ // This is a CALL statement
882+ return 0;
883+ }
884+ // $v1 is address to store value. Save it in stack.
885+ check_obj_space(1);
886+ g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
887+ g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp)
888+ if (b3=='$') {
889+ // String field
890+ // Get value
891+ next_position();
892+ if (g_source[g_srcpos]!='=') return ERR_SYNTAX;
893+ g_srcpos++;
894+ err=get_string();
895+ } else if (b3=='#') {
896+ // Float field
897+ // Get value
898+ next_position();
899+ if (g_source[g_srcpos]!='=') return ERR_SYNTAX;
900+ g_srcpos++;
901+ err=get_float();
902+ } else {
903+ // Integer field
904+ // Get value
905+ next_position();
906+ if (g_source[g_srcpos]!='=') return ERR_SYNTAX;
907+ g_srcpos++;
908+ err=get_value();
909+ }
910+ if (err) return err;
911+ // Store in field of object
912+ check_obj_space(4);
913+ g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp)
914+ g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4
915+ g_object[g_objpos++]=0x8C640000; // lw a0,0(v1)
916+ g_object[g_objpos++]=0xAC620000; // sw v0,0(v1)
917+ // Handle permanent block for string field
918+ if (b3=='$') call_quicklib_code(lib_let_str_field,ASM_ADDU_A1_V0_ZERO);
919+ return 0;
822920 }
\ No newline at end of file
--- a/mips/zoea/class.txt
+++ b/mips/zoea/class.txt
@@ -56,6 +56,9 @@ METHOD命令で宣言されたメソッドは、すべてパブリックです
5656 メソッドが指定された場合、オブジェクト作成時に、このメソッドが呼ばれます。INIT
5757 メソッドに引数を与える事も可能です(引数は必須ではありません)。
5858
59+クラス中でオブジェクトへのポインターが必要な場合は、ARGS(-2)で取り出す事が出来
60+ます。
61+
5962 記述例(CLASS1.BASの名前で保存):
6063  FIELD PUBLIC TEST1,TEST2
6164  FIELD PRIVATE TEST3
@@ -103,6 +106,11 @@ NEW(x[,y[,z[, ... ]]])
103106 クターは実装していませんので、必要ならば、それ用のメソッドを作成して破棄する直前に
104107 呼び出して下さい。
105108
109+オブジェクトのフィールドに文字列もしくは配列を用いている場合、オブジェクトを
110+DELETEするだけではこれらの領域は破棄されません。その場合、まずメソッド内でこれら
111+のフィールドを破棄(DELETE命令が使えます)してから、オブジェクトを破棄するようにし
112+て下さい。
113+
106114 記述例:
107115  USECLASS CLASS1
108116  A=NEW(CLASS1)
--- a/mips/zoea/compiler.c
+++ b/mips/zoea/compiler.c
@@ -57,6 +57,8 @@ void start_program(void* addr, void* memory){
5757 asm volatile("la $v0,%0"::"i"(&g_end_addr));
5858 asm volatile("la $v1,label");
5959 asm volatile("sw $v1,0($v0)");
60+ // Set s5 for initial_s5_stack
61+ asm volatile("la $s5,%0"::"i"(&g_initial_s5_stack[2]));
6062 // Set s7 for easy calling call_library()
6163 asm volatile("la $s7,%0"::"i"(&call_library));
6264 // Set fp and execute program
--- a/mips/zoea/compiler.h
+++ b/mips/zoea/compiler.h
@@ -189,6 +189,7 @@ extern unsigned int g_rnd_seed;
189189 extern unsigned int g_label;
190190 extern int g_sdepth;
191191 extern int g_maxsdepth;
192+extern char g_allow_shift_obj;
192193 extern enum variable g_lastvar;
193194 extern char* g_source;
194195 extern int g_srcpos;
@@ -333,7 +334,12 @@ char* register_var_name(int nameint);
333334
334335 char* update_class_info(int class);
335336 char* construct_class_structure(int class);
336-void delete_cmpdata_for_class();
337+void delete_cmpdata_for_class(int class);
338+
339+extern const unsigned int g_initial_s5_stack[3];
340+char* prepare_args_stack(char start_char);
341+char* remove_args_stack(void);
342+char* args_function_main(void);
337343
338344 char* begin_compiling_class(int class);
339345 char* end_compiling_class(int class);
@@ -344,7 +350,10 @@ char* string_obj_field();
344350 char* float_obj_field();
345351 int lib_obj_field(int* object, int fieldname);
346352 int lib_pre_method(int* object, int methodname);
347-int lib_post_method(int* object, int methodname, int v0);
353+int lib_post_method(int* object, int v0);
354+int lib_save_vars_to_fields(int* object,int v0);
355+int lib_load_vars_from_fields(int* object, int v0);
356+
348357 char* method_statement();
349358 char* delete_statement();
350359 char* call_statement();
@@ -352,6 +361,7 @@ void lib_let_str_field(char* str, char* prev_str);
352361 char* let_object_field();
353362 char* static_statement();
354363 char* static_method(char type);
364+char* resolve_unresolved(int class);
355365
356366 /* Error messages */
357367 #define ERR_SYNTAX (char*)(g_err_str[0])
@@ -390,6 +400,24 @@ char* static_method(char type);
390400 #define CMPDATA_CLASS 2
391401 #define CMPDATA_FIELD 3
392402 #define CMPDATA_STATIC 4
403+#define CMPDATA_UNSOLVED 5
404+// Sub types follow
405+#define CMPTYPE_PUBLIC_FIELD 0
406+#define CMPTYPE_PRIVATE_FIELD 1
407+#define CMPTYPE_PUBLIC_METHOD 2
408+#define CMPTYPE_NEW_FUNCTION 0
409+#define CMPTYPE_STATIC_METHOD 1
410+
411+
412+/* Stack position for values in args.c */
413+#define ARGS_SP_SP 4
414+#define ARGS_SP_V0_OBJ 8
415+#define ARGS_SP_PREV_S5 12
416+#define ARGS_SP_NUM_ARGS 16
417+#define ARGS_S5_SP (-12 & 0xFFFF)
418+#define ARGS_S5_V0_OBJ (-8 & 0xFFFF)
419+#define ARGS_S5_PREV_S5 (-4 & 0xFFFF)
420+#define ARGS_S5_NUM_ARGS (0 & 0xFFFF)
393421
394422 /*
395423 Hidden varname 31 bit values
@@ -439,6 +467,7 @@ char* static_method(char type);
439467 #define ASM_ADDU_A3_V0_ZERO 0x00403821
440468 #define ASM_ORI_A0_ZERO_ 0x34040000
441469 #define ASM_LW_A0_XXXX_S8 0x8FC40000
470+#define ASM_LW_A0_XXXX_S5 0x8EA40000
442471
443472 // Division macro for unsigned long
444473 // Valid for 31 bits for all cases and 32 bits for some cases
--- a/mips/zoea/debug.c
+++ b/mips/zoea/debug.c
@@ -229,42 +229,18 @@ static const char bastext[]=
229229 "USECLASS CLASS1\n"
230230 "CLS\n"
231231 "a=new(CLASS1)\n"
232-"call a.INIT(123,456)\n"
233-"CLASS1::TEST=123\n"
234-"CLASS1::TEST2=456\n"
235-"print CLASS1::TEST3(),\n"
236-"print CLASS1::TEST4#(),\n"
237-"print CLASS1::TEST5$(),\n"
232+"print a.T3()\n"
238233 "\n"
239234 "\n"
240235 "\n"
241236 "\n"
242-"end\n"
243-"for i=1 to 150\n"
244-" a=new(CLASS1)\n"
245-" delete a\n"
246-" cursor 0,0\n"
247-" print i,\n"
248-"next\n"
249-"\n"
250-"\n"
251-"\n"
252237 "\n"
253238 "\n";
254239
255240
256241 static const char classtext[]=
257-"REM\n"
258-"STATIC TEST,TEST2\n"
259-"METHOD TEST3\n"
260-"return TEST+TEST2\n"
261-"METHOD TEST4\n"
262-"return 3.14\n"
263-"METHOD TEST5\n"
264-"return hex$(0xabc)\n"
265-"\n"
266-"\n"
267-"\n"
242+"METHOD T3\n"
243+" return 123\n"
268244 "\n"
269245 "\n"
270246 "\n"
@@ -281,9 +257,7 @@ static const void* debugjumptable[]={
281257
282258 int _debug_test(int a0, int a1, int a2, int a3, int param4, int param5){
283259 asm volatile(".set noreorder");
284- asm volatile("lw $a0,0($v1)");
285- asm volatile("nop");
286- asm volatile("nop");
260+ asm volatile("lw $a0,-8($s5)");
287261 asm volatile("nop");
288262 asm volatile("nop");
289263 asm volatile("nop");
--- a/mips/zoea/file.c
+++ b/mips/zoea/file.c
@@ -189,8 +189,10 @@ int compile_and_link_class(char* buff,int class){
189189 i=compile_and_link_file(buff,&classfile[0]);
190190 if (i) break;
191191 // End compiling class
192- end_compiling_class(class);
192+ err=end_compiling_class(class);
193+ if (err) break;
193194 // Initial assembly is a jump statement to jump to the end of class file
195+ // Note that there is at least a code (set line # to $s6) before reaching here
194196 g_object[0]=0x08000000 | ((((int)(&g_object[g_objpos]))&0x0FFFFFFF)>>2); // j xxxxxxxx
195197 // In the next link, current region of object is ignored.
196198 g_object+=g_objpos;
--- a/mips/zoea/float.c
+++ b/mips/zoea/float.c
@@ -148,15 +148,17 @@ char* get_float(){
148148 prevpos=g_objpos;
149149 // Stack decrement command will be filled later
150150 check_obj_space(1);
151- g_objpos++;
151+ g_object[g_objpos++]=0x00000000; // nop (will be replaced by "addiu sp,sp,-xx")
152152 }
153153 err=get_float_sub(priority(OP_VOID));
154154 if (err) return err;
155155 if (g_sdepth==0) {
156156 if (g_maxsdepth==0) {
157157 // Stack was not used.
158- shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1);
159- g_objpos--;
158+ if (g_allow_shift_obj) {
159+ shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1);
160+ g_objpos--;
161+ }
160162 } else {
161163 // Stack was used.
162164 check_obj_space(1);
--- a/mips/zoea/function.c
+++ b/mips/zoea/function.c
@@ -261,23 +261,7 @@ char* inkey_function(void){
261261 }
262262
263263 char* args_function(void){
264- char* err;
265- int i;
266- err=get_value();
267- if (err) return err;
268- i=g_object[g_objpos-1];
269- if ((i>>16)==0x3402) {
270- // Previous object is "ori v0,zero,xxxx".
271- i&=0xffff;
272- i=(i+1)<<2;
273- g_object[g_objpos-1]=0x8EA20000|i; // lw v0,xx(s5)
274- } else {
275- check_obj_space(3);
276- g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2
277- g_object[g_objpos++]=0x02A21021; // addu v0,s5,v0
278- g_object[g_objpos++]=0x8C420004; // lw v0,4(v0)
279- }
280- return 0;
264+ return args_function_main();
281265 }
282266
283267 char* system_function(void){
--- a/mips/zoea/globalvars.c
+++ b/mips/zoea/globalvars.c
@@ -28,6 +28,7 @@ int g_end_addr;
2828 // handling values and strings.
2929 int g_sdepth;
3030 int g_maxsdepth;
31+char g_allow_shift_obj;
3132
3233 // Following var shows what type of variable was defined
3334 // in compiling the last code.
--- a/mips/zoea/memory.c
+++ b/mips/zoea/memory.c
@@ -25,6 +25,16 @@
2525 Therefore, it must be released when it's not used any more.
2626 */
2727
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+
32+#define register_deleted_block(x,y) \
33+ do {\
34+ g_last_deleted_pointer=(x);\
35+ g_last_deleted_size=(y);\
36+ } while(0)
37+
2838 void set_free_area(void* begin, void* end){
2939 int i;
3040 for(i=0;i<ALLOC_BLOCK_NUM;i++){
@@ -87,6 +97,15 @@ void* _alloc_memory_main(int size, int var_num){
8797 g_var_size[var_num]=0;
8898 g_var_pointer[var_num]=0;
8999 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;
108+ }
90109 // Try the block after last block
91110 candidate=0;
92111 for(i=0;i<ALLOC_BLOCK_NUM;i++){
@@ -137,6 +156,7 @@ void free_temp_str(char* str){
137156 for(i=26;i<ALLOC_VAR_NUM;i++){
138157 if (g_var_pointer[i]==pointer) {
139158 if (g_var_size[i] && g_var_mem[i]==(int)str) {
159+ register_deleted_block(pointer,g_var_size[i]);
140160 g_var_size[i]=0;
141161 }
142162 }
@@ -151,6 +171,7 @@ void free_non_temp_str(char* str){
151171 for(i=0;i<26;i++){
152172 if (g_var_pointer[i]==pointer) {
153173 if (g_var_size[i] && g_var_mem[i]==(int)str) {
174+ register_deleted_block(pointer,g_var_size[i]);
154175 g_var_size[i]=0;
155176 g_var_mem[i]=0;
156177 }
@@ -159,8 +180,10 @@ void free_non_temp_str(char* str){
159180 for(i=ALLOC_VAR_NUM;i<ALLOC_BLOCK_NUM;i++){
160181 if (g_var_pointer[i]==pointer && g_var_size[i]) {
161182 if (g_var_size[i] && g_var_mem[i]==(int)str) {
183+ register_deleted_block(pointer,g_var_size[i]);
162184 g_var_size[i]=0;
163185 g_var_mem[i]=0;
186+ if (ALLOC_PERM_BLOCK<=i) g_temp_var_num_candidate=i;
164187 }
165188 }
166189 }
@@ -175,7 +198,9 @@ void free_perm_str(char* str){
175198 for(i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){
176199 if (g_var_pointer[i]==pointer) {
177200 if (g_var_size[i] && g_var_mem[i]==(int)str) {
201+ register_deleted_block(pointer,g_var_size[i]);
178202 g_var_size[i]=0;
203+ g_temp_var_num_candidate=i;
179204 break;
180205 }
181206 }
@@ -185,10 +210,7 @@ void free_perm_str(char* str){
185210 void move_to_perm_block(int var_num){
186211 int i;
187212 // Find available permanent block
188- for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){
189- if (g_var_size[i]==0) break;
190- }
191- if (ALLOC_BLOCK_NUM<=i) err_no_block(); // Not found
213+ i=get_permanent_var_num();
192214 // Available block found.
193215 // Copy value from variable.
194216 g_var_size[i]=g_var_size[var_num];
@@ -214,6 +236,7 @@ int move_from_perm_block_if_exists(int var_num){
214236 g_var_pointer[var_num]=g_var_pointer[i];
215237 // Clear block
216238 g_var_size[i]=0;
239+ g_temp_var_num_candidate=i;
217240 return 1;
218241 }
219242
@@ -224,8 +247,19 @@ void move_from_perm_block(int var_num){
224247
225248 int get_permanent_var_num(){
226249 int i;
250+ // Try candidate first
251+ if (!g_var_size[g_temp_var_num_candidate]) {
252+ if (ALLOC_PERM_BLOCK<g_temp_var_num_candidate &&
253+ g_temp_var_num_candidate<ALLOC_BLOCK_NUM) {
254+ return g_temp_var_num_candidate++;
255+ }
256+ }
257+ // Candidate is not available. Seek all.
227258 for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++) {
228- if (g_var_size[i]==0) return i;
259+ if (g_var_size[i]==0) {
260+ g_temp_var_num_candidate=i+1;
261+ return i;
262+ }
229263 }
230264 err_no_block();
231265 return 0;
@@ -241,14 +275,8 @@ int get_varnum_from_address(void* address){
241275 }
242276
243277 void* lib_calloc_memory(int size){
244- int i;
245- // Find available permanent block
246- for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){
247- if (g_var_size[i]==0) break;
248- }
249- if (ALLOC_BLOCK_NUM<=i) err_no_block(); // Not found
250278 // Allocate memory and return address
251- return calloc_memory(size,i);
279+ return calloc_memory(size,get_permanent_var_num());
252280 }
253281
254282 void lib_delete(int* object){
--- a/mips/zoea/sharedfiles.js
+++ b/mips/zoea/sharedfiles.js
@@ -10,6 +10,7 @@
1010 */
1111
1212 var filearray=[
13+ 'args.c',
1314 'class.c',
1415 'cmpdata.c',
1516 'compiler.c',
--- a/mips/zoea/statement.c
+++ b/mips/zoea/statement.c
@@ -359,9 +359,10 @@ char* gosub_statement_sub(){
359359 // Label/number is constant.
360360 // Linker will change following codes later.
361361 // Note that 0x0812xxxx and 0x0813xxxx are specific codes for these.
362- check_obj_space(6);
363- g_object[g_objpos++]=0x04130003; // bgezall zero,label1
362+ check_obj_space(7);
364363 g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
364+ g_object[g_objpos++]=0x04130003; // bgezall zero,label1
365+ g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5)
365366 g_object[g_objpos++]=0x10000003; // beq zero,zero,label2
366367 g_object[g_objpos++]=0x08120000|((g_label>>16)&0x0000FFFF); // nop
367368 // label1:
@@ -373,15 +374,16 @@ char* gosub_statement_sub(){
373374 err=get_value();
374375 if (err) return err;
375376 call_lib_code(LIB_LABEL);
376- check_obj_space(6);
377- g_object[g_objpos++]=0x04130003; // bgezall zero,label1
378- g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
379- g_object[g_objpos++]=0x10000003; // beq zero,zero,label2
380- g_object[g_objpos++]=0x00000000; // nop
381- // label1:
382- g_object[g_objpos++]=0x00400008; // jr v0
383- g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp)
384- // label2:
377+ check_obj_space(7);
378+ g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4
379+ g_object[g_objpos++]=0x04130003; // bgezall zero,label1
380+ g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5)
381+ g_object[g_objpos++]=0x10000003; // beq zero,zero,label2
382+ g_object[g_objpos++]=0x00000000; // nop
383+ // label1:
384+ g_object[g_objpos++]=0x00400008; // jr v0
385+ g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp)
386+ // label2:
385387 }
386388 return 0;
387389 }
@@ -397,34 +399,10 @@ char* gosub_statement(){
397399 next_position();
398400 // Rewind object and construct argument-creating routine.
399401 g_objpos=opos;
400-
401402 // Begin parameter(s) construction routine
402- // Note that this comment must be copied
403- // when inserting simiar routine to source
404-
405- stack=8;
406- g_object[g_objpos++]=0x27BD0000; // addiu sp,sp,-xx
407- while(g_source[g_srcpos]==',') {
408- g_srcpos++;
409- stack+=4;
410- err=get_stringFloatOrValue();
411- if (err) return err;
412- check_obj_space(1);
413- g_object[g_objpos++]=0xAFA20000|stack; // sw v0,xx(sp)
414- next_position();
415- }
416- // 4(sp) is for $s5, 8(sp) is for # of parameters
417- check_obj_space(5);
418- g_object[g_objpos++]=0xAFB50004; // sw s5,4(sp)
419- g_object[g_objpos++]=0x34020000|(stack/4-2); // ori v0,zero,xx
420- g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp)
421- g_object[g_objpos++]=0x27B50004; // addiu s5,sp,4
422- g_object[opos]|=((0-stack)&0xFFFF); // addiu sp,sp,-xx (See above)
423-
424- // End parameter(s) construction routine
425- // Note that this comment must be copied
426- // when inserting simiar routine to source
427-
403+ g_object[g_objpos++]=0x8EA20000|ARGS_S5_V0_OBJ; // lw v0,-8(s5)
404+ err=prepare_args_stack(',');
405+ if (err) return err;
428406 // Rewind source and construct GOSUB routine again.
429407 opos=spos;
430408 spos=g_srcpos;
@@ -432,9 +410,8 @@ char* gosub_statement(){
432410 err=gosub_statement_sub();
433411 if (err) return err;
434412 // Remove stack
435- check_obj_space(2);
436- g_object[g_objpos++]=0x8FB50004; // lw s5,4(sp)
437- g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx
413+ err=remove_args_stack();
414+ if (err) return err;
438415 // All done, go back to right source position
439416 g_srcpos=spos;
440417 return 0;
@@ -450,10 +427,11 @@ char* return_statement(){
450427 err=get_stringFloatOrValue();
451428 if (err) return err;
452429 }
453- check_obj_space(3);
454- g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp)
455- g_object[g_objpos++]=0x00600008; // jr v1
456- g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4
430+ check_obj_space(4);
431+ g_object[g_objpos++]=0x8EBD0000|ARGS_S5_SP; // lw sp,-12(s5)
432+ g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp)
433+ g_object[g_objpos++]=0x00600008; // jr v1
434+ g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4
457435 return 0;
458436 }
459437
@@ -1258,6 +1236,9 @@ char* var_statement(){
12581236 call_lib_code(LIB_VAR_PUSH);
12591237
12601238 } while (g_source[g_srcpos-1]==',');
1239+ // Renew sp stored in s5 stack.
1240+ check_obj_space(1);
1241+ g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5)
12611242 return 0;
12621243 }
12631244
@@ -1721,6 +1702,9 @@ char* statement(void){
17211702 g_temp_area_used=0;
17221703 // Initialize stack handler used for value
17231704 g_sdepth=g_maxsdepth=0;
1705+ // Allow shifting code object when stack is used.
1706+ // This will be disalloed when CMPDATA_UNSOLVED etc is used.
1707+ g_allow_shift_obj=1;
17241708 // Seek the statement
17251709 for (i=0;i<sizeof(statement_list)/sizeof(statement_list[0]);i+=2){
17261710 if (nextCodeIs((char*)statement_list[i])) break;
--- a/mips/zoea/string.c
+++ b/mips/zoea/string.c
@@ -213,15 +213,17 @@ char* get_string(){
213213 prevpos=g_objpos;
214214 // Stack decrement command will be filled later
215215 check_obj_space(1);
216- g_objpos++;
216+ g_object[g_objpos++]=0x00000000; // nop (will be replaced by "addiu sp,sp,-xx")
217217 }
218218 err=get_string_sub();
219219 if (err) return err;
220220 if (g_sdepth==0) {
221221 if (g_maxsdepth==0) {
222222 // Stack was not used.
223- shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1);
224- g_objpos--;
223+ if (g_allow_shift_obj) {
224+ shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1);
225+ g_objpos--;
226+ }
225227 } else {
226228 // Stack was used.
227229 check_obj_space(1);
--- a/mips/zoea/value.c
+++ b/mips/zoea/value.c
@@ -232,15 +232,17 @@ char* get_value(){
232232 prevpos=g_objpos;
233233 // Stack decrement command will be filled later
234234 check_obj_space(1);
235- g_objpos++;
235+ g_object[g_objpos++]=0x00000000; // nop (will be replaced by "addiu sp,sp,-xx")
236236 }
237237 err=get_value_sub(priority(OP_VOID));
238238 if (err) return err;
239239 if (g_sdepth==0) {
240240 if (g_maxsdepth==0) {
241241 // Stack was not used.
242- shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1);
243- g_objpos--;
242+ if (g_allow_shift_obj) {
243+ shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1);
244+ g_objpos--;
245+ }
244246 } else {
245247 // Stack was used.
246248 check_obj_space(1);