• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

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

BASIC compiler/interpreter for PIC32MX/MZ-80K


Commit MetaInfo

Revisionfa324cd371259c174345975f86a3a42b551b0506 (tree)
Time2019-02-06 06:00:48
AuthorKatsumi <kmorimatsu@sour...>
CommiterKatsumi

Log Message

Support recursive class/object structure.

Change Summary

Incremental Difference

--- a/mips/megalopa/class.c
+++ b/mips/megalopa/class.c
@@ -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;
762881 }
\ No newline at end of file
--- a/mips/megalopa/class.txt
+++ b/mips/megalopa/class.txt
@@ -103,6 +103,11 @@ NEW(x[,y[,z[, ... ]]])
103103 クターは実装していませんので、必要ならば、それ用のメソッドを作成して破棄する直前に
104104 呼び出して下さい。
105105
106+オブジェクトのフィールドに文字列もしくは配列を用いている場合、オブジェクトを
107+DELETEするだけではこれらの領域は破棄されません。その場合、まずメソッド内でこれら
108+のフィールドを破棄(DELETE命令が使えます)してから、オブジェクトを破棄するようにし
109+て下さい。
110+
106111 記述例:
107112  USECLASS CLASS1
108113  A=NEW(CLASS1)
--- a/mips/megalopa/compiler.h
+++ b/mips/megalopa/compiler.h
@@ -333,7 +333,7 @@ char* register_var_name(int nameint);
333333
334334 char* update_class_info(int class);
335335 char* construct_class_structure(int class);
336-void delete_cmpdata_for_class();
336+void delete_cmpdata_for_class(int class);
337337
338338 extern const unsigned int g_initial_s5_stack[3];
339339 char* prepare_args_stack(char start_char);
@@ -357,6 +357,7 @@ void lib_let_str_field(char* str, char* prev_str);
357357 char* let_object_field();
358358 char* static_statement();
359359 char* static_method(char type);
360+char* resolve_unresolved(int class);
360361
361362 /* Error messages */
362363 #define ERR_SYNTAX (char*)(g_err_str[0])
@@ -395,6 +396,14 @@ char* static_method(char type);
395396 #define CMPDATA_CLASS 2
396397 #define CMPDATA_FIELD 3
397398 #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+
398407
399408 /* Stack position for values in args.c */
400409 #define ARGS_SP_SP 4