BASIC compiler/interpreter for PIC32MX/MZ-80K
修订版 | fa324cd371259c174345975f86a3a42b551b0506 (tree) |
---|---|
时间 | 2019-02-06 06:00:48 |
作者 | Katsumi <kmorimatsu@sour...> |
Commiter | Katsumi |
Support recursive class/object structure.
@@ -1,762 +1,881 @@ | ||
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 | - // Begin parameter(s) construction routine | |
323 | - err=prepare_args_stack('('); | |
324 | - if (err) return err; | |
325 | - if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
326 | - g_srcpos++; | |
327 | - // Determine address of method and store fields to local variables. | |
328 | - check_obj_space(3); | |
329 | - g_object[g_objpos++]=0x8FA20000|ARGS_SP_V0_OBJ; // lw v0,8(sp) | |
330 | - g_object[g_objpos++]=0x3C050000|((method>>16)&0x0000FFFF); // lui a1,xxxx | |
331 | - g_object[g_objpos++]=0x34A50000|(method&0x0000FFFF); // ori a1,a1,xxxx | |
332 | - call_quicklib_code(lib_pre_method,ASM_ADDU_A0_V0_ZERO); | |
333 | - // Call method address here. Same routine for GOSUB statement with integer value is used. | |
334 | - check_obj_space(6); | |
335 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
336 | - g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
337 | - g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5) | |
338 | - g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
339 | - g_object[g_objpos++]=0x00000000; // nop | |
340 | - // label1: | |
341 | - g_object[g_objpos++]=0x00400008; // jr v0 | |
342 | - g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) // label2: | |
343 | - // Restore fields from local variables. | |
344 | - check_obj_space(3); | |
345 | - g_object[g_objpos++]=0x8FA40008; // lw a0,8(sp) | |
346 | - call_quicklib_code(lib_post_method,ASM_ADDU_A1_V0_ZERO); | |
347 | - // Remove stack | |
348 | - err=remove_args_stack(); | |
349 | - if (err) return err; | |
350 | - return 0; | |
351 | -} | |
352 | - | |
353 | -/* | |
354 | - char* integer_obj_field(); | |
355 | - char* string_obj_field(); | |
356 | - char* float_obj_field(); | |
357 | - Implementation of access to field of object. | |
358 | - This feature is recursive. When an object is applied to the field of another object, | |
359 | - following expression is possible (for example): | |
360 | - obj1.field1.field2 | |
361 | - | |
362 | -*/ | |
363 | - | |
364 | -#define OBJ_FIELD_INTEGER 0 | |
365 | -#define OBJ_FIELD_STRING '$' | |
366 | -#define OBJ_FIELD_FLOAT '#' | |
367 | - | |
368 | -char* _obj_field(char mode){ | |
369 | - // $v0 contains the address of object. | |
370 | - int i; | |
371 | - char* err; | |
372 | - do { | |
373 | - i=check_var_name(); | |
374 | - if (i<65536) return ERR_SYNTAX; | |
375 | - if (g_source[g_srcpos]=='(' && mode==OBJ_FIELD_INTEGER) { | |
376 | - // This is a method | |
377 | - return obj_method(i); | |
378 | - } else if (g_source[g_srcpos+1]=='(') { | |
379 | - if (g_source[g_srcpos]==mode) { | |
380 | - // This is a string/float method | |
381 | - g_srcpos++; | |
382 | - return obj_method(i); | |
383 | - } | |
384 | - } else if (g_source[g_srcpos]==mode && mode==OBJ_FIELD_STRING) { | |
385 | - // This is a string field. Raise 31st bit. | |
386 | - i|=0x80000000; | |
387 | - } | |
388 | - check_obj_space(2); | |
389 | - g_object[g_objpos++]=0x3C050000|((i>>16)&0x0000FFFF); // lui a1,xxxx | |
390 | - g_object[g_objpos++]=0x34A50000|(i&0x0000FFFF); // ori a1,a1,xxxx | |
391 | - // First and second arguments are address of object and field name, respectively. | |
392 | - call_quicklib_code(lib_obj_field,ASM_ADDU_A0_V0_ZERO); | |
393 | - // Check if "." follows | |
394 | - if (g_source[g_srcpos]=='.') { | |
395 | - // "." found. $v0 is adress of an object. See the field. | |
396 | - g_srcpos++; | |
397 | - continue; | |
398 | - } | |
399 | - } while(0); | |
400 | - // All done. Check variable type | |
401 | - if (mode==OBJ_FIELD_INTEGER) return 0; | |
402 | - else if (g_source[g_srcpos]==mode) { | |
403 | - g_srcpos++; | |
404 | - return 0; | |
405 | - } else return ERR_SYNTAX; | |
406 | -} | |
407 | - | |
408 | -char* integer_obj_field(){ | |
409 | - return _obj_field(OBJ_FIELD_INTEGER); | |
410 | -} | |
411 | - | |
412 | -char* string_obj_field(){ | |
413 | - return _obj_field(OBJ_FIELD_STRING); | |
414 | -} | |
415 | - | |
416 | -char* float_obj_field(){ | |
417 | - return _obj_field(OBJ_FIELD_FLOAT); | |
418 | -} | |
419 | - | |
420 | -int lib_obj_field(int* object, int fieldname){ | |
421 | - int* class; | |
422 | - int i,numfield; | |
423 | - // Check if this is an object (if within the RAM). | |
424 | - if (!withinRAM(object)) err_not_obj(); | |
425 | - class=(int*)object[0]; | |
426 | - if (!withinRAM(class)) err_not_obj(); | |
427 | - // Obtain # of public field | |
428 | - numfield=class[1]&0xff; | |
429 | - for(i=0;i<numfield;i++){ | |
430 | - if (class[2+i*2]==fieldname) break; | |
431 | - } | |
432 | - if (i==numfield) err_not_field(fieldname,class[0]); | |
433 | - // Got address of field. Return value as $v0 and address as $v1. | |
434 | - g_temp=(int)(&object[1+i]); | |
435 | - asm volatile("la $v1,%0"::"i"(&g_temp)); | |
436 | - asm volatile("lw $v1,0($v1)"); | |
437 | - return object[1+i]; | |
438 | -} | |
439 | - | |
440 | -/* | |
441 | - Library for letting string field | |
442 | -*/ | |
443 | - | |
444 | -void lib_let_str_field(char* prev_str, char* new_str){ | |
445 | - int var_num=get_permanent_var_num(); | |
446 | - free_perm_str(prev_str); | |
447 | - lib_let_str(new_str,var_num); | |
448 | - return; | |
449 | -} | |
450 | - | |
451 | -/* | |
452 | - Library for calling method statement | |
453 | -*/ | |
454 | - | |
455 | -// Return code used for calling null method | |
456 | -static const unsigned int g_return_code[]={ | |
457 | - 0x8FA30004, // lw v1,4(sp) | |
458 | - 0x00600008, // jr v1 | |
459 | - 0x27BD0004, // addiu sp,sp,4 | |
460 | -}; | |
461 | - | |
462 | -int lib_pre_method(int* object, int methodname){ | |
463 | - int i,num,nums; | |
464 | - int* class; | |
465 | - // Check if this is an object (if within the RAM). | |
466 | - if (!withinRAM(object)) err_not_obj(); | |
467 | - class=(int*)object[0]; | |
468 | - if (!withinRAM(class)) err_not_obj(); | |
469 | - // Save object field values in local variables in class | |
470 | - nums=class[1]; | |
471 | - num=nums&0xff; | |
472 | - for(i=0;i<num;i++){ | |
473 | - // Public fields | |
474 | - class+=2; | |
475 | - g_var_mem[class[1]]=object[i+1]; | |
476 | - // When string, move from permanent block | |
477 | - if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]); | |
478 | - } | |
479 | - num+=(nums>>8)&0xff; | |
480 | - for(i=i;i<num;i++){ | |
481 | - // Private fields | |
482 | - class+=2; | |
483 | - g_var_mem[class[1]]=object[i+1]; | |
484 | - // When string/dimension, move from permanent block | |
485 | - if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]); | |
486 | - } | |
487 | - // Seek method | |
488 | - num+=(nums>>16)&0xff; | |
489 | - for(i=i;i<num;i++){ | |
490 | - class+=2; | |
491 | - if (class[0]==methodname) break; | |
492 | - } | |
493 | - if (i==num) { | |
494 | - // Method not found | |
495 | - if (methodname==LABEL_INIT) { | |
496 | - // INIT method not found | |
497 | - // Call null function | |
498 | - return (int)(&g_return_code[0]); | |
499 | - } else { | |
500 | - class=(int*)object[0]; | |
501 | - err_not_field(methodname,class[0]); | |
502 | - } | |
503 | - } | |
504 | - // Method found. return it. | |
505 | - return class[1]; | |
506 | -} | |
507 | - | |
508 | -int lib_post_method(int* object, int v0){ | |
509 | - // Note that v0 (a1) contains the return value from a method. | |
510 | - int i,num,nums; | |
511 | - int* class; | |
512 | - // Restore local variables to object field values | |
513 | - class=(int*)object[0]; | |
514 | - nums=class[1]; | |
515 | - num=nums&0xff; | |
516 | - for(i=0;i<num;i++){ | |
517 | - // Public fields | |
518 | - class+=2; | |
519 | - object[i+1]=g_var_mem[class[1]]; | |
520 | - // When string, move to permanent block | |
521 | - if (0x80000000&class[0]) { | |
522 | - if (g_var_size[class[1]]) move_to_perm_block(class[1]); | |
523 | - } | |
524 | - } | |
525 | - num+=(nums>>8)&0xff; | |
526 | - for(i=i;i<num;i++){ | |
527 | - // Private fields | |
528 | - class+=2; | |
529 | - object[i+1]=g_var_mem[class[1]]; | |
530 | - // When string/dimension, move to permanent block | |
531 | - if (0x80000000&class[0]) { | |
532 | - if (g_var_size[class[1]]) move_to_perm_block(class[1]); | |
533 | - } | |
534 | - } | |
535 | - // all done | |
536 | - return v0; | |
537 | -} | |
538 | - | |
539 | -/* | |
540 | - Method statement | |
541 | -*/ | |
542 | - | |
543 | -char* method_statement(){ | |
544 | - char* err; | |
545 | - int data[2]; | |
546 | - int opos=g_objpos; | |
547 | - // This statement is valid only in class file. | |
548 | - if (!g_compiling_class) return ERR_INVALID_NON_CLASS; | |
549 | - // Insert label for setting $s6 | |
550 | - err=label_statement(); | |
551 | - if (err) return err; | |
552 | - // Register cmpdata | |
553 | - data[0]=g_label; | |
554 | - data[1]=(int)(&g_object[opos]); | |
555 | - return cmpdata_insert(CMPDATA_FIELD,PUBLIC_METHOD,(int*)&data[0],2); | |
556 | -} | |
557 | - | |
558 | -/* | |
559 | - Delete statement | |
560 | -*/ | |
561 | - | |
562 | -char* delete_statement(){ | |
563 | - char* err; | |
564 | - next_position(); | |
565 | - g_srcpos--; | |
566 | - do{ | |
567 | - g_srcpos++; | |
568 | - err=get_value(); | |
569 | - if (err) return err; | |
570 | - call_quicklib_code(lib_delete,ASM_ADDU_A0_V0_ZERO); | |
571 | - next_position(); | |
572 | - } while (g_source[g_srcpos]==','); | |
573 | - return 0; | |
574 | -} | |
575 | - | |
576 | -/* | |
577 | - Call statement | |
578 | -*/ | |
579 | - | |
580 | -char* call_statement(){ | |
581 | - // Just get an integer value. That is it. | |
582 | - return get_value(); | |
583 | -} | |
584 | - | |
585 | -/* | |
586 | - Static statement | |
587 | -*/ | |
588 | - | |
589 | -char* static_statement(){ | |
590 | - char* err; | |
591 | - int data[2]; | |
592 | - int i; | |
593 | - int is_private=0; | |
594 | - // This statement is valid only in class file. | |
595 | - if (!g_compiling_class) return ERR_INVALID_NON_CLASS; | |
596 | - // Check which private or public | |
597 | - next_position(); | |
598 | - if (nextCodeIs("PRIVATE ")) { | |
599 | - is_private=1; | |
600 | - } else if (nextCodeIs("PUBLIC ")) { | |
601 | - is_private=0; | |
602 | - } | |
603 | - do { | |
604 | - next_position(); | |
605 | - i=check_var_name(); | |
606 | - if (i<65536) return ERR_SYNTAX; | |
607 | - // Register varname | |
608 | - err=register_var_name(i); | |
609 | - if (err) return err; | |
610 | - if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') { | |
611 | - g_srcpos++; | |
612 | - } | |
613 | - // Register public static field | |
614 | - if (!is_private) { | |
615 | - data[0]=g_compiling_class; // class name as integer | |
616 | - data[1]=i; // static var name as integer | |
617 | - i=search_var_name(i); // var number of this static field | |
618 | - if (i<0) return ERR_UNKNOWN; | |
619 | - err=cmpdata_insert(CMPDATA_STATIC,i,(int*)&data[0],2); | |
620 | - if (err) return err; | |
621 | - } | |
622 | - next_position(); | |
623 | - if (g_source[g_srcpos]==',') { | |
624 | - g_srcpos++; | |
625 | - } else { | |
626 | - break; | |
627 | - } | |
628 | - } while(1); | |
629 | - return 0; | |
630 | - | |
631 | -} | |
632 | - | |
633 | -/* | |
634 | - Static method | |
635 | - Type is either 0, '$', or '#', | |
636 | - for integer, string, or float | |
637 | -*/ | |
638 | - | |
639 | -char* static_method(char type){ | |
640 | - char* err; | |
641 | - int* data; | |
642 | - int i,opos,method,stack; | |
643 | - next_position(); | |
644 | - // Check class name | |
645 | - i=check_var_name(); | |
646 | - if (i<65536) return ERR_SYNTAX; | |
647 | - // Check if the class exists | |
648 | - cmpdata_reset(); | |
649 | - while(data=cmpdata_find(CMPDATA_CLASS)){ | |
650 | - if (data[1]==i) { | |
651 | - // The class was already defined. | |
652 | - i=0; | |
653 | - break; | |
654 | - } | |
655 | - } | |
656 | - // Check '::' | |
657 | - if (g_source[g_srcpos]!=':') return ERR_SYNTAX; | |
658 | - g_srcpos++; | |
659 | - if (g_source[g_srcpos]!=':') return ERR_SYNTAX; | |
660 | - g_srcpos++; | |
661 | - if (i) return ERR_NO_CLASS; | |
662 | - data=(int*)data[2]; | |
663 | - // Check method | |
664 | - i=check_var_name(); | |
665 | - if (i<65536) return ERR_SYNTAX; | |
666 | - method=(int)search_method(data,i); | |
667 | - if (!method) return ERR_NOT_FIELD; | |
668 | - // Check type and '(' | |
669 | - if (type) {// Either 0, '$', or '#' | |
670 | - if (g_source[g_srcpos]!=type) return ERR_SYNTAX; | |
671 | - g_srcpos++; | |
672 | - | |
673 | - } | |
674 | - if (g_source[g_srcpos]!='(') return ERR_SYNTAX; | |
675 | - // Begin parameter(s) construction routine | |
676 | - check_obj_space(1); | |
677 | - g_object[g_objpos++]=0x34020000; // ori v0,zero,0 | |
678 | - err=prepare_args_stack('('); | |
679 | - if (err) return err; | |
680 | - // Calling subroutine, which is static method of class | |
681 | - check_obj_space(7); | |
682 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
683 | - g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
684 | - g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5) | |
685 | - g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
686 | - g_object[g_objpos++]=0x00000000; // nop | |
687 | - // label1: | |
688 | - g_object[g_objpos++]=0x08000000|((method&0x0FFFFFFF)>>2); // j xxxx | |
689 | - g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
690 | - // label2: | |
691 | - // Remove stack | |
692 | - err=remove_args_stack(); | |
693 | - if (err) return err; | |
694 | - return 0; | |
695 | -} | |
696 | - | |
697 | -/* | |
698 | - Let object.field statement | |
699 | -*/ | |
700 | - | |
701 | -char* let_object_field(){ | |
702 | - char* err; | |
703 | - char b3; | |
704 | - int spos,opos; | |
705 | - // $v0 contains the pointer to object | |
706 | - spos=g_srcpos; | |
707 | - opos=g_objpos; | |
708 | - // Try string field, first | |
709 | - err=string_obj_field(); | |
710 | - if (err) { | |
711 | - // Integer or float field | |
712 | - g_srcpos=spos; | |
713 | - g_objpos=opos; | |
714 | - err=integer_obj_field(); | |
715 | - if (err) return err; | |
716 | - b3=g_source[g_srcpos]; | |
717 | - if (b3=='#') g_srcpos++; | |
718 | - } else { | |
719 | - // String field | |
720 | - b3='$'; | |
721 | - } | |
722 | - if (g_source[g_srcpos-1]==')') { | |
723 | - // This is a CALL statement | |
724 | - return 0; | |
725 | - } | |
726 | - // $v1 is address to store value. Save it in stack. | |
727 | - check_obj_space(1); | |
728 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
729 | - g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
730 | - if (b3=='$') { | |
731 | - // String field | |
732 | - // Get value | |
733 | - next_position(); | |
734 | - if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
735 | - g_srcpos++; | |
736 | - err=get_string(); | |
737 | - } else if (b3=='#') { | |
738 | - // Float field | |
739 | - // Get value | |
740 | - next_position(); | |
741 | - if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
742 | - g_srcpos++; | |
743 | - err=get_float(); | |
744 | - } else { | |
745 | - // Integer field | |
746 | - // Get value | |
747 | - next_position(); | |
748 | - if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
749 | - g_srcpos++; | |
750 | - err=get_value(); | |
751 | - } | |
752 | - if (err) return err; | |
753 | - // Store in field of object | |
754 | - check_obj_space(4); | |
755 | - g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
756 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
757 | - g_object[g_objpos++]=0x8C640000; // lw a0,0(v1) | |
758 | - g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
759 | - // Handle permanent block for string field | |
760 | - if (b3=='$') call_quicklib_code(lib_let_str_field,ASM_ADDU_A1_V0_ZERO); | |
761 | - 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 | + resolve_unresolved(class); | |
99 | + // Delete some cmpdata. | |
100 | + delete_cmpdata_for_class(class); | |
101 | + return 0; | |
102 | +} | |
103 | + | |
104 | +void* search_method(int* classdata,int method){ | |
105 | + int pos,i; | |
106 | + int nums=classdata[1]; | |
107 | + | |
108 | + classdata+=2; // exclude first 2 words | |
109 | + classdata+=2*(nums&0xff); // exclude public field | |
110 | + classdata+=2*((nums>>8)&0xff); // exclude private field | |
111 | + nums=(nums>>16)&0xff; // number of methods | |
112 | + for(i=0;i<nums;i++){ | |
113 | + if (classdata[0]==method) return (void*)classdata[1]; | |
114 | + classdata+=2; | |
115 | + } | |
116 | + return 0; // not found | |
117 | +} | |
118 | + | |
119 | +char* resolve_unresolved(int class){ | |
120 | + int* classdata; | |
121 | + int* record; | |
122 | + int* code; | |
123 | + int i; | |
124 | + // Get class structure | |
125 | + cmpdata_reset(); | |
126 | + while(record=cmpdata_find(CMPDATA_CLASS)){ | |
127 | + if (record[1]==class) break; | |
128 | + } | |
129 | + if (!record) return ERR_UNKNOWN; | |
130 | + classdata=(int*)record[2]; | |
131 | + // Explore CMPDATA_UNSOLVED | |
132 | + cmpdata_reset(); | |
133 | + while(record=cmpdata_find(CMPDATA_UNSOLVED)){ | |
134 | + // Note: don't use cmpdata_find() again in the loop. | |
135 | + // If used, the solved CMPDATA_UNSOLVED must be removed before. | |
136 | + if (record[1]!=class) continue; | |
137 | + switch (record[0]&0xffff) { | |
138 | + case CMPTYPE_NEW_FUNCTION: | |
139 | + // Resolve address of code for pointer to class structure | |
140 | + code=(int*)record[2]; | |
141 | + code[0]=(code[0]&0xFFFF0000) | (((int)classdata)>>16); | |
142 | + code[1]=(code[1]&0xFFFF0000) | (((int)classdata) & 0x0000FFFF); | |
143 | + // Resolve size of object | |
144 | + code=(int*)record[3]; | |
145 | + code[0]=(code[0]&0xFFFF0000) | (object_size(classdata) & 0x0000FFFF); | |
146 | + // All done | |
147 | + break; | |
148 | + case CMPTYPE_STATIC_METHOD: | |
149 | + // Resolve address of code for pointer to method | |
150 | + // Find method | |
151 | + i=(int)search_method(classdata,record[2]); | |
152 | + if (!i) return ERR_NOT_FIELD; | |
153 | + code=(int*)record[3]; | |
154 | + code[0]=(code[0]&0xFC000000)|((i&0x0FFFFFFF)>>2); | |
155 | + // All done | |
156 | + break; | |
157 | + default: | |
158 | + return ERR_UNKNOWN; | |
159 | + } } | |
160 | + return 0; | |
161 | +} | |
162 | + | |
163 | +char* update_class_info(int class){ | |
164 | + int* record; | |
165 | + int data[2]; | |
166 | + // Update record if exist. | |
167 | + cmpdata_reset(); | |
168 | + while(record=cmpdata_find(CMPDATA_CLASS)){ | |
169 | + if (record[1]==class) { | |
170 | + record[2]=(int)g_class_structure; | |
171 | + return 0; | |
172 | + } | |
173 | + } | |
174 | + // No record of this class yet. Insert a record. | |
175 | + data[0]=class; | |
176 | + data[1]=(int)g_class_structure; | |
177 | + return cmpdata_insert(CMPDATA_CLASS,0,&data[0],2); | |
178 | +} | |
179 | + | |
180 | +/* | |
181 | + Class structure: | |
182 | + cstruct[0]: class name as integer | |
183 | + cstruct[1]: number of fields and methods: | |
184 | + bit 0-7: # of public fields | |
185 | + bit 8-15: # of private fields | |
186 | + bit 16-23: # of public methods | |
187 | + bit 24-31: reserved | |
188 | + cstruct[x]: public field name | |
189 | + cstruct[x+1]: public field var number | |
190 | + cstruct[y]: private field name | |
191 | + cstruct[y+1]: private field var number | |
192 | + cstruct[z]: public method name | |
193 | + cstruct[z+1]: public method pointer | |
194 | +*/ | |
195 | + | |
196 | +char* construct_class_structure(int class){ | |
197 | + int* record; | |
198 | + int i; | |
199 | + int num=0; | |
200 | + // Register current address to global var | |
201 | + g_class_structure=&g_object[g_objpos]; | |
202 | + // Construct a class structure in object area in following lines | |
203 | + // Class name | |
204 | + check_obj_space(2); | |
205 | + g_object[g_objpos++]=class; // Class name | |
206 | + g_objpos++; // Number of fields/methods | |
207 | + // Public fields | |
208 | + cmpdata_reset(); | |
209 | + while(record=cmpdata_find(CMPDATA_FIELD)){ | |
210 | + if ((record[0]&0xffff)==CMPTYPE_PUBLIC_FIELD) { | |
211 | + num+=1<<0; | |
212 | + check_obj_space(2); | |
213 | + g_object[g_objpos++]=record[1]; // Field name | |
214 | + g_objpos++; // Var number (see below) | |
215 | + } | |
216 | + } | |
217 | + // Private fields | |
218 | + cmpdata_reset(); | |
219 | + while(record=cmpdata_find(CMPDATA_FIELD)){ | |
220 | + if ((record[0]&0xffff)==CMPTYPE_PRIVATE_FIELD) { | |
221 | + num+=1<<8; | |
222 | + check_obj_space(2); | |
223 | + g_object[g_objpos++]=record[1]; // Field name | |
224 | + g_objpos++; // Var number (see below) | |
225 | + } | |
226 | + } | |
227 | + // Public methods | |
228 | + cmpdata_reset(); | |
229 | + while(record=cmpdata_find(CMPDATA_FIELD)){ | |
230 | + if ((record[0]&0xffff)==CMPTYPE_PUBLIC_METHOD) { | |
231 | + num+=1<<16; | |
232 | + check_obj_space(2); | |
233 | + g_object[g_objpos++]=record[1]; // Method name | |
234 | + g_object[g_objpos++]=record[2]; // pointer | |
235 | + } | |
236 | + } | |
237 | + // Update number info | |
238 | + g_class_structure[1]=num; | |
239 | + // Update var numbers of fields | |
240 | + num=((num>>8)&0xff)+(num&0xff); | |
241 | + for(i=1;i<=num;i++){ | |
242 | + if (( | |
243 | + g_class_structure[i*2+1]=search_var_name(0x7FFFFFFF & g_class_structure[i*2])+ALLOC_LNV_BLOCK | |
244 | + )<ALLOC_LNV_BLOCK) return ERR_UNKNOWN; | |
245 | + } | |
246 | + return 0; | |
247 | +} | |
248 | + | |
249 | +void delete_cmpdata_for_class(int class){ | |
250 | + int* record; | |
251 | + // Delete field/method data | |
252 | + cmpdata_reset(); | |
253 | + while(record=cmpdata_find(CMPDATA_FIELD)){ | |
254 | + cmpdata_delete(record); | |
255 | + cmpdata_reset(); | |
256 | + } | |
257 | + // Delete longvar data | |
258 | + cmpdata_reset(); | |
259 | + while(record=cmpdata_find(CMPDATA_USEVAR)){ | |
260 | + cmpdata_delete(record); | |
261 | + cmpdata_reset(); | |
262 | + } | |
263 | + // Delete solved class codes | |
264 | + cmpdata_reset(); | |
265 | + while(record=cmpdata_find(CMPDATA_UNSOLVED)){ | |
266 | + if (record[1]!=class) continue; | |
267 | + cmpdata_delete(record); | |
268 | + cmpdata_reset(); | |
269 | + } | |
270 | +} | |
271 | + | |
272 | +int object_size(int* classdata){ | |
273 | + int nums=classdata[1]; | |
274 | + int size=nums&0xff; // public field | |
275 | + size+=(nums>>8)&0xff; // private | |
276 | + // Add 1 for pointer to class data. | |
277 | + return size+1; | |
278 | +} | |
279 | + | |
280 | +char* new_function(){ | |
281 | + char* err; | |
282 | + int class,size; | |
283 | + int i,stack, opos; | |
284 | + int* data; | |
285 | + int* classdata; | |
286 | + int record[3]; | |
287 | + void* init_method; | |
288 | + // Resolve class name | |
289 | + err=get_label(); | |
290 | + if (err) return err; | |
291 | + if (!g_label) return ERR_SYNTAX; | |
292 | + class=g_label; | |
293 | + record[0]=class; | |
294 | + next_position(); | |
295 | + // Get class data from cmpdata | |
296 | + // Note that the address of class structure can be resolved | |
297 | + // by using cmpdata when compiling NEW function but not running. | |
298 | + // Therefore, class table is not requred when running. | |
299 | + cmpdata_reset(); | |
300 | + while(data=cmpdata_find(CMPDATA_CLASS)){ | |
301 | + if (data[1]==class) break; | |
302 | + } | |
303 | + if (!data) return ERR_NO_CLASS; | |
304 | + classdata=(int*)data[2]; | |
305 | + if (classdata) { | |
306 | + size=object_size(classdata); | |
307 | + } else { | |
308 | + // Class structure is unsolved. | |
309 | + size=0; | |
310 | + } | |
311 | + // Create object | |
312 | + record[2]=(int)&g_object[g_objpos+3]; | |
313 | + call_quicklib_code(lib_calloc_memory,ASM_ORI_A0_ZERO_|size); | |
314 | + // First word of object is pointer to classdata | |
315 | + check_obj_space(3); | |
316 | + record[1]=(int)&g_object[g_objpos]; | |
317 | + g_object[g_objpos++]=0x3C080000|(((unsigned int)classdata)>>16); // lui t0,xxxx | |
318 | + g_object[g_objpos++]=0x35080000|(((unsigned int)classdata)&0x0000FFFF); // ori t0,t0,xxxx | |
319 | + g_object[g_objpos++]=0xAC480000; // sw t0,0(v0) | |
320 | + // Check if INIT method exists | |
321 | + if (classdata) { | |
322 | + init_method=search_method(classdata,LABEL_INIT); | |
323 | + } else { | |
324 | + // Class structure is unknown. Use null method. | |
325 | + init_method=(int*)&g_return_code[0]; | |
326 | + // Register CMPDATA | |
327 | + cmpdata_insert(CMPDATA_UNSOLVED,CMPTYPE_NEW_FUNCTION,(int*)record[0],3); | |
328 | + } | |
329 | + if (!init_method) { | |
330 | + // All done | |
331 | + // Note that $v0 is address of object here. | |
332 | + // There should not be parameter(s). | |
333 | + if (g_source[g_srcpos]==',') return ERR_NO_INIT; | |
334 | + return 0; | |
335 | + } | |
336 | + // INIT method exists. Note that $v0 is address of object here. | |
337 | + if (g_source[g_srcpos]==',') g_srcpos++; | |
338 | + else if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
339 | + check_obj_space(2); | |
340 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
341 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
342 | + err=obj_method(LABEL_INIT); | |
343 | + if (err) return err; | |
344 | + g_srcpos--; // Leave ')' character for detecting end of "new" function | |
345 | + check_obj_space(2); | |
346 | + g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp) | |
347 | + g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4 | |
348 | + // All done | |
349 | + // Note that $v0 is address of object here. | |
350 | + return 0; | |
351 | +} | |
352 | + | |
353 | +char* field_statement(){ | |
354 | + char* err; | |
355 | + int i; | |
356 | + int data[1]; | |
357 | + int is_private=0; | |
358 | + // This statement is valid only in class file. | |
359 | + if (!g_compiling_class) return ERR_INVALID_NON_CLASS; | |
360 | + // Check which private or public | |
361 | + next_position(); | |
362 | + if (nextCodeIs("PRIVATE ")) { | |
363 | + is_private=1; | |
364 | + } else if (nextCodeIs("PUBLIC ")) { | |
365 | + is_private=0; | |
366 | + } | |
367 | + do { | |
368 | + next_position(); | |
369 | + i=check_var_name(); | |
370 | + if (i<65536) return ERR_SYNTAX; | |
371 | + // Register varname | |
372 | + err=register_var_name(i); | |
373 | + if (err) return err; | |
374 | + if (g_source[g_srcpos]=='#') { | |
375 | + g_srcpos++; | |
376 | + } else if (g_source[g_srcpos]=='$') { | |
377 | + // String field. Raise 31st bit. | |
378 | + g_srcpos++; | |
379 | + i|=0x80000000; | |
380 | + } else if (g_source[g_srcpos]=='(' && g_source[g_srcpos+1]==')' && is_private) { | |
381 | + // Dimension field (private only). Raise 31st bit. | |
382 | + g_srcpos++; | |
383 | + g_srcpos++; | |
384 | + i|=0x80000000; | |
385 | + } | |
386 | + // Register field | |
387 | + data[0]=i; | |
388 | + if (is_private) { | |
389 | + err=cmpdata_insert(CMPDATA_FIELD,CMPTYPE_PRIVATE_FIELD,(int*)&data[0],1); | |
390 | + } else { | |
391 | + err=cmpdata_insert(CMPDATA_FIELD,CMPTYPE_PUBLIC_FIELD,(int*)&data[0],1); | |
392 | + } | |
393 | + next_position(); | |
394 | + if (g_source[g_srcpos]==',') { | |
395 | + g_srcpos++; | |
396 | + } else { | |
397 | + break; | |
398 | + } | |
399 | + } while(1); | |
400 | + return 0; | |
401 | +} | |
402 | + | |
403 | +/* | |
404 | + char* obj_method(int method); | |
405 | + Implementation of access to method of object. | |
406 | +*/ | |
407 | +char* obj_method(int method){ | |
408 | + // $v0 contains the address of object. | |
409 | + char* err; | |
410 | + int stack,opos; | |
411 | + // Parameters preparation (to $s5) here. | |
412 | + next_position(); | |
413 | + opos=g_objpos; | |
414 | + // Begin parameter(s) construction routine | |
415 | + err=prepare_args_stack('('); | |
416 | + if (err) return err; | |
417 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
418 | + g_srcpos++; | |
419 | + // Determine address of method and store fields to local variables. | |
420 | + check_obj_space(3); | |
421 | + g_object[g_objpos++]=0x8FA20000|ARGS_SP_V0_OBJ; // lw v0,8(sp) | |
422 | + g_object[g_objpos++]=0x3C050000|((method>>16)&0x0000FFFF); // lui a1,xxxx | |
423 | + g_object[g_objpos++]=0x34A50000|(method&0x0000FFFF); // ori a1,a1,xxxx | |
424 | + call_quicklib_code(lib_pre_method,ASM_ADDU_A0_V0_ZERO); | |
425 | + // Call method address here. Same routine for GOSUB statement with integer value is used. | |
426 | + check_obj_space(6); | |
427 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
428 | + g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
429 | + g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5) | |
430 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
431 | + g_object[g_objpos++]=0x00000000; // nop | |
432 | + // label1: | |
433 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
434 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) // label2: | |
435 | + // Restore fields from local variables. | |
436 | + check_obj_space(3); | |
437 | + g_object[g_objpos++]=0x8FA40008; // lw a0,8(sp) | |
438 | + call_quicklib_code(lib_post_method,ASM_ADDU_A1_V0_ZERO); | |
439 | + // Remove stack | |
440 | + err=remove_args_stack(); | |
441 | + if (err) return err; | |
442 | + return 0; | |
443 | +} | |
444 | + | |
445 | +/* | |
446 | + char* integer_obj_field(); | |
447 | + char* string_obj_field(); | |
448 | + char* float_obj_field(); | |
449 | + Implementation of access to field of object. | |
450 | + This feature is recursive. When an object is applied to the field of another object, | |
451 | + following expression is possible (for example): | |
452 | + obj1.field1.field2 | |
453 | + | |
454 | +*/ | |
455 | + | |
456 | +#define OBJ_FIELD_INTEGER 0 | |
457 | +#define OBJ_FIELD_STRING '$' | |
458 | +#define OBJ_FIELD_FLOAT '#' | |
459 | + | |
460 | +char* _obj_field(char mode){ | |
461 | + // $v0 contains the address of object. | |
462 | + int i; | |
463 | + char* err; | |
464 | + do { | |
465 | + i=check_var_name(); | |
466 | + if (i<65536) return ERR_SYNTAX; | |
467 | + if (g_source[g_srcpos]=='(' && mode==OBJ_FIELD_INTEGER) { | |
468 | + // This is a method | |
469 | + return obj_method(i); | |
470 | + } else if (g_source[g_srcpos+1]=='(') { | |
471 | + if (g_source[g_srcpos]==mode) { | |
472 | + // This is a string/float method | |
473 | + g_srcpos++; | |
474 | + return obj_method(i); | |
475 | + } | |
476 | + } else if (g_source[g_srcpos]==mode && mode==OBJ_FIELD_STRING) { | |
477 | + // This is a string field. Raise 31st bit. | |
478 | + i|=0x80000000; | |
479 | + } | |
480 | + check_obj_space(2); | |
481 | + g_object[g_objpos++]=0x3C050000|((i>>16)&0x0000FFFF); // lui a1,xxxx | |
482 | + g_object[g_objpos++]=0x34A50000|(i&0x0000FFFF); // ori a1,a1,xxxx | |
483 | + // First and second arguments are address of object and field name, respectively. | |
484 | + call_quicklib_code(lib_obj_field,ASM_ADDU_A0_V0_ZERO); | |
485 | + // Check if "." follows | |
486 | + if (g_source[g_srcpos]=='.') { | |
487 | + // "." found. $v0 is adress of an object. See the field. | |
488 | + g_srcpos++; | |
489 | + continue; | |
490 | + } | |
491 | + } while(0); | |
492 | + // All done. Check variable type | |
493 | + if (mode==OBJ_FIELD_INTEGER) return 0; | |
494 | + else if (g_source[g_srcpos]==mode) { | |
495 | + g_srcpos++; | |
496 | + return 0; | |
497 | + } else return ERR_SYNTAX; | |
498 | +} | |
499 | + | |
500 | +char* integer_obj_field(){ | |
501 | + return _obj_field(OBJ_FIELD_INTEGER); | |
502 | +} | |
503 | + | |
504 | +char* string_obj_field(){ | |
505 | + return _obj_field(OBJ_FIELD_STRING); | |
506 | +} | |
507 | + | |
508 | +char* float_obj_field(){ | |
509 | + return _obj_field(OBJ_FIELD_FLOAT); | |
510 | +} | |
511 | + | |
512 | +int lib_obj_field(int* object, int fieldname){ | |
513 | + int* class; | |
514 | + int i,numfield; | |
515 | + // Check if this is an object (if within the RAM). | |
516 | + if (!withinRAM(object)) err_not_obj(); | |
517 | + class=(int*)object[0]; | |
518 | + if (!withinRAM(class)) err_not_obj(); | |
519 | + // Obtain # of public field | |
520 | + numfield=class[1]&0xff; | |
521 | + for(i=0;i<numfield;i++){ | |
522 | + if (class[2+i*2]==fieldname) break; | |
523 | + } | |
524 | + if (i==numfield) err_not_field(fieldname,class[0]); | |
525 | + // Got address of field. Return value as $v0 and address as $v1. | |
526 | + g_temp=(int)(&object[1+i]); | |
527 | + asm volatile("la $v1,%0"::"i"(&g_temp)); | |
528 | + asm volatile("lw $v1,0($v1)"); | |
529 | + return object[1+i]; | |
530 | +} | |
531 | + | |
532 | +/* | |
533 | + Library for letting string field | |
534 | +*/ | |
535 | + | |
536 | +void lib_let_str_field(char* prev_str, char* new_str){ | |
537 | + int var_num=get_permanent_var_num(); | |
538 | + free_perm_str(prev_str); | |
539 | + lib_let_str(new_str,var_num); | |
540 | + return; | |
541 | +} | |
542 | + | |
543 | +/* | |
544 | + Library for calling method statement | |
545 | +*/ | |
546 | + | |
547 | +int lib_pre_method(int* object, int methodname){ | |
548 | + int i,num,nums; | |
549 | + int* class; | |
550 | + // Check if this is an object (if within the RAM). | |
551 | + if (!withinRAM(object)) err_not_obj(); | |
552 | + class=(int*)object[0]; | |
553 | + if (!withinRAM(class)) err_not_obj(); | |
554 | + // Save object field values in local variables in class | |
555 | + nums=class[1]; | |
556 | + num=nums&0xff; | |
557 | + for(i=0;i<num;i++){ | |
558 | + // Public fields | |
559 | + class+=2; | |
560 | + g_var_mem[class[1]]=object[i+1]; | |
561 | + // When string, move from permanent block | |
562 | + if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]); | |
563 | + } | |
564 | + num+=(nums>>8)&0xff; | |
565 | + for(i=i;i<num;i++){ | |
566 | + // Private fields | |
567 | + class+=2; | |
568 | + g_var_mem[class[1]]=object[i+1]; | |
569 | + // When string/dimension, move from permanent block | |
570 | + if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]); | |
571 | + } | |
572 | + // Seek method | |
573 | + num+=(nums>>16)&0xff; | |
574 | + for(i=i;i<num;i++){ | |
575 | + class+=2; | |
576 | + if (class[0]==methodname) break; | |
577 | + } | |
578 | + if (i==num) { | |
579 | + // Method not found | |
580 | + if (methodname==LABEL_INIT) { | |
581 | + // INIT method not found | |
582 | + // Call null function | |
583 | + return (int)(&g_return_code[0]); | |
584 | + } else { | |
585 | + class=(int*)object[0]; | |
586 | + err_not_field(methodname,class[0]); | |
587 | + } | |
588 | + } | |
589 | + // Method found. return it. | |
590 | + return class[1]; | |
591 | +} | |
592 | + | |
593 | +int lib_post_method(int* object, int v0){ | |
594 | + // Note that v0 (a1) contains the return value from a method. | |
595 | + int i,num,nums; | |
596 | + int* class; | |
597 | + // Restore local variables to object field values | |
598 | + class=(int*)object[0]; | |
599 | + nums=class[1]; | |
600 | + num=nums&0xff; | |
601 | + for(i=0;i<num;i++){ | |
602 | + // Public fields | |
603 | + class+=2; | |
604 | + object[i+1]=g_var_mem[class[1]]; | |
605 | + // When string, move to permanent block | |
606 | + if (0x80000000&class[0]) { | |
607 | + if (g_var_size[class[1]]) move_to_perm_block(class[1]); | |
608 | + } | |
609 | + } | |
610 | + num+=(nums>>8)&0xff; | |
611 | + for(i=i;i<num;i++){ | |
612 | + // Private fields | |
613 | + class+=2; | |
614 | + object[i+1]=g_var_mem[class[1]]; | |
615 | + // When string/dimension, move to permanent block | |
616 | + if (0x80000000&class[0]) { | |
617 | + if (g_var_size[class[1]]) move_to_perm_block(class[1]); | |
618 | + } | |
619 | + } | |
620 | + // all done | |
621 | + return v0; | |
622 | +} | |
623 | + | |
624 | +/* | |
625 | + Method statement | |
626 | +*/ | |
627 | + | |
628 | +char* method_statement(){ | |
629 | + char* err; | |
630 | + int data[2]; | |
631 | + int opos=g_objpos; | |
632 | + // This statement is valid only in class file. | |
633 | + if (!g_compiling_class) return ERR_INVALID_NON_CLASS; | |
634 | + // Insert label for setting $s6 | |
635 | + err=label_statement(); | |
636 | + if (err) return err; | |
637 | + // Register cmpdata | |
638 | + data[0]=g_label; | |
639 | + data[1]=(int)(&g_object[opos]); | |
640 | + return cmpdata_insert(CMPDATA_FIELD,CMPTYPE_PUBLIC_METHOD,(int*)&data[0],2); | |
641 | +} | |
642 | + | |
643 | +/* | |
644 | + Delete statement | |
645 | +*/ | |
646 | + | |
647 | +char* delete_statement(){ | |
648 | + char* err; | |
649 | + next_position(); | |
650 | + g_srcpos--; | |
651 | + do{ | |
652 | + g_srcpos++; | |
653 | + err=get_value(); | |
654 | + if (err) return err; | |
655 | + call_quicklib_code(lib_delete,ASM_ADDU_A0_V0_ZERO); | |
656 | + next_position(); | |
657 | + } while (g_source[g_srcpos]==','); | |
658 | + return 0; | |
659 | +} | |
660 | + | |
661 | +/* | |
662 | + Call statement | |
663 | +*/ | |
664 | + | |
665 | +char* call_statement(){ | |
666 | + // Just get an integer value. That is it. | |
667 | + return get_value(); | |
668 | +} | |
669 | + | |
670 | +/* | |
671 | + Static statement | |
672 | +*/ | |
673 | + | |
674 | +char* static_statement(){ | |
675 | + char* err; | |
676 | + int* record; | |
677 | + int data[2]; | |
678 | + int i; | |
679 | + int is_private=0; | |
680 | + // This statement is valid only in class file. | |
681 | + if (!g_compiling_class) return ERR_INVALID_NON_CLASS; | |
682 | + // Check which private or public | |
683 | + next_position(); | |
684 | + if (nextCodeIs("PRIVATE ")) { | |
685 | + is_private=1; | |
686 | + } else if (nextCodeIs("PUBLIC ")) { | |
687 | + is_private=0; | |
688 | + } | |
689 | + do { | |
690 | + next_position(); | |
691 | + i=check_var_name(); | |
692 | + if (i<65536) return ERR_SYNTAX; | |
693 | + if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') { | |
694 | + g_srcpos++; | |
695 | + } | |
696 | + // Register public static field | |
697 | + if (is_private) { | |
698 | + // This is the same as USEVAR | |
699 | + // Register varname | |
700 | + err=register_var_name(i); | |
701 | + if (err) return err; | |
702 | + } else { | |
703 | + // Check if there is already a CMPDATA record | |
704 | + cmpdata_reset(); | |
705 | + while(record=cmpdata_find(CMPDATA_STATIC)){ | |
706 | + if (record[1]!=g_compiling_class) continue; | |
707 | + if (record[2]!=i) continue; | |
708 | + break; | |
709 | + } | |
710 | + if (record) { | |
711 | + // There is already a record. | |
712 | + // Do not allocate new number but use the registered number; | |
713 | + i=record[0]&0xffff; | |
714 | + err=cmpdata_insert(CMPDATA_USEVAR,i,&record[2],1); | |
715 | + if (err) return err; | |
716 | + } else { | |
717 | + // Register varname | |
718 | + err=register_var_name(i); | |
719 | + if (err) return err; | |
720 | + // Insert a CMDATA_STATIC record | |
721 | + data[0]=g_compiling_class; // class name as integer | |
722 | + data[1]=i; // static var name as integer | |
723 | + i=search_var_name(i); // var number of this static field | |
724 | + if (i<0) return ERR_UNKNOWN; | |
725 | + err=cmpdata_insert(CMPDATA_STATIC,i,(int*)&data[0],2); | |
726 | + if (err) return err; | |
727 | + } | |
728 | + } | |
729 | + next_position(); | |
730 | + if (g_source[g_srcpos]==',') { | |
731 | + g_srcpos++; | |
732 | + } else { | |
733 | + break; | |
734 | + } | |
735 | + } while(1); | |
736 | + return 0; | |
737 | + | |
738 | +} | |
739 | + | |
740 | +/* | |
741 | + Static method | |
742 | + Type is either 0, '$', or '#', | |
743 | + for integer, string, or float | |
744 | +*/ | |
745 | + | |
746 | +char* static_method(char type){ | |
747 | + char* err; | |
748 | + int* data; | |
749 | + int record[3]; | |
750 | + int i,opos,method,stack; | |
751 | + next_position(); | |
752 | + // Check class name | |
753 | + i=check_var_name(); | |
754 | + if (i<65536) return ERR_SYNTAX; | |
755 | + // Check if the class exists | |
756 | + cmpdata_reset(); | |
757 | + while(data=cmpdata_find(CMPDATA_CLASS)){ | |
758 | + if (data[1]==i) { | |
759 | + // The class was already defined. | |
760 | + i=0; | |
761 | + break; | |
762 | + } | |
763 | + } | |
764 | + record[0]=i; | |
765 | + // Check '::' | |
766 | + if (g_source[g_srcpos]!=':') return ERR_SYNTAX; | |
767 | + g_srcpos++; | |
768 | + if (g_source[g_srcpos]!=':') return ERR_SYNTAX; | |
769 | + g_srcpos++; | |
770 | + if (i) return ERR_NO_CLASS; | |
771 | + data=(int*)data[2]; | |
772 | + // Check method | |
773 | + i=check_var_name(); | |
774 | + if (i<65536) return ERR_SYNTAX; | |
775 | + if (data) { | |
776 | + method=(int)search_method(data,i); | |
777 | + if (!method) return ERR_NOT_FIELD; | |
778 | + } else { | |
779 | + method=(int)&g_return_code[0]; | |
780 | + record[1]=i; | |
781 | + } | |
782 | + // Check type and '(' | |
783 | + if (type) {// Either 0, '$', or '#' | |
784 | + if (g_source[g_srcpos]!=type) return ERR_SYNTAX; | |
785 | + g_srcpos++; | |
786 | + | |
787 | + } | |
788 | + if (g_source[g_srcpos]!='(') return ERR_SYNTAX; | |
789 | + // Begin parameter(s) construction routine | |
790 | + check_obj_space(1); | |
791 | + g_object[g_objpos++]=0x34020000; // ori v0,zero,0 | |
792 | + err=prepare_args_stack('('); | |
793 | + if (err) return err; | |
794 | + // Calling subroutine, which is static method of class | |
795 | + record[2]=(int)&g_object[g_objpos+5]; | |
796 | + check_obj_space(7); | |
797 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
798 | + g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
799 | + g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5) | |
800 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
801 | + g_object[g_objpos++]=0x00000000; // nop | |
802 | + // label1: | |
803 | + g_object[g_objpos++]=0x08000000|((method&0x0FFFFFFF)>>2); // j xxxx | |
804 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
805 | + // label2: | |
806 | + // Register CMPDATA if required. | |
807 | + if (!data) { | |
808 | + cmpdata_insert(CMPDATA_UNSOLVED,CMPTYPE_STATIC_METHOD,(int*)record[0],3); | |
809 | + } | |
810 | + // Remove stack | |
811 | + err=remove_args_stack(); | |
812 | + if (err) return err; | |
813 | + return 0; | |
814 | +} | |
815 | + | |
816 | +/* | |
817 | + Let object.field statement | |
818 | +*/ | |
819 | + | |
820 | +char* let_object_field(){ | |
821 | + char* err; | |
822 | + char b3; | |
823 | + int spos,opos; | |
824 | + // $v0 contains the pointer to object | |
825 | + spos=g_srcpos; | |
826 | + opos=g_objpos; | |
827 | + // Try string field, first | |
828 | + err=string_obj_field(); | |
829 | + if (err) { | |
830 | + // Integer or float field | |
831 | + g_srcpos=spos; | |
832 | + g_objpos=opos; | |
833 | + err=integer_obj_field(); | |
834 | + if (err) return err; | |
835 | + b3=g_source[g_srcpos]; | |
836 | + if (b3=='#') g_srcpos++; | |
837 | + } else { | |
838 | + // String field | |
839 | + b3='$'; | |
840 | + } | |
841 | + if (g_source[g_srcpos-1]==')') { | |
842 | + // This is a CALL statement | |
843 | + return 0; | |
844 | + } | |
845 | + // $v1 is address to store value. Save it in stack. | |
846 | + check_obj_space(1); | |
847 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
848 | + g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
849 | + if (b3=='$') { | |
850 | + // String field | |
851 | + // Get value | |
852 | + next_position(); | |
853 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
854 | + g_srcpos++; | |
855 | + err=get_string(); | |
856 | + } else if (b3=='#') { | |
857 | + // Float field | |
858 | + // Get value | |
859 | + next_position(); | |
860 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
861 | + g_srcpos++; | |
862 | + err=get_float(); | |
863 | + } else { | |
864 | + // Integer field | |
865 | + // Get value | |
866 | + next_position(); | |
867 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
868 | + g_srcpos++; | |
869 | + err=get_value(); | |
870 | + } | |
871 | + if (err) return err; | |
872 | + // Store in field of object | |
873 | + check_obj_space(4); | |
874 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
875 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
876 | + g_object[g_objpos++]=0x8C640000; // lw a0,0(v1) | |
877 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
878 | + // Handle permanent block for string field | |
879 | + if (b3=='$') call_quicklib_code(lib_let_str_field,ASM_ADDU_A1_V0_ZERO); | |
880 | + return 0; | |
762 | 881 | } |
\ No newline at end of file |
@@ -103,6 +103,11 @@ NEW(x[,y[,z[, ... ]]]) | ||
103 | 103 | クターは実装していませんので、必要ならば、それ用のメソッドを作成して破棄する直前に |
104 | 104 | 呼び出して下さい。 |
105 | 105 | |
106 | +オブジェクトのフィールドに文字列もしくは配列を用いている場合、オブジェクトを | |
107 | +DELETEするだけではこれらの領域は破棄されません。その場合、まずメソッド内でこれら | |
108 | +のフィールドを破棄(DELETE命令が使えます)してから、オブジェクトを破棄するようにし | |
109 | +て下さい。 | |
110 | + | |
106 | 111 | 記述例: |
107 | 112 | USECLASS CLASS1 |
108 | 113 | A=NEW(CLASS1) |
@@ -333,7 +333,7 @@ char* register_var_name(int nameint); | ||
333 | 333 | |
334 | 334 | char* update_class_info(int class); |
335 | 335 | char* construct_class_structure(int class); |
336 | -void delete_cmpdata_for_class(); | |
336 | +void delete_cmpdata_for_class(int class); | |
337 | 337 | |
338 | 338 | extern const unsigned int g_initial_s5_stack[3]; |
339 | 339 | char* prepare_args_stack(char start_char); |
@@ -357,6 +357,7 @@ void lib_let_str_field(char* str, char* prev_str); | ||
357 | 357 | char* let_object_field(); |
358 | 358 | char* static_statement(); |
359 | 359 | char* static_method(char type); |
360 | +char* resolve_unresolved(int class); | |
360 | 361 | |
361 | 362 | /* Error messages */ |
362 | 363 | #define ERR_SYNTAX (char*)(g_err_str[0]) |
@@ -395,6 +396,14 @@ char* static_method(char type); | ||
395 | 396 | #define CMPDATA_CLASS 2 |
396 | 397 | #define CMPDATA_FIELD 3 |
397 | 398 | #define CMPDATA_STATIC 4 |
399 | +#define CMPDATA_UNSOLVED 5 | |
400 | +// Sub types follow | |
401 | +#define CMPTYPE_PUBLIC_FIELD 0 | |
402 | +#define CMPTYPE_PRIVATE_FIELD 1 | |
403 | +#define CMPTYPE_PUBLIC_METHOD 2 | |
404 | +#define CMPTYPE_NEW_FUNCTION 0 | |
405 | +#define CMPTYPE_STATIC_METHOD 1 | |
406 | + | |
398 | 407 | |
399 | 408 | /* Stack position for values in args.c */ |
400 | 409 | #define ARGS_SP_SP 4 |