BASIC compiler/interpreter for PIC32MX/MZ-80K
Révision | ff96d68c21430719766477129a3fa47f9c5f400f (tree) |
---|---|
l'heure | 2019-02-11 12:43:51 |
Auteur | Katsumi <kmorimatsu@sour...> |
Commiter | Katsumi |
Update help texts. Update Zoea.
@@ -56,6 +56,9 @@ METHOD命令で宣言されたメソッドは、すべてパブリックです | ||
56 | 56 | メソッドが指定された場合、オブジェクト作成時に、このメソッドが呼ばれます。INIT |
57 | 57 | メソッドに引数を与える事も可能です(引数は必須ではありません)。 |
58 | 58 | |
59 | +クラス中でオブジェクトへのポインターが必要な場合は、ARGS(-2)で取り出す事が出来 | |
60 | +ます。 | |
61 | + | |
59 | 62 | 記述例(CLASS1.BASの名前で保存): |
60 | 63 | FIELD PUBLIC TEST1,TEST2 |
61 | 64 | FIELD PRIVATE TEST3 |
@@ -229,10 +229,7 @@ static const char bastext[]= | ||
229 | 229 | "USECLASS CLASS1\n" |
230 | 230 | "CLS\n" |
231 | 231 | "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" | |
236 | 233 | "\n" |
237 | 234 | "\n" |
238 | 235 | "\n" |
@@ -242,17 +239,8 @@ static const char bastext[]= | ||
242 | 239 | |
243 | 240 | |
244 | 241 | 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" | |
251 | 242 | "METHOD T3\n" |
252 | -" o=new(CLASS1)\n" | |
253 | -" return o\n" | |
254 | -"METHOD T4\n" | |
255 | -" return T6\n" | |
243 | +" return 123\n" | |
256 | 244 | "\n" |
257 | 245 | "\n" |
258 | 246 | "\n" |
@@ -192,6 +192,7 @@ int compile_and_link_class(char* buff,int class){ | ||
192 | 192 | err=end_compiling_class(class); |
193 | 193 | if (err) break; |
194 | 194 | // 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 | |
195 | 196 | g_object[0]=0x08000000 | ((((int)(&g_object[g_objpos]))&0x0FFFFFFF)>>2); // j xxxxxxxx |
196 | 197 | // In the next link, current region of object is ignored. |
197 | 198 | g_object+=g_objpos; |
@@ -246,7 +246,11 @@ FSEEK x | ||
246 | 246 | ABS(x) |
247 | 247 | xの絶対値を返す。 |
248 | 248 | ARGS(x) |
249 | - サブルーチン中で、GOSUBに渡されたx番目の引数を整数値として取り出す。 | |
249 | + サブルーチン中で、GOSUBもしくはメソッドに渡されたx番目の引数を整数値として取 | |
250 | + り出す。但し、 | |
251 | + ARGS(0)は、引数の数を返す。 | |
252 | + ARGS(-1)は、一つ前に使われた引数を格納する配列へのポインターを返す。 | |
253 | + ARGS(-2)は、クラスで用いられた場合、オブジェクトへのポインターを返す。 | |
250 | 254 | ASC(x$) |
251 | 255 | 文字列の最初の一文字の、アスキーコードを返す。 |
252 | 256 | CREAD() |
@@ -324,7 +328,8 @@ VAL(x$) | ||
324 | 328 | ACOS#(x#) |
325 | 329 | x# の逆余弦を実数値で返す。 |
326 | 330 | ARGS#(x) |
327 | - サブルーチン中で、GOSUBに渡されたx番目の引数を実数値として取り出す。 | |
331 | + サブルーチン中で、GOSUBもしくはメソッドに渡されたx番目の引数を実数値として取 | |
332 | + り出す。 | |
328 | 333 | ASIN#(x#) |
329 | 334 | x# の逆正弦を実数値で返す。 |
330 | 335 | ATAN#(x#) |
@@ -381,7 +386,8 @@ A$(x [,y])など | ||
381 | 386 | xの値が負のとき、文字列の右側x文字を返す。 |
382 | 387 | yが指定された場合、y文字分の文字列を返す。 |
383 | 388 | ARGS$(x) |
384 | - サブルーチン中で、GOSUBに渡されたx番目の引数を文字列として取り出す。 | |
389 | + サブルーチン中で、GOSUBもしくはメソッドに渡されたx番目の引数を文字列として取 | |
390 | + り出す。 | |
385 | 391 | CHR$(x) |
386 | 392 | xをアスキーコードとする文字を返す。 |
387 | 393 | DEC$(x) |
@@ -10,6 +10,7 @@ | ||
10 | 10 | */ |
11 | 11 | |
12 | 12 | var filearray=[ |
13 | + 'args.c', | |
13 | 14 | 'class.c', |
14 | 15 | 'cmpdata.c', |
15 | 16 | 'compiler.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 | + |
@@ -67,6 +67,7 @@ file_039=. | ||
67 | 67 | file_040=. |
68 | 68 | file_041=. |
69 | 69 | file_042=. |
70 | +file_043=. | |
70 | 71 | [GENERATED_FILES] |
71 | 72 | file_000=no |
72 | 73 | file_001=no |
@@ -111,6 +112,7 @@ file_039=no | ||
111 | 112 | file_040=no |
112 | 113 | file_041=no |
113 | 114 | file_042=no |
115 | +file_043=no | |
114 | 116 | [OTHER_FILES] |
115 | 117 | file_000=no |
116 | 118 | file_001=no |
@@ -150,11 +152,12 @@ file_034=no | ||
150 | 152 | file_035=no |
151 | 153 | file_036=no |
152 | 154 | file_037=no |
153 | -file_038=yes | |
155 | +file_038=no | |
154 | 156 | file_039=yes |
155 | 157 | file_040=yes |
156 | 158 | file_041=yes |
157 | 159 | file_042=yes |
160 | +file_043=yes | |
158 | 161 | [FILE_INFO] |
159 | 162 | file_000=compiler.c |
160 | 163 | file_001=editor.c |
@@ -180,25 +183,26 @@ file_020=cmpdata.c | ||
180 | 183 | file_021=varname.c |
181 | 184 | file_022=envspecific.c |
182 | 185 | 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 | |
202 | 206 | [SUITE_INFO] |
203 | 207 | suite_guid={62D235D8-2DB2-49CD-AF24-5489A6015337} |
204 | 208 | suite_state= |
@@ -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; | |
822 | 920 | } |
\ No newline at end of file |
@@ -56,6 +56,9 @@ METHOD命令で宣言されたメソッドは、すべてパブリックです | ||
56 | 56 | メソッドが指定された場合、オブジェクト作成時に、このメソッドが呼ばれます。INIT |
57 | 57 | メソッドに引数を与える事も可能です(引数は必須ではありません)。 |
58 | 58 | |
59 | +クラス中でオブジェクトへのポインターが必要な場合は、ARGS(-2)で取り出す事が出来 | |
60 | +ます。 | |
61 | + | |
59 | 62 | 記述例(CLASS1.BASの名前で保存): |
60 | 63 | FIELD PUBLIC TEST1,TEST2 |
61 | 64 | FIELD PRIVATE TEST3 |
@@ -103,6 +106,11 @@ NEW(x[,y[,z[, ... ]]]) | ||
103 | 106 | クターは実装していませんので、必要ならば、それ用のメソッドを作成して破棄する直前に |
104 | 107 | 呼び出して下さい。 |
105 | 108 | |
109 | +オブジェクトのフィールドに文字列もしくは配列を用いている場合、オブジェクトを | |
110 | +DELETEするだけではこれらの領域は破棄されません。その場合、まずメソッド内でこれら | |
111 | +のフィールドを破棄(DELETE命令が使えます)してから、オブジェクトを破棄するようにし | |
112 | +て下さい。 | |
113 | + | |
106 | 114 | 記述例: |
107 | 115 | USECLASS CLASS1 |
108 | 116 | A=NEW(CLASS1) |
@@ -57,6 +57,8 @@ void start_program(void* addr, void* memory){ | ||
57 | 57 | asm volatile("la $v0,%0"::"i"(&g_end_addr)); |
58 | 58 | asm volatile("la $v1,label"); |
59 | 59 | 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])); | |
60 | 62 | // Set s7 for easy calling call_library() |
61 | 63 | asm volatile("la $s7,%0"::"i"(&call_library)); |
62 | 64 | // Set fp and execute program |
@@ -189,6 +189,7 @@ extern unsigned int g_rnd_seed; | ||
189 | 189 | extern unsigned int g_label; |
190 | 190 | extern int g_sdepth; |
191 | 191 | extern int g_maxsdepth; |
192 | +extern char g_allow_shift_obj; | |
192 | 193 | extern enum variable g_lastvar; |
193 | 194 | extern char* g_source; |
194 | 195 | extern int g_srcpos; |
@@ -333,7 +334,12 @@ char* register_var_name(int nameint); | ||
333 | 334 | |
334 | 335 | char* update_class_info(int class); |
335 | 336 | 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); | |
337 | 343 | |
338 | 344 | char* begin_compiling_class(int class); |
339 | 345 | char* end_compiling_class(int class); |
@@ -344,7 +350,10 @@ char* string_obj_field(); | ||
344 | 350 | char* float_obj_field(); |
345 | 351 | int lib_obj_field(int* object, int fieldname); |
346 | 352 | 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 | + | |
348 | 357 | char* method_statement(); |
349 | 358 | char* delete_statement(); |
350 | 359 | char* call_statement(); |
@@ -352,6 +361,7 @@ void lib_let_str_field(char* str, char* prev_str); | ||
352 | 361 | char* let_object_field(); |
353 | 362 | char* static_statement(); |
354 | 363 | char* static_method(char type); |
364 | +char* resolve_unresolved(int class); | |
355 | 365 | |
356 | 366 | /* Error messages */ |
357 | 367 | #define ERR_SYNTAX (char*)(g_err_str[0]) |
@@ -390,6 +400,24 @@ char* static_method(char type); | ||
390 | 400 | #define CMPDATA_CLASS 2 |
391 | 401 | #define CMPDATA_FIELD 3 |
392 | 402 | #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) | |
393 | 421 | |
394 | 422 | /* |
395 | 423 | Hidden varname 31 bit values |
@@ -439,6 +467,7 @@ char* static_method(char type); | ||
439 | 467 | #define ASM_ADDU_A3_V0_ZERO 0x00403821 |
440 | 468 | #define ASM_ORI_A0_ZERO_ 0x34040000 |
441 | 469 | #define ASM_LW_A0_XXXX_S8 0x8FC40000 |
470 | +#define ASM_LW_A0_XXXX_S5 0x8EA40000 | |
442 | 471 | |
443 | 472 | // Division macro for unsigned long |
444 | 473 | // Valid for 31 bits for all cases and 32 bits for some cases |
@@ -229,42 +229,18 @@ static const char bastext[]= | ||
229 | 229 | "USECLASS CLASS1\n" |
230 | 230 | "CLS\n" |
231 | 231 | "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" | |
238 | 233 | "\n" |
239 | 234 | "\n" |
240 | 235 | "\n" |
241 | 236 | "\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" | |
252 | 237 | "\n" |
253 | 238 | "\n"; |
254 | 239 | |
255 | 240 | |
256 | 241 | 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" | |
268 | 244 | "\n" |
269 | 245 | "\n" |
270 | 246 | "\n" |
@@ -281,9 +257,7 @@ static const void* debugjumptable[]={ | ||
281 | 257 | |
282 | 258 | int _debug_test(int a0, int a1, int a2, int a3, int param4, int param5){ |
283 | 259 | 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)"); | |
287 | 261 | asm volatile("nop"); |
288 | 262 | asm volatile("nop"); |
289 | 263 | asm volatile("nop"); |
@@ -189,8 +189,10 @@ int compile_and_link_class(char* buff,int class){ | ||
189 | 189 | i=compile_and_link_file(buff,&classfile[0]); |
190 | 190 | if (i) break; |
191 | 191 | // End compiling class |
192 | - end_compiling_class(class); | |
192 | + err=end_compiling_class(class); | |
193 | + if (err) break; | |
193 | 194 | // 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 | |
194 | 196 | g_object[0]=0x08000000 | ((((int)(&g_object[g_objpos]))&0x0FFFFFFF)>>2); // j xxxxxxxx |
195 | 197 | // In the next link, current region of object is ignored. |
196 | 198 | g_object+=g_objpos; |
@@ -148,15 +148,17 @@ char* get_float(){ | ||
148 | 148 | prevpos=g_objpos; |
149 | 149 | // Stack decrement command will be filled later |
150 | 150 | check_obj_space(1); |
151 | - g_objpos++; | |
151 | + g_object[g_objpos++]=0x00000000; // nop (will be replaced by "addiu sp,sp,-xx") | |
152 | 152 | } |
153 | 153 | err=get_float_sub(priority(OP_VOID)); |
154 | 154 | if (err) return err; |
155 | 155 | if (g_sdepth==0) { |
156 | 156 | if (g_maxsdepth==0) { |
157 | 157 | // 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 | + } | |
160 | 162 | } else { |
161 | 163 | // Stack was used. |
162 | 164 | check_obj_space(1); |
@@ -261,23 +261,7 @@ char* inkey_function(void){ | ||
261 | 261 | } |
262 | 262 | |
263 | 263 | 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(); | |
281 | 265 | } |
282 | 266 | |
283 | 267 | char* system_function(void){ |
@@ -28,6 +28,7 @@ int g_end_addr; | ||
28 | 28 | // handling values and strings. |
29 | 29 | int g_sdepth; |
30 | 30 | int g_maxsdepth; |
31 | +char g_allow_shift_obj; | |
31 | 32 | |
32 | 33 | // Following var shows what type of variable was defined |
33 | 34 | // in compiling the last code. |
@@ -25,6 +25,16 @@ | ||
25 | 25 | Therefore, it must be released when it's not used any more. |
26 | 26 | */ |
27 | 27 | |
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 | + | |
28 | 38 | void set_free_area(void* begin, void* end){ |
29 | 39 | int i; |
30 | 40 | for(i=0;i<ALLOC_BLOCK_NUM;i++){ |
@@ -87,6 +97,15 @@ void* _alloc_memory_main(int size, int var_num){ | ||
87 | 97 | g_var_size[var_num]=0; |
88 | 98 | g_var_pointer[var_num]=0; |
89 | 99 | 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 | + } | |
90 | 109 | // Try the block after last block |
91 | 110 | candidate=0; |
92 | 111 | for(i=0;i<ALLOC_BLOCK_NUM;i++){ |
@@ -137,6 +156,7 @@ void free_temp_str(char* str){ | ||
137 | 156 | for(i=26;i<ALLOC_VAR_NUM;i++){ |
138 | 157 | if (g_var_pointer[i]==pointer) { |
139 | 158 | if (g_var_size[i] && g_var_mem[i]==(int)str) { |
159 | + register_deleted_block(pointer,g_var_size[i]); | |
140 | 160 | g_var_size[i]=0; |
141 | 161 | } |
142 | 162 | } |
@@ -151,6 +171,7 @@ void free_non_temp_str(char* str){ | ||
151 | 171 | for(i=0;i<26;i++){ |
152 | 172 | if (g_var_pointer[i]==pointer) { |
153 | 173 | if (g_var_size[i] && g_var_mem[i]==(int)str) { |
174 | + register_deleted_block(pointer,g_var_size[i]); | |
154 | 175 | g_var_size[i]=0; |
155 | 176 | g_var_mem[i]=0; |
156 | 177 | } |
@@ -159,8 +180,10 @@ void free_non_temp_str(char* str){ | ||
159 | 180 | for(i=ALLOC_VAR_NUM;i<ALLOC_BLOCK_NUM;i++){ |
160 | 181 | if (g_var_pointer[i]==pointer && g_var_size[i]) { |
161 | 182 | if (g_var_size[i] && g_var_mem[i]==(int)str) { |
183 | + register_deleted_block(pointer,g_var_size[i]); | |
162 | 184 | g_var_size[i]=0; |
163 | 185 | g_var_mem[i]=0; |
186 | + if (ALLOC_PERM_BLOCK<=i) g_temp_var_num_candidate=i; | |
164 | 187 | } |
165 | 188 | } |
166 | 189 | } |
@@ -175,7 +198,9 @@ void free_perm_str(char* str){ | ||
175 | 198 | for(i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){ |
176 | 199 | if (g_var_pointer[i]==pointer) { |
177 | 200 | if (g_var_size[i] && g_var_mem[i]==(int)str) { |
201 | + register_deleted_block(pointer,g_var_size[i]); | |
178 | 202 | g_var_size[i]=0; |
203 | + g_temp_var_num_candidate=i; | |
179 | 204 | break; |
180 | 205 | } |
181 | 206 | } |
@@ -185,10 +210,7 @@ void free_perm_str(char* str){ | ||
185 | 210 | void move_to_perm_block(int var_num){ |
186 | 211 | int i; |
187 | 212 | // 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(); | |
192 | 214 | // Available block found. |
193 | 215 | // Copy value from variable. |
194 | 216 | g_var_size[i]=g_var_size[var_num]; |
@@ -214,6 +236,7 @@ int move_from_perm_block_if_exists(int var_num){ | ||
214 | 236 | g_var_pointer[var_num]=g_var_pointer[i]; |
215 | 237 | // Clear block |
216 | 238 | g_var_size[i]=0; |
239 | + g_temp_var_num_candidate=i; | |
217 | 240 | return 1; |
218 | 241 | } |
219 | 242 |
@@ -224,8 +247,19 @@ void move_from_perm_block(int var_num){ | ||
224 | 247 | |
225 | 248 | int get_permanent_var_num(){ |
226 | 249 | 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. | |
227 | 258 | 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 | + } | |
229 | 263 | } |
230 | 264 | err_no_block(); |
231 | 265 | return 0; |
@@ -241,14 +275,8 @@ int get_varnum_from_address(void* address){ | ||
241 | 275 | } |
242 | 276 | |
243 | 277 | 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 | |
250 | 278 | // Allocate memory and return address |
251 | - return calloc_memory(size,i); | |
279 | + return calloc_memory(size,get_permanent_var_num()); | |
252 | 280 | } |
253 | 281 | |
254 | 282 | void lib_delete(int* object){ |
@@ -10,6 +10,7 @@ | ||
10 | 10 | */ |
11 | 11 | |
12 | 12 | var filearray=[ |
13 | + 'args.c', | |
13 | 14 | 'class.c', |
14 | 15 | 'cmpdata.c', |
15 | 16 | 'compiler.c', |
@@ -359,9 +359,10 @@ char* gosub_statement_sub(){ | ||
359 | 359 | // Label/number is constant. |
360 | 360 | // Linker will change following codes later. |
361 | 361 | // 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); | |
364 | 363 | 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) | |
365 | 366 | g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 |
366 | 367 | g_object[g_objpos++]=0x08120000|((g_label>>16)&0x0000FFFF); // nop |
367 | 368 | // label1: |
@@ -373,15 +374,16 @@ char* gosub_statement_sub(){ | ||
373 | 374 | err=get_value(); |
374 | 375 | if (err) return err; |
375 | 376 | 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: | |
385 | 387 | } |
386 | 388 | return 0; |
387 | 389 | } |
@@ -397,34 +399,10 @@ char* gosub_statement(){ | ||
397 | 399 | next_position(); |
398 | 400 | // Rewind object and construct argument-creating routine. |
399 | 401 | g_objpos=opos; |
400 | - | |
401 | 402 | // 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; | |
428 | 406 | // Rewind source and construct GOSUB routine again. |
429 | 407 | opos=spos; |
430 | 408 | spos=g_srcpos; |
@@ -432,9 +410,8 @@ char* gosub_statement(){ | ||
432 | 410 | err=gosub_statement_sub(); |
433 | 411 | if (err) return err; |
434 | 412 | // 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; | |
438 | 415 | // All done, go back to right source position |
439 | 416 | g_srcpos=spos; |
440 | 417 | return 0; |
@@ -450,10 +427,11 @@ char* return_statement(){ | ||
450 | 427 | err=get_stringFloatOrValue(); |
451 | 428 | if (err) return err; |
452 | 429 | } |
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 | |
457 | 435 | return 0; |
458 | 436 | } |
459 | 437 |
@@ -1258,6 +1236,9 @@ char* var_statement(){ | ||
1258 | 1236 | call_lib_code(LIB_VAR_PUSH); |
1259 | 1237 | |
1260 | 1238 | } 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) | |
1261 | 1242 | return 0; |
1262 | 1243 | } |
1263 | 1244 |
@@ -1721,6 +1702,9 @@ char* statement(void){ | ||
1721 | 1702 | g_temp_area_used=0; |
1722 | 1703 | // Initialize stack handler used for value |
1723 | 1704 | 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; | |
1724 | 1708 | // Seek the statement |
1725 | 1709 | for (i=0;i<sizeof(statement_list)/sizeof(statement_list[0]);i+=2){ |
1726 | 1710 | if (nextCodeIs((char*)statement_list[i])) break; |
@@ -213,15 +213,17 @@ char* get_string(){ | ||
213 | 213 | prevpos=g_objpos; |
214 | 214 | // Stack decrement command will be filled later |
215 | 215 | check_obj_space(1); |
216 | - g_objpos++; | |
216 | + g_object[g_objpos++]=0x00000000; // nop (will be replaced by "addiu sp,sp,-xx") | |
217 | 217 | } |
218 | 218 | err=get_string_sub(); |
219 | 219 | if (err) return err; |
220 | 220 | if (g_sdepth==0) { |
221 | 221 | if (g_maxsdepth==0) { |
222 | 222 | // 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 | + } | |
225 | 227 | } else { |
226 | 228 | // Stack was used. |
227 | 229 | check_obj_space(1); |
@@ -232,15 +232,17 @@ char* get_value(){ | ||
232 | 232 | prevpos=g_objpos; |
233 | 233 | // Stack decrement command will be filled later |
234 | 234 | check_obj_space(1); |
235 | - g_objpos++; | |
235 | + g_object[g_objpos++]=0x00000000; // nop (will be replaced by "addiu sp,sp,-xx") | |
236 | 236 | } |
237 | 237 | err=get_value_sub(priority(OP_VOID)); |
238 | 238 | if (err) return err; |
239 | 239 | if (g_sdepth==0) { |
240 | 240 | if (g_maxsdepth==0) { |
241 | 241 | // 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 | + } | |
244 | 246 | } else { |
245 | 247 | // Stack was used. |
246 | 248 | check_obj_space(1); |