Revision | 37 (tree) |
---|---|
Zeit | 2019-03-18 00:10:49 |
Autor | kenkenmkiisr |
オブジェクト指向対応
@@ -0,0 +1,106 @@ | ||
1 | +/* | |
2 | + This file is provided under the LGPL license ver 2.1. | |
3 | + Written by Katsumi. | |
4 | + http://hp.vector.co.jp/authors/VA016157/ | |
5 | + kmorimatsu@users.sourceforge.jp | |
6 | +*/ | |
7 | + | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
12 | +#include "compiler.h" | |
13 | + | |
14 | +const unsigned int g_initial_s5_stack[3]={ | |
15 | + 0, // -8($s5): no object | |
16 | + (unsigned int) &g_initial_s5_stack[2], // -4($s5): previous $s5 (recursive) | |
17 | + 0 // 0($s5): no parameter | |
18 | +}; | |
19 | + | |
20 | +static int g_args_stack; | |
21 | +/* | |
22 | + See ARGS_SP_XXXX and ARGS_S5_XXXX in compiler.h | |
23 | + At least 4 stacks are needed even without argument | |
24 | + 4($sp) = -12($s5): $sp | |
25 | + 8($sp) = -8($s5): $v0 - pointer to object or previous -8($s5) | |
26 | + 12($sp) = -4($s5): previous $s5 | |
27 | + 16($sp) = 0($s5): number of arguments | |
28 | + 20($sp) = 4($s5): first argument | |
29 | + $v0 must be the pointer to an object before comming to this code. | |
30 | + After this code, -12($s5) must be set to $sp: 0xAEBDFFF4 sw sp,-12(s5) | |
31 | +*/ | |
32 | +char* prepare_args_stack(char start_char){ | |
33 | + // start_char is either ',' or '(' | |
34 | + // When ',' mode, there must be a ',' if argument(s) exist(s). | |
35 | + // When '(' mode, there shouldn't be a '(', because this character has passed. | |
36 | + char* err; | |
37 | + int opos,stack; | |
38 | + stack=0; | |
39 | + opos=g_objpos; | |
40 | + check_obj_space(2); | |
41 | + g_object[g_objpos++]=0x27BD0000; // addiu sp,sp,-xx | |
42 | + // 8(sp) is for $v0, which is pointer to an object | |
43 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
44 | + next_position(); | |
45 | + do { | |
46 | + if (!stack) { | |
47 | + // First parameter if exists | |
48 | + stack=16; | |
49 | + if (start_char==','){ | |
50 | + if (g_source[g_srcpos]!=',') break; | |
51 | + } else if (start_char=='('){ | |
52 | + next_position(); | |
53 | + if (g_source[g_srcpos]==')') break; | |
54 | + g_srcpos--; | |
55 | + } else { | |
56 | + return ERR_UNKNOWN; | |
57 | + } | |
58 | + } | |
59 | + g_srcpos++; | |
60 | + stack+=4; | |
61 | + err=get_stringFloatOrValue(); | |
62 | + if (err) return err; | |
63 | + check_obj_space(1); | |
64 | + g_object[g_objpos++]=0xAFA20000|stack; // sw v0,xx(sp) | |
65 | + next_position(); | |
66 | + } while (g_source[g_srcpos]==','); | |
67 | + // 12(sp) is for $s5, 16(sp) is for # of parameters | |
68 | + check_obj_space(5); | |
69 | + g_object[g_objpos++]=0xAFB5000C; // sw s5,12(sp) | |
70 | + g_object[g_objpos++]=0x34020000|(stack/4-4); // ori v0,zero,xx | |
71 | + g_object[g_objpos++]=0xAFA20010; // sw v0,16(sp) | |
72 | + g_object[g_objpos++]=0x27B50010; // addiu s5,sp,16 | |
73 | + g_object[opos]|=((0-stack)&0xFFFF); // addiu sp,sp,-xx (See above) | |
74 | + // All done. Register # of stacks to global var. | |
75 | + g_args_stack=stack; | |
76 | + return 0; | |
77 | +} | |
78 | + | |
79 | +char* remove_args_stack(void){ | |
80 | + // Remove stack | |
81 | + check_obj_space(2); | |
82 | + g_object[g_objpos++]=0x8FB5000C; // lw s5,12(sp) | |
83 | + g_object[g_objpos++]=0x27BD0000|g_args_stack; // addiu sp,sp,xx | |
84 | + return 0; | |
85 | +} | |
86 | + | |
87 | +char* args_function_main(void){ | |
88 | + char* err; | |
89 | + int i; | |
90 | + err=get_value(); | |
91 | + if (err) return err; | |
92 | + i=g_object[g_objpos-1]; | |
93 | + if ((i>>16)==0x3402) { | |
94 | + // Previous object is "ori v0,zero,xxxx". | |
95 | + i&=0xffff; | |
96 | + i=i<<2; | |
97 | + g_object[g_objpos-1]=0x8EA20000|i; // lw v0,xx(s5) | |
98 | + } else { | |
99 | + check_obj_space(3); | |
100 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
101 | + g_object[g_objpos++]=0x02A21021; // addu v0,s5,v0 | |
102 | + g_object[g_objpos++]=0x8C420000; // lw v0,0(v0) | |
103 | + } | |
104 | + return 0; | |
105 | +} | |
106 | + |
@@ -0,0 +1,922 @@ | ||
1 | +/* | |
2 | + This file is provided under the LGPL license ver 2.1. | |
3 | + Written by K.Tanaka & Katsumi | |
4 | + http://www.ze.em-net.ne.jp/~kenken/index.html | |
5 | + http://hp.vector.co.jp/authors/VA016157/ | |
6 | +*/ | |
7 | + | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
12 | +#include "compiler.h" | |
13 | + | |
14 | +static int* g_class_structure; | |
15 | + | |
16 | +/* | |
17 | + CMPDATA_CLASS structure | |
18 | + type: CMPDATA_CLASS (2) | |
19 | + len: 3 | |
20 | + data16: n/a (0) | |
21 | + record[1]: class name as integer | |
22 | + record[2]: pointer to class structure | |
23 | +*/ | |
24 | + | |
25 | +/* | |
26 | + CMPDATA_FIELD structure | |
27 | + type: CMPDATA_FIELD (3) | |
28 | + len: 2 or 3 (2: field; 3: method) | |
29 | + data16: field or method | |
30 | + CMPTYPE_PUBLIC_FIELD: 0 | |
31 | + CMPTYPE_PRIVATE_FIELD: 1 | |
32 | + CMPTYPE_PUBLIC_METHOD: 2 | |
33 | + record[1]: field/method name as integer | |
34 | + record[2]: pointer to method | |
35 | +*/ | |
36 | + | |
37 | +/* | |
38 | + CMPDATA_STATIC structure | |
39 | + type: CMPDATA_STATIC (4) | |
40 | + len: 3 | |
41 | + data16: variable number; add ALLOC_LNV_BLOCK when using | |
42 | + record[1]: class name as integer | |
43 | + record[2]: variable name as integer | |
44 | +*/ | |
45 | + | |
46 | +/* | |
47 | + CMPDATA_UNSOLVED structure | |
48 | + type: CMPDATA_UNSOLVED (5) | |
49 | + len: 4 | |
50 | + data16: CMPTYPE_NEW_FUNCTION (0) | |
51 | + record[1]: class name as integer | |
52 | + record[2]: address of code for pointer to class structure | |
53 | + record[3]: address of code for size definition | |
54 | + | |
55 | + type: CMPDATA_UNSOLVED (5) | |
56 | + len: 4 | |
57 | + data16: CMPTYPE_STATIC_METHOD (1) | |
58 | + record[1]: class name as integer | |
59 | + record[2]: method name as integer | |
60 | + record[3]: address of code for pointer to method | |
61 | + | |
62 | +*/ | |
63 | + | |
64 | +/* | |
65 | + Local prototyping | |
66 | +*/ | |
67 | +char* obj_method(int method); | |
68 | + | |
69 | +/* | |
70 | + Return code used for calling null method | |
71 | +*/ | |
72 | +static const unsigned int g_return_code[]={ | |
73 | + 0x8FA30004, // lw v1,4(sp) | |
74 | + 0x00600008, // jr v1 | |
75 | + 0x27BD0004, // addiu sp,sp,4 | |
76 | +}; | |
77 | + | |
78 | + | |
79 | + | |
80 | +char* begin_compiling_class(int class){ | |
81 | + // Initialize parameters | |
82 | + g_compiling_class=class; | |
83 | + g_class_structure=0; | |
84 | + // Register the class to cmpdata without class structure | |
85 | + return update_class_info(class); | |
86 | +} | |
87 | + | |
88 | +char* end_compiling_class(int class){ | |
89 | + char* err; | |
90 | + g_compiling_class=0; | |
91 | + // Construct class structure | |
92 | + err=construct_class_structure(class); | |
93 | + if (err) return err; | |
94 | + // Uppdate class information. | |
95 | + err=update_class_info(class); | |
96 | + if (err) return err; | |
97 | + // Resolve CMPDATA_UNSOLVED. | |
98 | + err=resolve_unresolved(class); | |
99 | + if (err) return err; | |
100 | + // Delete some cmpdata. | |
101 | + delete_cmpdata_for_class(class); | |
102 | + return 0; | |
103 | +} | |
104 | + | |
105 | +void* search_method(int* classdata,int method){ | |
106 | + int pos,i; | |
107 | + int nums=classdata[1]; | |
108 | + | |
109 | + classdata+=2; // exclude first 2 words | |
110 | + classdata+=2*(nums&0xff); // exclude public field | |
111 | + classdata+=2*((nums>>8)&0xff); // exclude private field | |
112 | + nums=(nums>>16)&0xff; // number of methods | |
113 | + for(i=0;i<nums;i++){ | |
114 | + if (classdata[0]==method) return (void*)classdata[1]; | |
115 | + classdata+=2; | |
116 | + } | |
117 | + return 0; // not found | |
118 | +} | |
119 | + | |
120 | +char* resolve_unresolved(int class){ | |
121 | + int* classdata; | |
122 | + int* record; | |
123 | + int* code; | |
124 | + int i; | |
125 | + // Get class structure | |
126 | + cmpdata_reset(); | |
127 | + while(record=cmpdata_find(CMPDATA_CLASS)){ | |
128 | + if (record[1]==class) break; | |
129 | + } | |
130 | + if (!record) return ERR_UNKNOWN; | |
131 | + classdata=(int*)record[2]; | |
132 | + // Explore CMPDATA_UNSOLVED | |
133 | + cmpdata_reset(); | |
134 | + while(record=cmpdata_find(CMPDATA_UNSOLVED)){ | |
135 | + // Note: don't use cmpdata_find() again in the loop. | |
136 | + // If used, the solved CMPDATA_UNSOLVED must be removed before. | |
137 | + if (record[1]!=class) continue; | |
138 | + switch (record[0]&0xffff) { | |
139 | + case CMPTYPE_NEW_FUNCTION: | |
140 | + // Resolve address of code for pointer to class structure | |
141 | + code=(int*)(record[2]); | |
142 | + code[0]=(code[0]&0xFFFF0000) | (((unsigned int)classdata)>>16); | |
143 | + code[1]=(code[1]&0xFFFF0000) | (((unsigned int)classdata) & 0x0000FFFF); | |
144 | + // Resolve size of object | |
145 | + code=(int*)(record[3]); | |
146 | + code[0]=(code[0]&0xFFFF0000) | (object_size(classdata) & 0x0000FFFF); | |
147 | + // All done | |
148 | + break; | |
149 | + case CMPTYPE_STATIC_METHOD: | |
150 | + // Resolve address of code for pointer to method | |
151 | + // Find method | |
152 | + i=(int)search_method(classdata,record[2]); | |
153 | + if (!i) return ERR_NOT_FIELD; | |
154 | + code=(int*)(record[3]); | |
155 | + code[0]=(code[0]&0xFC000000)|((i&0x0FFFFFFF)>>2); | |
156 | + // All done | |
157 | + break; | |
158 | + default: | |
159 | + return ERR_UNKNOWN; | |
160 | + } + } | |
161 | + return 0; | |
162 | +} | |
163 | + | |
164 | +char* update_class_info(int class){ | |
165 | + int* record; | |
166 | + int data[2]; | |
167 | + // Update record if exist. | |
168 | + cmpdata_reset(); | |
169 | + while(record=cmpdata_find(CMPDATA_CLASS)){ | |
170 | + if (record[1]==class) { | |
171 | + record[2]=(int)g_class_structure; | |
172 | + return 0; | |
173 | + } | |
174 | + } | |
175 | + // No record of this class yet. Insert a record. | |
176 | + data[0]=class; | |
177 | + data[1]=(int)g_class_structure; | |
178 | + return cmpdata_insert(CMPDATA_CLASS,0,&data[0],2); | |
179 | +} | |
180 | + | |
181 | +/* | |
182 | + Class structure: | |
183 | + cstruct[0]: class name as integer | |
184 | + cstruct[1]: number of fields and methods: | |
185 | + bit 0-7: # of public fields | |
186 | + bit 8-15: # of private fields | |
187 | + bit 16-23: # of public methods | |
188 | + bit 24-31: reserved | |
189 | + cstruct[x]: public field name | |
190 | + cstruct[x+1]: public field var number | |
191 | + cstruct[y]: private field name | |
192 | + cstruct[y+1]: private field var number | |
193 | + cstruct[z]: public method name | |
194 | + cstruct[z+1]: public method pointer | |
195 | +*/ | |
196 | + | |
197 | +char* construct_class_structure(int class){ | |
198 | + int* record; | |
199 | + int i; | |
200 | + int num=0; | |
201 | + // Register current address to global var | |
202 | + g_class_structure=&g_object[g_objpos]; | |
203 | + // Construct a class structure in object area in following lines | |
204 | + // Class name | |
205 | + check_obj_space(2); | |
206 | + g_object[g_objpos++]=class; // Class name | |
207 | + g_objpos++; // Number of fields/methods | |
208 | + // Public fields | |
209 | + cmpdata_reset(); | |
210 | + while(record=cmpdata_find(CMPDATA_FIELD)){ | |
211 | + if ((record[0]&0xffff)==CMPTYPE_PUBLIC_FIELD) { | |
212 | + num+=1<<0; | |
213 | + check_obj_space(2); | |
214 | + g_object[g_objpos++]=record[1]; // Field name | |
215 | + g_objpos++; // Var number (see below) | |
216 | + } | |
217 | + } | |
218 | + // Private fields | |
219 | + cmpdata_reset(); | |
220 | + while(record=cmpdata_find(CMPDATA_FIELD)){ | |
221 | + if ((record[0]&0xffff)==CMPTYPE_PRIVATE_FIELD) { | |
222 | + num+=1<<8; | |
223 | + check_obj_space(2); | |
224 | + g_object[g_objpos++]=record[1]; // Field name | |
225 | + g_objpos++; // Var number (see below) | |
226 | + } | |
227 | + } | |
228 | + // Public methods | |
229 | + cmpdata_reset(); | |
230 | + while(record=cmpdata_find(CMPDATA_FIELD)){ | |
231 | + if ((record[0]&0xffff)==CMPTYPE_PUBLIC_METHOD) { | |
232 | + num+=1<<16; | |
233 | + check_obj_space(2); | |
234 | + g_object[g_objpos++]=record[1]; // Method name | |
235 | + g_object[g_objpos++]=record[2]; // pointer | |
236 | + } | |
237 | + } | |
238 | + // Update number info | |
239 | + g_class_structure[1]=num; | |
240 | + // Update var numbers of fields | |
241 | + num=((num>>8)&0xff)+(num&0xff); | |
242 | + for(i=1;i<=num;i++){ | |
243 | + if (( | |
244 | + g_class_structure[i*2+1]=search_var_name(0x7FFFFFFF & g_class_structure[i*2])+ALLOC_LNV_BLOCK | |
245 | + )<ALLOC_LNV_BLOCK) return ERR_UNKNOWN; | |
246 | + } | |
247 | + return 0; | |
248 | +} | |
249 | + | |
250 | +void delete_cmpdata_for_class(int class){ | |
251 | + int* record; | |
252 | + // Delete field/method data | |
253 | + cmpdata_reset(); | |
254 | + while(record=cmpdata_find(CMPDATA_FIELD)){ | |
255 | + cmpdata_delete(record); | |
256 | + cmpdata_reset(); | |
257 | + } | |
258 | + // Delete longvar data | |
259 | + cmpdata_reset(); | |
260 | + while(record=cmpdata_find(CMPDATA_USEVAR)){ | |
261 | + cmpdata_delete(record); | |
262 | + cmpdata_reset(); | |
263 | + } | |
264 | + // Delete solved class codes | |
265 | + cmpdata_reset(); | |
266 | + while(record=cmpdata_find(CMPDATA_UNSOLVED)){ | |
267 | + if (record[1]!=class) continue; | |
268 | + cmpdata_delete(record); | |
269 | + cmpdata_reset(); | |
270 | + } | |
271 | +} | |
272 | + | |
273 | +int object_size(int* classdata){ | |
274 | + int nums=classdata[1]; | |
275 | + int size=nums&0xff; // public field | |
276 | + size+=(nums>>8)&0xff; // private | |
277 | + // Add 1 for pointer to class data. | |
278 | + return size+1; | |
279 | +} | |
280 | + | |
281 | +char* new_function(){ | |
282 | + char* err; | |
283 | + int class,size; | |
284 | + int i,stack, opos; | |
285 | + int* data; | |
286 | + int* classdata; | |
287 | + int record[3]; | |
288 | + void* init_method; | |
289 | + // Resolve class name | |
290 | + err=get_label(); | |
291 | + if (err) return err; | |
292 | + if (!g_label) return ERR_SYNTAX; | |
293 | + class=g_label; | |
294 | + record[0]=class; | |
295 | + next_position(); | |
296 | + // Get class data from cmpdata | |
297 | + // Note that the address of class structure can be resolved | |
298 | + // by using cmpdata when compiling NEW function but not running. | |
299 | + // Therefore, class table is not requred when running. | |
300 | + cmpdata_reset(); | |
301 | + while(data=cmpdata_find(CMPDATA_CLASS)){ | |
302 | + if (data[1]==class) break; | |
303 | + } | |
304 | + if (!data) return ERR_NO_CLASS; | |
305 | + classdata=(int*)data[2]; | |
306 | + if (classdata) { | |
307 | + size=object_size(classdata); | |
308 | + } else { | |
309 | + // Class structure is unsolved. | |
310 | + size=0; | |
311 | + } | |
312 | + // Create object | |
313 | + record[2]=(int)&g_object[g_objpos+3]; | |
314 | + call_quicklib_code(lib_calloc_memory,ASM_ORI_A0_ZERO_|size); | |
315 | + // First word of object is pointer to classdata | |
316 | + check_obj_space(3); | |
317 | + record[1]=(int)&g_object[g_objpos]; | |
318 | + g_object[g_objpos++]=0x3C080000|(((unsigned int)classdata)>>16); // lui t0,xxxx | |
319 | + g_object[g_objpos++]=0x35080000|(((unsigned int)classdata)&0x0000FFFF); // ori t0,t0,xxxx | |
320 | + g_object[g_objpos++]=0xAC480000; // sw t0,0(v0) | |
321 | + // Check if INIT method exists | |
322 | + if (classdata) { | |
323 | + init_method=search_method(classdata,LABEL_INIT); | |
324 | + } else { | |
325 | + // Class structure is unknown. Use null method. | |
326 | + init_method=(int*)&g_return_code[0]; | |
327 | + // Register CMPDATA | |
328 | + cmpdata_insert(CMPDATA_UNSOLVED,CMPTYPE_NEW_FUNCTION,(int*)&record[0],3); | |
329 | + g_allow_shift_obj=0; | |
330 | + } | |
331 | + if (!init_method) { | |
332 | + // All done | |
333 | + // Note that $v0 is address of object here. | |
334 | + // There should not be parameter(s). | |
335 | + if (g_source[g_srcpos]==',') return ERR_NO_INIT; | |
336 | + return 0; | |
337 | + } | |
338 | + // INIT method exists. Note that $v0 is address of object here. | |
339 | + if (g_source[g_srcpos]==',') g_srcpos++; | |
340 | + else if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
341 | + check_obj_space(2); | |
342 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
343 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
344 | + err=obj_method(LABEL_INIT); | |
345 | + if (err) return err; | |
346 | + g_srcpos--; // Leave ')' character for detecting end of "new" function | |
347 | + check_obj_space(2); | |
348 | + g_object[g_objpos++]=0x8FA20004; //lw v0,4(sp) | |
349 | + g_object[g_objpos++]=0x27BD0004; //addiu sp,sp,4 | |
350 | + // All done | |
351 | + // Note that $v0 is address of object here. | |
352 | + return 0; | |
353 | +} | |
354 | + | |
355 | +char* field_statement(){ | |
356 | + char* err; | |
357 | + int i; | |
358 | + int data[1]; | |
359 | + int is_private=0; | |
360 | + // This statement is valid only in class file. | |
361 | + if (!g_compiling_class) return ERR_INVALID_NON_CLASS; | |
362 | + // Check which private or public | |
363 | + next_position(); | |
364 | + if (nextCodeIs("PRIVATE ")) { | |
365 | + is_private=1; | |
366 | + } else if (nextCodeIs("PUBLIC ")) { | |
367 | + is_private=0; | |
368 | + } | |
369 | + do { | |
370 | + next_position(); | |
371 | + i=check_var_name(); | |
372 | + if (i<65536) return ERR_SYNTAX; | |
373 | + // Register varname | |
374 | + err=register_var_name(i); | |
375 | + if (err) return err; | |
376 | + if (g_source[g_srcpos]=='#') { | |
377 | + g_srcpos++; | |
378 | + } else if (g_source[g_srcpos]=='$') { | |
379 | + // String field. Raise 31st bit. | |
380 | + g_srcpos++; | |
381 | + i|=0x80000000; | |
382 | + } else if (g_source[g_srcpos]=='(' && g_source[g_srcpos+1]==')' && is_private) { | |
383 | + // Dimension field (private only). Raise 31st bit. | |
384 | + g_srcpos++; | |
385 | + g_srcpos++; | |
386 | + i|=0x80000000; | |
387 | + } | |
388 | + // Register field | |
389 | + data[0]=i; | |
390 | + if (is_private) { | |
391 | + err=cmpdata_insert(CMPDATA_FIELD,CMPTYPE_PRIVATE_FIELD,(int*)&data[0],1); | |
392 | + } else { | |
393 | + err=cmpdata_insert(CMPDATA_FIELD,CMPTYPE_PUBLIC_FIELD,(int*)&data[0],1); | |
394 | + } | |
395 | + next_position(); | |
396 | + if (g_source[g_srcpos]==',') { | |
397 | + g_srcpos++; | |
398 | + } else { | |
399 | + break; | |
400 | + } | |
401 | + } while(1); | |
402 | + return 0; | |
403 | +} | |
404 | + | |
405 | +/* | |
406 | + char* obj_method(int method); | |
407 | + Implementation of access to method of object. | |
408 | +*/ | |
409 | +char* obj_method(int method){ | |
410 | + // $v0 contains the address of object. | |
411 | + // Note that '(' has been passed. | |
412 | + char* err; | |
413 | + int stack,opos; | |
414 | + // When method of an object is called from object, | |
415 | + // current variables must be saved to object fields | |
416 | + if (g_compiling_class) { | |
417 | + check_obj_space(1); | |
418 | + g_object[g_objpos++]=0x00402821; // addu a1,v0,zero | |
419 | + call_quicklib_code(lib_save_vars_to_fields,ASM_LW_A0_XXXX_S5|ARGS_S5_V0_OBJ); | |
420 | + } | |
421 | + // Parameters preparation (to $s5) here. | |
422 | + next_position(); | |
423 | + opos=g_objpos; | |
424 | + // Begin parameter(s) construction routine | |
425 | + err=prepare_args_stack('('); | |
426 | + if (err) return err; | |
427 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
428 | + g_srcpos++; | |
429 | + // Determine address of method and store fields to local variables. | |
430 | + check_obj_space(3); | |
431 | + g_object[g_objpos++]=0x8FA20000|ARGS_SP_V0_OBJ; // lw v0,8(sp) | |
432 | + g_object[g_objpos++]=0x3C050000|((method>>16)&0x0000FFFF); // lui a1,xxxx | |
433 | + g_object[g_objpos++]=0x34A50000|(method&0x0000FFFF); // ori a1,a1,xxxx | |
434 | + call_quicklib_code(lib_pre_method,ASM_ADDU_A0_V0_ZERO); | |
435 | + // Call method address here. Same routine for GOSUB statement with integer value is used. | |
436 | + check_obj_space(6); | |
437 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
438 | + g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
439 | + g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5) | |
440 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
441 | + g_object[g_objpos++]=0x00000000; // nop | |
442 | + // label1: | |
443 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
444 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) // label2: | |
445 | + // Restore fields from local variables. | |
446 | + check_obj_space(3); | |
447 | + g_object[g_objpos++]=0x8FA40008; // lw a0,8(sp) | |
448 | + call_quicklib_code(lib_post_method,ASM_ADDU_A1_V0_ZERO); | |
449 | + // Remove stack | |
450 | + err=remove_args_stack(); | |
451 | + if (err) return err; | |
452 | + // When method of an object is called from object, | |
453 | + // current variables must be saved to object fields | |
454 | + if (g_compiling_class) { | |
455 | + check_obj_space(1); | |
456 | + g_object[g_objpos++]=0x00402821; // addu a1,v0,zero | |
457 | + call_quicklib_code(lib_load_vars_from_fields,ASM_LW_A0_XXXX_S5|ARGS_S5_V0_OBJ); | |
458 | + } | |
459 | + return 0; | |
460 | +} | |
461 | + | |
462 | +/* | |
463 | + char* integer_obj_field(); | |
464 | + char* string_obj_field(); | |
465 | + char* float_obj_field(); | |
466 | + Implementation of access to field of object. | |
467 | + This feature is recursive. When an object is applied to the field of another object, | |
468 | + following expression is possible (for example): | |
469 | + obj1.field1.field2 | |
470 | + | |
471 | +*/ | |
472 | + | |
473 | +#define OBJ_FIELD_INTEGER 0 | |
474 | +#define OBJ_FIELD_STRING '$' | |
475 | +#define OBJ_FIELD_FLOAT '#' | |
476 | + | |
477 | +char* _obj_field(char mode){ | |
478 | + // $v0 contains the address of object. | |
479 | + int i; | |
480 | + char* err; | |
481 | + do { | |
482 | + i=check_var_name(); | |
483 | + if (i<65536) return ERR_SYNTAX; | |
484 | + if (g_source[g_srcpos]=='(' && mode==OBJ_FIELD_INTEGER) { | |
485 | + // This is a method | |
486 | + g_srcpos++; | |
487 | + return obj_method(i); | |
488 | + } else if (g_source[g_srcpos+1]=='(') { | |
489 | + if (g_source[g_srcpos]==mode) { | |
490 | + // This is a string/float method | |
491 | + g_srcpos++; | |
492 | + g_srcpos++; | |
493 | + return obj_method(i); | |
494 | + } | |
495 | + } else if (g_source[g_srcpos]==mode && mode==OBJ_FIELD_STRING) { | |
496 | + // This is a string field. Raise 31st bit. | |
497 | + i|=0x80000000; | |
498 | + } | |
499 | + check_obj_space(2); | |
500 | + g_object[g_objpos++]=0x3C050000|((i>>16)&0x0000FFFF); // lui a1,xxxx | |
501 | + g_object[g_objpos++]=0x34A50000|(i&0x0000FFFF); // ori a1,a1,xxxx | |
502 | + // First and second arguments are address of object and field name, respectively. | |
503 | + call_quicklib_code(lib_obj_field,ASM_ADDU_A0_V0_ZERO); | |
504 | + // Check if "." follows | |
505 | + if (g_source[g_srcpos]=='.') { | |
506 | + // "." found. $v0 is adress of an object. See the field. | |
507 | + g_srcpos++; | |
508 | + continue; | |
509 | + } | |
510 | + } while(0); | |
511 | + // All done. Check variable type | |
512 | + if (mode==OBJ_FIELD_INTEGER) return 0; | |
513 | + else if (g_source[g_srcpos]==mode) { | |
514 | + g_srcpos++; | |
515 | + return 0; | |
516 | + } else return ERR_SYNTAX; | |
517 | +} | |
518 | + | |
519 | +char* integer_obj_field(){ | |
520 | + return _obj_field(OBJ_FIELD_INTEGER); | |
521 | +} | |
522 | + | |
523 | +char* string_obj_field(){ | |
524 | + return _obj_field(OBJ_FIELD_STRING); | |
525 | +} | |
526 | + | |
527 | +char* float_obj_field(){ | |
528 | + return _obj_field(OBJ_FIELD_FLOAT); | |
529 | +} | |
530 | + | |
531 | +int lib_obj_field(int* object, int fieldname){ | |
532 | + int* class; | |
533 | + int i,numfield; | |
534 | + // Check if this is an object (if within the RAM). | |
535 | + if (!withinRAM(object)) err_not_obj(); | |
536 | + class=(int*)object[0]; | |
537 | + if (!withinRAM(class)) err_not_obj(); | |
538 | + // Obtain # of public field | |
539 | + numfield=class[1]&0xff; | |
540 | + for(i=0;i<numfield;i++){ | |
541 | + if (class[2+i*2]==fieldname) break; | |
542 | + } | |
543 | + if (i==numfield) err_not_field(fieldname,class[0]); | |
544 | + // Got address of field. Return value as $v0 and address as $v1. | |
545 | + g_temp=(int)(&object[1+i]); | |
546 | + asm volatile("la $v1,%0"::"i"(&g_temp)); | |
547 | + asm volatile("lw $v1,0($v1)"); | |
548 | + return object[1+i]; | |
549 | +} | |
550 | + | |
551 | +/* | |
552 | + Library for letting string field | |
553 | +*/ | |
554 | + | |
555 | +void lib_let_str_field(char* prev_str, char* new_str){ | |
556 | + int var_num=get_permanent_var_num(); | |
557 | + free_perm_str(prev_str); | |
558 | + lib_let_str(new_str,var_num); | |
559 | + return; | |
560 | +} | |
561 | + | |
562 | +/* | |
563 | + Library for calling method statement | |
564 | +*/ | |
565 | + | |
566 | +int lib_load_vars_from_fields(int* object, int v0){ | |
567 | + // Do nothing if no object | |
568 | + if (object) lib_pre_method(object,LABEL_INIT); | |
569 | + return v0; | |
570 | +} | |
571 | + | |
572 | +int lib_pre_method(int* object, int methodname){ | |
573 | + int i,num,nums; | |
574 | + int* class; | |
575 | + // Check if this is an object (if within the RAM). | |
576 | + if (!withinRAM(object)) err_not_obj(); | |
577 | + class=(int*)object[0]; | |
578 | + if (!withinRAM(class)) err_not_obj(); | |
579 | + // Save object field values in local variables in class | |
580 | + nums=class[1]; | |
581 | + num=nums&0xff; | |
582 | + for(i=0;i<num;i++){ | |
583 | + // Public fields | |
584 | + class+=2; | |
585 | + g_var_mem[class[1]]=object[i+1]; | |
586 | + // When string, move from permanent block | |
587 | + if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]); | |
588 | + } | |
589 | + num+=(nums>>8)&0xff; | |
590 | + for(i=i;i<num;i++){ | |
591 | + // Private fields | |
592 | + class+=2; | |
593 | + g_var_mem[class[1]]=object[i+1]; | |
594 | + // When string/dimension, move from permanent block | |
595 | + if (0x80000000&class[0]) move_from_perm_block_if_exists(class[1]); | |
596 | + } | |
597 | + // Seek method | |
598 | + num+=(nums>>16)&0xff; | |
599 | + for(i=i;i<num;i++){ | |
600 | + class+=2; | |
601 | + if (class[0]==methodname) break; | |
602 | + } | |
603 | + if (i==num) { | |
604 | + // Method not found | |
605 | + if (methodname==LABEL_INIT) { | |
606 | + // INIT method not found | |
607 | + // Call null function | |
608 | + return (int)(&g_return_code[0]); | |
609 | + } else { | |
610 | + class=(int*)object[0]; | |
611 | + err_not_field(methodname,class[0]); | |
612 | + } | |
613 | + } | |
614 | + // Method found. return it. | |
615 | + return class[1]; | |
616 | +} | |
617 | + | |
618 | +int lib_save_vars_to_fields(int* object,int v0){ | |
619 | + int* class; | |
620 | + // Do nothing if no object | |
621 | + if (!object) return; | |
622 | + // Check if this is an object (if within the RAM). | |
623 | + if (!withinRAM(object)) err_not_obj(); | |
624 | + class=(int*)object[0]; | |
625 | + if (!withinRAM(class)) err_not_obj(); | |
626 | + // save vars | |
627 | + lib_post_method(object,0); | |
628 | + return v0; | |
629 | +} | |
630 | + | |
631 | +int lib_post_method(int* object, int v0){ | |
632 | + // Note that v0 (a1) contains the return value from a method. | |
633 | + int i,num,nums; | |
634 | + int* class; | |
635 | + // Restore local variables to object field values | |
636 | + class=(int*)object[0]; | |
637 | + nums=class[1]; | |
638 | + num=nums&0xff; | |
639 | + for(i=0;i<num;i++){ | |
640 | + // Public fields | |
641 | + class+=2; | |
642 | + object[i+1]=g_var_mem[class[1]]; | |
643 | + // When string, move to permanent block | |
644 | + if (0x80000000&class[0]) { | |
645 | + if (g_var_size[class[1]]) move_to_perm_block(class[1]); | |
646 | + } | |
647 | + } | |
648 | + num+=(nums>>8)&0xff; | |
649 | + for(i=i;i<num;i++){ | |
650 | + // Private fields | |
651 | + class+=2; | |
652 | + object[i+1]=g_var_mem[class[1]]; | |
653 | + // When string/dimension, move to permanent block | |
654 | + if (0x80000000&class[0]) { | |
655 | + if (g_var_size[class[1]]) move_to_perm_block(class[1]); | |
656 | + } | |
657 | + } | |
658 | + // all done | |
659 | + return v0; | |
660 | +} | |
661 | + | |
662 | +/* | |
663 | + Method statement | |
664 | +*/ | |
665 | + | |
666 | +char* method_statement(){ | |
667 | + char* err; | |
668 | + int data[2]; | |
669 | + int opos=g_objpos; | |
670 | + // This statement is valid only in class file. | |
671 | + if (!g_compiling_class) return ERR_INVALID_NON_CLASS; | |
672 | + // Insert label for setting $s6 | |
673 | + err=label_statement(); | |
674 | + if (err) return err; | |
675 | + // Register cmpdata | |
676 | + data[0]=g_label; | |
677 | + data[1]=(int)(&g_object[opos]); | |
678 | + return cmpdata_insert(CMPDATA_FIELD,CMPTYPE_PUBLIC_METHOD,(int*)&data[0],2); | |
679 | +} | |
680 | + | |
681 | +/* | |
682 | + Delete statement | |
683 | +*/ | |
684 | + | |
685 | +char* delete_statement(){ | |
686 | + char* err; | |
687 | + next_position(); | |
688 | + g_srcpos--; | |
689 | + do{ | |
690 | + g_srcpos++; | |
691 | + err=get_value(); | |
692 | + if (err) return err; | |
693 | + call_quicklib_code(lib_delete,ASM_ADDU_A0_V0_ZERO); | |
694 | + next_position(); | |
695 | + } while (g_source[g_srcpos]==','); | |
696 | + return 0; | |
697 | +} | |
698 | + | |
699 | +/* | |
700 | + Call statement | |
701 | +*/ | |
702 | + | |
703 | +char* call_statement(){ | |
704 | + // Just get an integer value. That is it. | |
705 | + return get_value(); | |
706 | +} | |
707 | + | |
708 | +/* | |
709 | + Static statement | |
710 | +*/ | |
711 | + | |
712 | +char* static_statement(){ | |
713 | + char* err; | |
714 | + int* record; | |
715 | + int data[2]; | |
716 | + int i; | |
717 | + int is_private=0; | |
718 | + // This statement is valid only in class file. | |
719 | + if (!g_compiling_class) return ERR_INVALID_NON_CLASS; | |
720 | + // Check which private or public | |
721 | + next_position(); | |
722 | + if (nextCodeIs("PRIVATE ")) { | |
723 | + is_private=1; | |
724 | + } else if (nextCodeIs("PUBLIC ")) { | |
725 | + is_private=0; | |
726 | + } | |
727 | + do { | |
728 | + next_position(); | |
729 | + i=check_var_name(); | |
730 | + if (i<65536) return ERR_SYNTAX; | |
731 | + if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') { | |
732 | + g_srcpos++; | |
733 | + } | |
734 | + // Register public static field | |
735 | + if (is_private) { | |
736 | + // This is the same as USEVAR | |
737 | + // Register varname | |
738 | + err=register_var_name(i); | |
739 | + if (err) return err; | |
740 | + } else { | |
741 | + // Check if there is already a CMPDATA record | |
742 | + cmpdata_reset(); | |
743 | + while(record=cmpdata_find(CMPDATA_STATIC)){ | |
744 | + if (record[1]!=g_compiling_class) continue; | |
745 | + if (record[2]!=i) continue; | |
746 | + break; | |
747 | + } | |
748 | + if (record) { | |
749 | + // There is already a record. | |
750 | + // Do not allocate new number but use the registered number; | |
751 | + i=record[0]&0xffff; | |
752 | + err=cmpdata_insert(CMPDATA_USEVAR,i,&record[2],1); | |
753 | + if (err) return err; | |
754 | + } else { | |
755 | + // Register varname | |
756 | + err=register_var_name(i); | |
757 | + if (err) return err; | |
758 | + // Insert a CMDATA_STATIC record | |
759 | + data[0]=g_compiling_class; // class name as integer | |
760 | + data[1]=i; // static var name as integer | |
761 | + i=search_var_name(i); // var number of this static field | |
762 | + if (i<0) return ERR_UNKNOWN; | |
763 | + err=cmpdata_insert(CMPDATA_STATIC,i,(int*)&data[0],2); | |
764 | + if (err) return err; | |
765 | + } | |
766 | + } | |
767 | + next_position(); | |
768 | + if (g_source[g_srcpos]==',') { | |
769 | + g_srcpos++; | |
770 | + } else { | |
771 | + break; | |
772 | + } | |
773 | + } while(1); | |
774 | + return 0; | |
775 | + | |
776 | +} | |
777 | + | |
778 | +/* | |
779 | + Static method | |
780 | + Type is either 0, '$', or '#', | |
781 | + for integer, string, or float | |
782 | +*/ | |
783 | + | |
784 | +char* static_method(char type){ | |
785 | + char* err; | |
786 | + int* data; | |
787 | + int record[3]; | |
788 | + int i,opos,method,stack; | |
789 | + next_position(); | |
790 | + // Check class name | |
791 | + i=check_var_name(); | |
792 | + if (i<65536) return ERR_SYNTAX; | |
793 | + record[0]=i; | |
794 | + // Check if the class exists | |
795 | + cmpdata_reset(); | |
796 | + while(data=cmpdata_find(CMPDATA_CLASS)){ | |
797 | + if (data[1]==i) { | |
798 | + // The class was already defined. | |
799 | + i=0; | |
800 | + break; | |
801 | + } | |
802 | + } | |
803 | + // Check '::' | |
804 | + if (g_source[g_srcpos]!=':') return ERR_SYNTAX; | |
805 | + g_srcpos++; | |
806 | + if (g_source[g_srcpos]!=':') return ERR_SYNTAX; | |
807 | + g_srcpos++; | |
808 | + if (i) return ERR_NO_CLASS; | |
809 | + data=(int*)data[2]; | |
810 | + // Check method | |
811 | + i=check_var_name(); | |
812 | + if (i<65536) return ERR_SYNTAX; | |
813 | + if (data) { | |
814 | + method=(int)search_method(data,i); | |
815 | + if (!method) return ERR_NOT_FIELD; | |
816 | + } else { | |
817 | + method=(int)&g_return_code[0]; | |
818 | + record[1]=i; | |
819 | + } | |
820 | + // Check type and '(' | |
821 | + if (type) {// Either 0, '$', or '#' | |
822 | + if (g_source[g_srcpos]!=type) return ERR_SYNTAX; | |
823 | + g_srcpos++; | |
824 | + | |
825 | + } | |
826 | + if (g_source[g_srcpos]!='(') return ERR_SYNTAX; | |
827 | + g_srcpos++; | |
828 | + // Begin parameter(s) construction routine | |
829 | + check_obj_space(1); | |
830 | + g_object[g_objpos++]=0x34020000; // ori v0,zero,0 | |
831 | + err=prepare_args_stack('('); | |
832 | + if (err) return err; | |
833 | + // Calling subroutine, which is static method of class | |
834 | + record[2]=(int)&g_object[g_objpos+5]; | |
835 | + check_obj_space(7); | |
836 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
837 | + g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
838 | + g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5) | |
839 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
840 | + g_object[g_objpos++]=0x00000000; // nop | |
841 | + // label1: | |
842 | + g_object[g_objpos++]=0x08000000|((method&0x0FFFFFFF)>>2); // j xxxx | |
843 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
844 | + // label2: | |
845 | + // Register CMPDATA if required. | |
846 | + if (!data) { | |
847 | + cmpdata_insert(CMPDATA_UNSOLVED,CMPTYPE_STATIC_METHOD,(int*)&record[0],3); | |
848 | + g_allow_shift_obj=0; | |
849 | + } | |
850 | + // Remove stack | |
851 | + err=remove_args_stack(); | |
852 | + if (err) return err; | |
853 | + return 0; | |
854 | +} | |
855 | + | |
856 | +/* | |
857 | + Let object.field statement | |
858 | +*/ | |
859 | + | |
860 | +char* let_object_field(){ | |
861 | + char* err; | |
862 | + char b3; | |
863 | + int spos,opos; | |
864 | + // $v0 contains the pointer to object | |
865 | + spos=g_srcpos; | |
866 | + opos=g_objpos; | |
867 | + // Try string field, first | |
868 | + err=string_obj_field(); | |
869 | + if (err) { | |
870 | + // Integer or float field | |
871 | + g_srcpos=spos; | |
872 | + g_objpos=opos; | |
873 | + err=integer_obj_field(); | |
874 | + if (err) return err; | |
875 | + b3=g_source[g_srcpos]; | |
876 | + if (b3=='#') g_srcpos++; | |
877 | + } else { | |
878 | + // String field | |
879 | + b3='$'; | |
880 | + } | |
881 | + if (g_source[g_srcpos-1]==')') { | |
882 | + // This is a CALL statement | |
883 | + return 0; | |
884 | + } | |
885 | + // $v1 is address to store value. Save it in stack. | |
886 | + check_obj_space(1); | |
887 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
888 | + g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
889 | + if (b3=='$') { | |
890 | + // String field | |
891 | + // Get value | |
892 | + next_position(); | |
893 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
894 | + g_srcpos++; | |
895 | + err=get_string(); | |
896 | + } else if (b3=='#') { | |
897 | + // Float field | |
898 | + // Get value | |
899 | + next_position(); | |
900 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
901 | + g_srcpos++; | |
902 | + err=get_float(); | |
903 | + } else { | |
904 | + // Integer field | |
905 | + // Get value | |
906 | + next_position(); | |
907 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
908 | + g_srcpos++; | |
909 | + err=get_value(); | |
910 | + } | |
911 | + if (err) return err; | |
912 | + // Store in field of object | |
913 | + check_obj_space(4); | |
914 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
915 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
916 | + g_object[g_objpos++]=0x8C640000; // lw a0,0(v1) | |
917 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
918 | + // Handle permanent block for string field | |
919 | + if (b3=='$') call_quicklib_code(lib_let_str_field,ASM_ADDU_A1_V0_ZERO); | |
920 | + return 0; | |
921 | +} | |
\ No newline at end of file |
@@ -5,6 +5,10 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include "compiler.h" |
9 | 13 | |
10 | 14 | /* |
@@ -21,10 +25,22 @@ | ||
21 | 25 | data16: general 16 bit data (short) |
22 | 26 | */ |
23 | 27 | |
28 | +/* | |
29 | + CMPDATA_TEMP structure | |
30 | + type: CMPDATA_TEMP (6) | |
31 | + len: n+1 | |
32 | + data16: id | |
33 | + record[1]: any data | |
34 | + record[2]: any data | |
35 | + ... | |
36 | + record[n]: any data | |
37 | +*/ | |
38 | + | |
24 | 39 | #define g_cmpdata g_objmax |
25 | 40 | |
26 | 41 | static int* g_cmpdata_end; |
27 | 42 | static int* g_cmpdata_point; |
43 | +static unsigned short g_cmpdata_id; | |
28 | 44 | |
29 | 45 | /* |
30 | 46 | Initialize routine must be called when starting compiler. |
@@ -32,9 +48,18 @@ | ||
32 | 48 | void cmpdata_init(){ |
33 | 49 | g_cmpdata_end=g_objmax; |
34 | 50 | g_cmpdata_point=g_objmax; |
51 | + g_cmpdata_id=1; | |
35 | 52 | } |
36 | 53 | |
37 | 54 | /* |
55 | + Returns ID as 16 bit indivisual number | |
56 | +*/ | |
57 | +unsigned short cmpdata_get_id(){ | |
58 | + if ((++g_cmpdata_id)==0) printstr("CMPDATA: no more ID!\n"); | |
59 | + return g_cmpdata_id; | |
60 | +} | |
61 | + | |
62 | +/* | |
38 | 63 | Function to insert a data. The data must be defined by a pointer to int array. |
39 | 64 | unsigned char type: Data type number (0-255) |
40 | 65 | short data16: 16 bit data. If not required, set 0. |
@@ -84,3 +109,22 @@ | ||
84 | 109 | cmpdata_reset(); |
85 | 110 | return cmpdata_find(type); |
86 | 111 | } |
112 | + | |
113 | +/* | |
114 | + Delete a record. | |
115 | +*/ | |
116 | +void cmpdata_delete(int* record){ | |
117 | + int delnum; | |
118 | + int* data; | |
119 | + // Ignore if invalid record. | |
120 | + if (record<g_cmpdata || g_cmpdata_end<record) return; | |
121 | + // Get number of word to delete. | |
122 | + delnum=(record[0]&0x00ff0000)>>16; | |
123 | + // Delete record by shifting data. | |
124 | + for(data=record-1;g_cmpdata<=data;data--){ | |
125 | + data[delnum]=data[0]; | |
126 | + } | |
127 | + g_cmpdata+=delnum; | |
128 | + // Reset | |
129 | + cmpdata_reset(); | |
130 | +} |
@@ -5,6 +5,31 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
12 | +/* | |
13 | + Usage of MIPS32 registors | |
14 | + $zero: always zero | |
15 | + $at: not used | |
16 | + $v0: return value or result of last calculation | |
17 | + $v1: for calculation (like $v0=$v1*$v0) | |
18 | + $a0-$a2: parameters for calling library ($a2=$v0) | |
19 | + $a3: function # for library | |
20 | + $t0-$t7: used as temporary registors | |
21 | + $s0-$s4: not used | |
22 | + $s5: pointer to parameters list | |
23 | + $s6: line or label number | |
24 | + $s7: address of call_library() | |
25 | + $t8-$t9: used as temporary registors | |
26 | + $k0-$k1: not used | |
27 | + $gp: for accessing global valiables by C | |
28 | + $sp: stack pointer | |
29 | + $fp($s8) for accessing valiables by BASIC | |
30 | + $ra: contains return address | |
31 | +*/ | |
32 | + | |
8 | 33 | #include "compiler.h" |
9 | 34 | |
10 | 35 | void start_program(void* addr, void* memory){ |
@@ -32,6 +57,8 @@ | ||
32 | 57 | asm volatile("la $v0,%0"::"i"(&g_end_addr)); |
33 | 58 | asm volatile("la $v1,label"); |
34 | 59 | asm volatile("sw $v1,0($v0)"); |
60 | + // Set s5 for initial_s5_stack | |
61 | + asm volatile("la $s5,%0"::"i"(&g_initial_s5_stack[2])); | |
35 | 62 | // Set s7 for easy calling call_library() |
36 | 63 | asm volatile("la $s7,%0"::"i"(&call_library)); |
37 | 64 | // Set fp and execute program |
@@ -5,6 +5,10 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | // Include envilonment specific configurations |
9 | 13 | #include "envspecific.h" |
10 | 14 |
@@ -24,7 +28,7 @@ | ||
24 | 28 | // Start # of permanent blocks |
25 | 29 | #define ALLOC_PERM_BLOCK 229 |
26 | 30 | // Number of blocks that can be assigned for memory allocation (including all above) |
27 | -#define ALLOC_BLOCK_NUM 239 | |
31 | +#define ALLOC_BLOCK_NUM 329 | |
28 | 32 | |
29 | 33 | // Persistent RAM bytes used for object, heap and exception data |
30 | 34 | #ifndef PERSISTENT_RAM_SIZE |
@@ -118,6 +122,9 @@ | ||
118 | 122 | LIB_FILE =LIB_STEP*48, |
119 | 123 | LIB_PLAYWAVE =LIB_STEP*49, |
120 | 124 | LIB_PLAYWAVEFUNC =LIB_STEP*50, |
125 | + LIB_SETDIR =LIB_STEP*51, | |
126 | + LIB_SETDIRFUNC =LIB_STEP*52, | |
127 | + LIB_GETDIR =LIB_STEP*53, | |
121 | 128 | LIB_DEBUG =LIB_STEP*127, |
122 | 129 | }; |
123 | 130 |
@@ -185,6 +192,7 @@ | ||
185 | 192 | extern unsigned int g_label; |
186 | 193 | extern int g_sdepth; |
187 | 194 | extern int g_maxsdepth; |
195 | +extern char g_allow_shift_obj; | |
188 | 196 | extern enum variable g_lastvar; |
189 | 197 | extern char* g_source; |
190 | 198 | extern int g_srcpos; |
@@ -213,6 +221,8 @@ | ||
213 | 221 | extern unsigned short* g_graphic_area; |
214 | 222 | extern int* g_libparams; |
215 | 223 | extern int g_long_name_var_num; |
224 | +extern int g_class; | |
225 | +extern int g_compiling_class; | |
216 | 226 | extern int g_temp; |
217 | 227 | |
218 | 228 | /* Prototypes */ |
@@ -228,6 +238,9 @@ | ||
228 | 238 | void close_file(); |
229 | 239 | void read_file(int blocklen); |
230 | 240 | char* compile_file(); |
241 | +int compile_and_link_file(char* buff,char* appname); | |
242 | +int compile_and_link_main_file(char* buff,char* appname); | |
243 | +int compile_and_link_class(char* buff,int class); | |
231 | 244 | |
232 | 245 | void err_break(void); |
233 | 246 | void err_music(char* str); |
@@ -242,6 +255,9 @@ | ||
242 | 255 | void err_invalid_param(void); |
243 | 256 | void err_file(void); |
244 | 257 | void err_wave(void); |
258 | +void err_not_obj(void); | |
259 | +void err_not_field(int fieldname, int classname); | |
260 | +void err_str(char* str); | |
245 | 261 | char* resolve_label(int s6); |
246 | 262 | |
247 | 263 | void set_sound(unsigned long* data, int flagsLR); |
@@ -260,6 +276,7 @@ | ||
260 | 276 | char* fput_statement(); |
261 | 277 | char* fputc_statement(); |
262 | 278 | char* fremove_statement(); |
279 | +char* label_statement(); | |
263 | 280 | |
264 | 281 | char* function(void); |
265 | 282 | char* str_function(void); |
@@ -269,11 +286,17 @@ | ||
269 | 286 | void reset_dataread(); |
270 | 287 | |
271 | 288 | void free_temp_str(char* str); |
289 | +void free_non_temp_str(char* str); | |
290 | +void free_perm_str(char* str); | |
272 | 291 | void* alloc_memory(int size, int var_num); |
273 | 292 | void* calloc_memory(int size, int var_num); |
274 | 293 | void move_to_perm_block(int var_num); |
275 | 294 | void move_from_perm_block(int var_num); |
295 | +int move_from_perm_block_if_exists(int var_num); | |
276 | 296 | int get_permanent_var_num(void); |
297 | +int get_varnum_from_address(void* address); | |
298 | +void* lib_calloc_memory(int size); | |
299 | +void lib_delete(int* object); | |
277 | 300 | |
278 | 301 | char* link(void); |
279 | 302 | char* get_label(void); |
@@ -301,10 +324,12 @@ | ||
301 | 324 | char* get_float(); |
302 | 325 | |
303 | 326 | void cmpdata_init(); |
327 | +unsigned short cmpdata_get_id(); | |
304 | 328 | char* cmpdata_insert(unsigned char type, short data16, int* data, unsigned char num); |
305 | 329 | void cmpdata_reset(); |
306 | 330 | int* cmpdata_find(unsigned char type); |
307 | 331 | int* cmpdata_findfirst(unsigned char type); |
332 | +void cmpdata_delete(int* record); | |
308 | 333 | |
309 | 334 | int check_var_name(); |
310 | 335 | int get_var_number(); |
@@ -311,7 +336,37 @@ | ||
311 | 336 | int search_var_name(int nameint); |
312 | 337 | char* register_var_name(int nameint); |
313 | 338 | |
339 | +char* update_class_info(int class); | |
340 | +char* construct_class_structure(int class); | |
341 | +void delete_cmpdata_for_class(int class); | |
314 | 342 | |
343 | +extern const unsigned int g_initial_s5_stack[3]; | |
344 | +char* prepare_args_stack(char start_char); | |
345 | +char* remove_args_stack(void); | |
346 | +char* args_function_main(void); | |
347 | + | |
348 | +char* begin_compiling_class(int class); | |
349 | +char* end_compiling_class(int class); | |
350 | +char* new_function(); | |
351 | +char* field_statement(); | |
352 | +char* integer_obj_field(); | |
353 | +char* string_obj_field(); | |
354 | +char* float_obj_field(); | |
355 | +int lib_obj_field(int* object, int fieldname); | |
356 | +int lib_pre_method(int* object, int methodname); | |
357 | +int lib_post_method(int* object, int v0); | |
358 | +int lib_save_vars_to_fields(int* object,int v0); | |
359 | +int lib_load_vars_from_fields(int* object, int v0); | |
360 | + | |
361 | +char* method_statement(); | |
362 | +char* delete_statement(); | |
363 | +char* call_statement(); | |
364 | +void lib_let_str_field(char* str, char* prev_str); | |
365 | +char* let_object_field(); | |
366 | +char* static_statement(); | |
367 | +char* static_method(char type); | |
368 | +char* resolve_unresolved(int class); | |
369 | + | |
315 | 370 | /* Error messages */ |
316 | 371 | #define ERR_SYNTAX (char*)(g_err_str[0]) |
317 | 372 | #define ERR_NE_BINARY (char*)(g_err_str[1]) |
@@ -335,13 +390,51 @@ | ||
335 | 390 | #define ERR_FILE (char*)(g_err_str[19]) |
336 | 391 | #define ERR_INVALID_VAR_NAME (char*)(g_err_str[20]) |
337 | 392 | #define ERR_WAVE (char*)(g_err_str[21]) |
393 | +#define ERR_COMPILE_CLASS (char*)(g_err_str[22]) | |
394 | +#define ERR_NO_CLASS (char*)(g_err_str[23]) | |
395 | +#define ERR_NOT_OBJ (char*)(g_err_str[24]) | |
396 | +#define ERR_NOT_FIELD (char*)(g_err_str[25]) | |
397 | +#define ERR_INVALID_NON_CLASS (char*)(g_err_str[26]) | |
398 | +#define ERR_INVALID_CLASS (char*)(g_err_str[27]) | |
399 | +#define ERR_NO_INIT (char*)(g_err_str[28]) | |
338 | 400 | |
339 | -/* comple data type numbers */ | |
401 | +/* compile data type numbers */ | |
340 | 402 | #define CMPDATA_RESERVED 0 |
341 | 403 | #define CMPDATA_USEVAR 1 |
404 | +#define CMPDATA_CLASS 2 | |
405 | +#define CMPDATA_FIELD 3 | |
406 | +#define CMPDATA_STATIC 4 | |
407 | +#define CMPDATA_UNSOLVED 5 | |
408 | +#define CMPDATA_TEMP 6 | |
409 | +// Sub types follow | |
410 | +#define CMPTYPE_PUBLIC_FIELD 0 | |
411 | +#define CMPTYPE_PRIVATE_FIELD 1 | |
412 | +#define CMPTYPE_PUBLIC_METHOD 2 | |
413 | +#define CMPTYPE_NEW_FUNCTION 0 | |
414 | +#define CMPTYPE_STATIC_METHOD 1 | |
342 | 415 | |
416 | + | |
417 | +/* Stack position for values in args.c */ | |
418 | +#define ARGS_SP_SP 4 | |
419 | +#define ARGS_SP_V0_OBJ 8 | |
420 | +#define ARGS_SP_PREV_S5 12 | |
421 | +#define ARGS_SP_NUM_ARGS 16 | |
422 | +#define ARGS_S5_SP (-12 & 0xFFFF) | |
423 | +#define ARGS_S5_V0_OBJ (-8 & 0xFFFF) | |
424 | +#define ARGS_S5_PREV_S5 (-4 & 0xFFFF) | |
425 | +#define ARGS_S5_NUM_ARGS (0 & 0xFFFF) | |
426 | + | |
427 | +/* | |
428 | + Hidden varname 31 bit values | |
429 | + Note that max number of 31 bit value is 0x61504BFF (for ZZZZZZ) | |
430 | +*/ | |
431 | +#define HIDDEN_VAR_THIS_OBJECT 0x7FFF0000 | |
432 | + | |
343 | 433 | /* Macros */ |
344 | 434 | |
435 | +// Lables as 31 bit integer | |
436 | +#define LABEL_INIT 0x0007df55 | |
437 | + | |
345 | 438 | // Skip blanc(s) in source code |
346 | 439 | #define next_position() while(g_source[g_srcpos]==' ') {g_srcpos++;} |
347 | 440 |
@@ -359,6 +452,28 @@ | ||
359 | 452 | g_object[g_objpos++]=0x02E0F809;\ |
360 | 453 | g_object[g_objpos++]=0x24070000|((x)&0x0000FFFF) |
361 | 454 | |
455 | +// Insert code for calling quick library | |
456 | +//3C081234 lui t0,0x1234 | |
457 | +//35085678 ori t0,t0,0x5678 | |
458 | +//0100F809 jalr ra,t0 | |
459 | +//00000000 nop | |
460 | +#define call_quicklib_code(x,y) do {\ | |
461 | + check_obj_space(4);\ | |
462 | + g_object[g_objpos++]=0x3C080000|(((unsigned int)(x))>>16);\ | |
463 | + g_object[g_objpos++]=0x35080000|(((unsigned int)(x))&0x0000FFFF);\ | |
464 | + g_object[g_objpos++]=0x0100F809;\ | |
465 | + g_object[g_objpos++]=(y);\ | |
466 | + } while (0) | |
467 | + | |
468 | +#define ASM_NOP 0x00000000 | |
469 | +#define ASM_ADDU_A0_V0_ZERO 0x00402021 | |
470 | +#define ASM_ADDU_A1_V0_ZERO 0x00402821 | |
471 | +#define ASM_ADDU_A2_V0_ZERO 0x00403021 | |
472 | +#define ASM_ADDU_A3_V0_ZERO 0x00403821 | |
473 | +#define ASM_ORI_A0_ZERO_ 0x34040000 | |
474 | +#define ASM_LW_A0_XXXX_S8 0x8FC40000 | |
475 | +#define ASM_LW_A0_XXXX_S5 0x8EA40000 | |
476 | + | |
362 | 477 | // Division macro for unsigned long |
363 | 478 | // Valid for 31 bits for all cases and 32 bits for some cases |
364 | 479 | #define div32(x,y,z) ((((unsigned long long)((unsigned long)(x)))*((unsigned long long)((unsigned long)(y))))>>(z)) |
@@ -374,3 +489,6 @@ | ||
374 | 489 | // Divide by 36 (valid for 32 bits) |
375 | 490 | #define div36_32(x) div32(x,0xe38e38e4,37) |
376 | 491 | #define rem36_32(x) (x-36*div36_32(x)) |
492 | + | |
493 | +// Check if within RAM | |
494 | +#define withinRAM(x) ((&RAM[0])<=((char*)(x)) && ((char*)(x))<(&RAM[RAMSIZE])) |
@@ -32,6 +32,8 @@ | ||
32 | 32 | |
33 | 33 | static const char initext[]; |
34 | 34 | static const char bastext[]; |
35 | +static const char class1text[]; | |
36 | +static const char class2text[]; | |
35 | 37 | |
36 | 38 | static char* readtext; |
37 | 39 | static int filepos; |
@@ -129,8 +131,15 @@ | ||
129 | 131 | // INI file |
130 | 132 | readtext=(char*)&initext[0]; |
131 | 133 | } else if (fileName[i+1]=='B' && fileName[i+2]=='A' && fileName[i+3]=='S') { |
132 | - // BAS file | |
133 | - readtext=(char*)&bastext[0]; | |
134 | + // Select BAS file | |
135 | + if (fileName[i-6]=='C' && fileName[i-5]=='L' && fileName[i-4]=='A' && | |
136 | + fileName[i-3]=='S' && fileName[i-2]=='S') { | |
137 | + if (fileName[i-1]=='1') readtext=(char*)&class1text[0]; | |
138 | + else if (fileName[i-1]=='2') readtext=(char*)&class2text[0]; | |
139 | + else readtext=(char*)&bastext[0]; | |
140 | + } else { | |
141 | + readtext=(char*)&bastext[0]; | |
142 | + } | |
134 | 143 | // Try debugDump. |
135 | 144 | if (debugDump()) return 0; |
136 | 145 | } else { |
@@ -218,29 +227,60 @@ | ||
218 | 227 | "#PRINT\n" |
219 | 228 | "#PRINT\n"; |
220 | 229 | |
221 | - | |
222 | 230 | static const char bastext[]= |
223 | -"I2C 100\n" | |
224 | -"DIM D(5)\n" | |
225 | -"T$=\"Hello MachiKania!\"\n" | |
226 | -"I2CREADDATA 0x50,D,18,0x00,0x00\n" | |
227 | -"PRINT I2CERROR()\n" | |
228 | -"PRINT D$\n" | |
229 | -"I2CWRITEDATA 0x50,T,18,0x00,0x00\n" | |
230 | -"PRINT I2CERROR()\n" | |
231 | -"WAIT 60\n" | |
232 | -"I2CREADDATA 0x50,D,18,0x00,0x00\n" | |
231 | +"print getdir$()\n" | |
232 | +"end\n" | |
233 | 233 | "\n" |
234 | +"\n" | |
235 | +"\n" | |
236 | +"\n" | |
237 | +"\n" | |
234 | 238 | "\n"; |
235 | 239 | |
240 | +static const char class1text[]= | |
241 | +"STATIC T1\n" | |
242 | +"useclass CLASS2\n" | |
243 | +"method T3\n" | |
244 | +" return CLASS2::T2\n" | |
245 | +"method T5\n" | |
246 | +" return T1\n" | |
247 | +"\n" | |
248 | +"\n"; | |
249 | + | |
250 | +static const char class2text[]= | |
251 | +"STATIC T2\n" | |
252 | +"useclass CLASS1\n" | |
253 | +"method T4\n" | |
254 | +" return CLASS1::T1\n" | |
255 | +"method T6\n" | |
256 | +" return T2\n" | |
257 | +"\n" | |
258 | +"\n" | |
259 | +"\n" | |
260 | +"\n"; | |
261 | + | |
236 | 262 | /* |
237 | 263 | Test function for constructing assemblies from C codes. |
238 | 264 | */ |
239 | 265 | |
266 | +static const void* debugjumptable[]={ | |
267 | + FSfread, | |
268 | + FSfopen, | |
269 | +}; | |
270 | + | |
240 | 271 | int _debug_test(int a0, int a1, int a2, int a3, int param4, int param5){ |
241 | -// if (a0<0xa0008192) return 0xa0000000; | |
242 | - asm volatile("lw $sp,18($fp)"); | |
243 | - asm volatile("addiu $sp,$sp,2044"); | |
272 | + asm volatile(".set noreorder"); | |
273 | + asm volatile("lw $a0,4($s5)"); | |
274 | + asm volatile("lw $a1,8($s5)"); | |
275 | + asm volatile("lw $a2,12($s5)"); | |
276 | + asm volatile("lw $a3,16($s5)"); | |
277 | + asm volatile("nop"); | |
278 | + asm volatile("nop"); | |
279 | + asm volatile("nop"); | |
280 | + asm volatile("nop"); | |
281 | + asm volatile("nop"); | |
282 | + asm volatile("nop"); | |
283 | + asm volatile("nop"); | |
244 | 284 | return a2+a3; |
245 | 285 | } |
246 | 286 |
@@ -5,6 +5,10 @@ | ||
5 | 5 | http://hp.vector.co.jp/authors/VA016157/ |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #ifdef __DEBUG |
9 | 13 | |
10 | 14 | // Pseudo reading config setting for debug mode |
@@ -107,7 +107,7 @@ | ||
107 | 107 | return; |
108 | 108 | } else { |
109 | 109 | // Clear previous area here |
110 | - free_temp_str((char*)g_graphic_area); | |
110 | + free_non_temp_str((char*)g_graphic_area); | |
111 | 111 | g_graphic_area=0; |
112 | 112 | } |
113 | 113 | } |
@@ -5,6 +5,10 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include "compiler.h" |
9 | 13 | |
10 | 14 | const char* g_err_str[]={ |
@@ -30,6 +34,13 @@ | ||
30 | 34 | "File error", |
31 | 35 | "Invalid variable name", |
32 | 36 | "WAVE format error", |
37 | + "ERR_COMPILE_CLASS", | |
38 | + "Class not found", | |
39 | + "Not an object", | |
40 | + " is not public field/method", | |
41 | + "Valid only in class file", | |
42 | + "Invalid in class file", | |
43 | + "INIT method does not exist", | |
33 | 44 | }; |
34 | 45 | |
35 | 46 | char* resolve_label(int s6){ |
@@ -168,3 +179,20 @@ | ||
168 | 179 | end_exec(); |
169 | 180 | } |
170 | 181 | |
182 | +void err_not_obj(void){ | |
183 | + printstr(ERR_NOT_OBJ); | |
184 | + end_exec(); | |
185 | +} | |
186 | + | |
187 | +void err_not_field(int fieldname, int classname){ | |
188 | + printstr(resolve_label(classname)); | |
189 | + printchar('.'); | |
190 | + printstr(resolve_label(fieldname & 0x7FFFFFFF)); | |
191 | + printstr(ERR_NOT_FIELD); | |
192 | + end_exec(); | |
193 | +} | |
194 | + | |
195 | +void err_str(char* str){ | |
196 | + printstr(str); | |
197 | + end_exec(); | |
198 | +} | |
\ No newline at end of file |
@@ -5,6 +5,10 @@ | ||
5 | 5 | http://hp.vector.co.jp/authors/VA016157/ |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include <xc.h> |
9 | 13 | #include "api.h" |
10 | 14 | #include "main.h" |
@@ -5,6 +5,10 @@ | ||
5 | 5 | http://hp.vector.co.jp/authors/VA016157/ |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include <xc.h> |
9 | 13 | #include "api.h" |
10 | 14 | #include "compiler.h" |
@@ -19,9 +23,12 @@ | ||
19 | 23 | if (!g_fhandle) { |
20 | 24 | return ERR_UNKNOWN; |
21 | 25 | } |
26 | + // Initialize parameters | |
22 | 27 | g_fbuff=buff; |
23 | 28 | g_line=0; |
24 | 29 | g_fileline=0; |
30 | + g_source=buff; | |
31 | + g_srcpos=0; | |
25 | 32 | return 0; |
26 | 33 | } |
27 | 34 |
@@ -88,7 +95,11 @@ | ||
88 | 95 | if (err) return err; |
89 | 96 | } |
90 | 97 | // Add "DATA 0" and "END" statements. |
91 | - g_source="DATA 0:END\n"; | |
98 | + if (g_compiling_class) { | |
99 | + g_source="END\n"; | |
100 | + } else { | |
101 | + g_source="DATA 0:END\n"; | |
102 | + } | |
92 | 103 | g_srcpos=0; |
93 | 104 | err=compile_line(); |
94 | 105 | if (err) return err; |
@@ -97,3 +108,165 @@ | ||
97 | 108 | return 0; |
98 | 109 | } |
99 | 110 | |
111 | +int compile_and_link_file(char* buff,char* appname){ | |
112 | + int i,j; | |
113 | + char* err; | |
114 | + | |
115 | + while(1){ | |
116 | + // Initialize SD card file system | |
117 | + err=init_file(buff,appname); | |
118 | + if (err) { | |
119 | + //setcursorcolor(COLOR_ERRORTEXT); | |
120 | + printstr("Can't Open "); | |
121 | + printstr(appname); | |
122 | + printchar('\n'); | |
123 | + return -1; | |
124 | + } | |
125 | + | |
126 | + // Compile the file | |
127 | + err=compile_file(); | |
128 | + close_file(); | |
129 | + | |
130 | + // If compiling a class file is required, do it. | |
131 | + if (err==ERR_COMPILE_CLASS) { | |
132 | + j=g_compiling_class; | |
133 | + i=compile_and_link_class(buff, g_class); | |
134 | + g_compiling_class=j; | |
135 | + if (i) return i; | |
136 | + // Continue compiling current file from the beginning. | |
137 | + continue; | |
138 | + } | |
139 | + break; | |
140 | + } | |
141 | + | |
142 | + if (err) { | |
143 | + // Compile error | |
144 | + printstr(err); | |
145 | + printstr("\nAround: '"); | |
146 | + for(i=0;i<5;i++){ | |
147 | + printchar(g_source[g_srcpos-2+i]); | |
148 | + } | |
149 | + printstr("' in line "); | |
150 | + printdec(g_line); | |
151 | + printstr("\n"); | |
152 | + for(i=g_srcpos;0x20<=g_source[i];i++); | |
153 | + g_source[i]=0x00; | |
154 | + for(i=g_srcpos;0x20<=g_source[i];i--); | |
155 | + printstr(g_source+i); | |
156 | + return g_fileline; | |
157 | + } | |
158 | + | |
159 | + // Link | |
160 | + err=link(); | |
161 | + if (err) { | |
162 | + // Link error | |
163 | + printstr(err); | |
164 | + printstr(resolve_label(g_label)); | |
165 | + return -2; | |
166 | + } | |
167 | + | |
168 | + // All done | |
169 | + return 0; | |
170 | +} | |
171 | + | |
172 | +int compile_and_link_class(char* buff,int class){ | |
173 | + int i,j; | |
174 | + char* err; | |
175 | + char* classname; | |
176 | + char classfile[13]; | |
177 | + char classdir[11]; | |
178 | + int data[2]; | |
179 | + unsigned short cwd_id; | |
180 | + int* record; | |
181 | + while(1){ | |
182 | + // Begin compiling class | |
183 | + err=begin_compiling_class(class); | |
184 | + if (err) break; | |
185 | + // Determine class file name | |
186 | + classname=resolve_label(class); | |
187 | + for(i=0;classfile[i]=classname[i];i++); | |
188 | + classfile[i++]='.'; | |
189 | + classfile[i++]='B'; | |
190 | + classfile[i++]='A'; | |
191 | + classfile[i++]='S'; | |
192 | + classfile[i]=0; | |
193 | + // Check if file exists in current directory | |
194 | + err=init_file(buff,&classfile[0]); | |
195 | + if (!err) { | |
196 | + // Class file found in current directory | |
197 | + close_file(); | |
198 | + // Compile it | |
199 | + i=compile_and_link_file(buff,&classfile[0]); | |
200 | + if (i) break; | |
201 | + } else { | |
202 | + // Class file not found in current directory. | |
203 | + // Try library directory, for example, \LIB\CLASS1\CLASS1.BAS | |
204 | + // Store current directory, first | |
205 | + if (!FSgetcwd(buff,256)) break; | |
206 | + for(i=0;buff[i];i++); | |
207 | + cwd_id=cmpdata_get_id(); | |
208 | + if (!cwd_id) break; | |
209 | + err=cmpdata_insert(CMPDATA_TEMP,cwd_id,(int*)(&buff[0]),(i+1+3)>>2); | |
210 | + if (err) break; | |
211 | + // Change current directory to class library directory | |
212 | + for(i=0;classdir[i]="\\LIB\\"[i];i++); | |
213 | + for(j=0;classdir[i++]=classname[j];j++); | |
214 | + classdir[i]=0; | |
215 | + FSchdir(classdir); | |
216 | + // Compile class file | |
217 | + i=compile_and_link_file(buff,&classfile[0]); | |
218 | + // Restore current dirctory | |
219 | + cmpdata_reset(); | |
220 | + while(record=cmpdata_find(CMPDATA_TEMP)){ | |
221 | + if (cwd_id=(record[0]&0xffff)) break; | |
222 | + } | |
223 | + if (!record) break; | |
224 | + FSchdir((char*)(&record[1])); | |
225 | + cmpdata_delete(record); | |
226 | + if (i) break; | |
227 | + } | |
228 | + // End compiling class | |
229 | + err=end_compiling_class(class); | |
230 | + if (err) break; | |
231 | + // Initial assembly is a jump statement to jump to the end of class file | |
232 | + // Note that there is at least a code (set line # to $s6) before reaching here | |
233 | + g_object[0]=0x08000000 | ((((int)(&g_object[g_objpos]))&0x0FFFFFFF)>>2); // j xxxxxxxx | |
234 | + // In the next link, current region of object is ignored. | |
235 | + g_object+=g_objpos; | |
236 | + g_objpos=0; | |
237 | + // All done | |
238 | + return 0; | |
239 | + } | |
240 | + // Error occured | |
241 | + printstr("/nError in class: "); | |
242 | + printstr((char*)&classfile[0]); | |
243 | + printchar('\n'); | |
244 | + if (err) printstr(err); | |
245 | + return -2; | |
246 | +} | |
247 | + | |
248 | +int compile_and_link_main_file(char* buff,char* appname){ | |
249 | + int i; | |
250 | + g_compiling_class=0; | |
251 | + i=compile_and_link_file(buff,appname); | |
252 | + if (i) return i; | |
253 | + return 0; | |
254 | + /* | |
255 | + After compiling class code, g_object is set to the beginning of next code. | |
256 | + Therefore, after the all, g_object is set toe the beginnig of main code, | |
257 | + and class code(s) is/are excluded. This will affect following features when running: | |
258 | + READ/DATA/RESTORE function/statements | |
259 | + The linker also works withing the g_object dimension. Therefore, the label only works withing the file, | |
260 | + but not in the other file. This feature allows using the same label name in different files without | |
261 | + causing error/misjumping | |
262 | + | |
263 | + After compiling class code, following cmpdata are destroyed (see delete_cmpdata_for_class() function): | |
264 | + CMPDATA_FIELD : object field and method information | |
265 | + CMPDATA_USEVAR : long var name information | |
266 | + but following cmpdata remains: | |
267 | + CMPDATA_CLASS : class name and address of class structure | |
268 | + This feature allows compiler to use class information (name and structure) for "NEW" function, | |
269 | + to use the same long var name in different files (note that g_long_name_var_num is not reseted after | |
270 | + compiling each class code). | |
271 | + */ | |
272 | +} | |
\ No newline at end of file |
@@ -1,3 +1,14 @@ | ||
1 | +/* | |
2 | + This file is provided under the LGPL license ver 2.1. | |
3 | + Written by Katsumi. | |
4 | + http://hp.vector.co.jp/authors/VA016157/ | |
5 | + kmorimatsu@users.sourceforge.jp | |
6 | +*/ | |
7 | + | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
1 | 12 | #include "./compiler.h" |
2 | 13 | #include "stdlib.h" |
3 | 14 |
@@ -57,6 +68,21 @@ | ||
57 | 68 | // Must be a function. |
58 | 69 | return float_function(); |
59 | 70 | } |
71 | + if (g_source[g_srcpos]=='.') { | |
72 | + // This is an object field or method to return string | |
73 | + check_obj_space(1); | |
74 | + g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
75 | + g_srcpos++; | |
76 | + return float_obj_field(); | |
77 | + } else if (g_source[g_srcpos]=='(') { | |
78 | + // An array element contains pointer to an object. | |
79 | + g_srcpos++; | |
80 | + err=get_dim_value(i); | |
81 | + if (err) return err; | |
82 | + if (g_source[g_srcpos]!='.') return ERR_SYNTAX; | |
83 | + g_srcpos++; | |
84 | + return float_obj_field(); | |
85 | + } | |
60 | 86 | if (g_source[g_srcpos]!='#') return ERR_SYNTAX; |
61 | 87 | g_srcpos++; |
62 | 88 | if (g_source[g_srcpos]=='(') { |
@@ -122,7 +148,7 @@ | ||
122 | 148 | prevpos=g_objpos; |
123 | 149 | // Stack decrement command will be filled later |
124 | 150 | check_obj_space(1); |
125 | - g_objpos++; | |
151 | + g_object[g_objpos++]=0x00000000; // nop (will be replaced by "addiu sp,sp,-xx") | |
126 | 152 | } |
127 | 153 | err=get_float_sub(priority(OP_VOID)); |
128 | 154 | if (err) return err; |
@@ -129,8 +155,10 @@ | ||
129 | 155 | if (g_sdepth==0) { |
130 | 156 | if (g_maxsdepth==0) { |
131 | 157 | // Stack was not used. |
132 | - shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
133 | - g_objpos--; | |
158 | + if (g_allow_shift_obj) { | |
159 | + shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
160 | + g_objpos--; | |
161 | + } | |
134 | 162 | } else { |
135 | 163 | // Stack was used. |
136 | 164 | check_obj_space(1); |
@@ -5,6 +5,10 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include "compiler.h" |
9 | 13 | #include "api.h" |
10 | 14 |
@@ -23,6 +27,8 @@ | ||
23 | 27 | } |
24 | 28 | |
25 | 29 | char* read_function(){ |
30 | + // This function is not valid in class file. | |
31 | + if (g_compiling_class) return ERR_INVALID_CLASS; | |
26 | 32 | call_lib_code(LIB_READ); |
27 | 33 | return 0; |
28 | 34 | } |
@@ -92,12 +98,23 @@ | ||
92 | 98 | return 0; |
93 | 99 | } |
94 | 100 | |
95 | -char* peek_function(){ | |
101 | +char* peek_function_sub(int bits){ | |
96 | 102 | char* err; |
97 | 103 | err=get_value(); |
98 | 104 | if (err) return err; |
99 | 105 | check_obj_space(1); |
100 | - g_object[g_objpos++]=0x90420000; // lbu v0,0(v0) | |
106 | + switch(bits){ | |
107 | + case 32: | |
108 | + g_object[g_objpos++]=0x8C420000; // lw v0,0(v0) | |
109 | + break; | |
110 | + case 16: | |
111 | + g_object[g_objpos++]=0x94420000; // lhu v0,0(v0) | |
112 | + break; | |
113 | + case 8: | |
114 | + default: | |
115 | + g_object[g_objpos++]=0x90420000; // lbu v0,0(v0) | |
116 | + break; | |
117 | + } | |
101 | 118 | return 0; |
102 | 119 | } |
103 | 120 |
@@ -244,23 +261,7 @@ | ||
244 | 261 | } |
245 | 262 | |
246 | 263 | char* args_function(void){ |
247 | - char* err; | |
248 | - int i; | |
249 | - err=get_value(); | |
250 | - if (err) return err; | |
251 | - i=g_object[g_objpos-1]; | |
252 | - if ((i>>16)==0x3402) { | |
253 | - // Previous object is "ori v0,zero,xxxx". | |
254 | - i&=0xffff; | |
255 | - i=(i+1)<<2; | |
256 | - g_object[g_objpos-1]=0x8EA20000|i; // lw v0,xx(s5) | |
257 | - } else { | |
258 | - check_obj_space(3); | |
259 | - g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
260 | - g_object[g_objpos++]=0x02A21021; // addu v0,s5,v0 | |
261 | - g_object[g_objpos++]=0x8C420004; // lw v0,4(v0) | |
262 | - } | |
263 | - return 0; | |
264 | + return args_function_main(); | |
264 | 265 | } |
265 | 266 | |
266 | 267 | char* system_function(void){ |
@@ -378,6 +379,19 @@ | ||
378 | 379 | return 0; |
379 | 380 | } |
380 | 381 | |
382 | +char* setdir_function(){ | |
383 | + char* err; | |
384 | + err=get_string(); | |
385 | + if (err) return err; | |
386 | + call_lib_code(LIB_SETDIRFUNC); | |
387 | + return 0; | |
388 | +} | |
389 | + | |
390 | +char* getdir_function(){ | |
391 | + call_lib_code(LIB_GETDIR); | |
392 | + return 0; | |
393 | +} | |
394 | + | |
381 | 395 | char* float_constant(float val){ |
382 | 396 | volatile int i; |
383 | 397 | ((float*)(&i))[0]=val; |
@@ -475,7 +489,9 @@ | ||
475 | 489 | } else if (nextCodeIs("PI#")) { |
476 | 490 | return float_constant(3.141593); |
477 | 491 | } else { |
478 | - return ERR_SYNTAX; | |
492 | + // Check if static method of a class | |
493 | + err=static_method('#'); | |
494 | + //return ERR_SYNTAX; | |
479 | 495 | } |
480 | 496 | if (err) return err; |
481 | 497 | if (g_source[g_srcpos]!=')') return ERR_SYNTAX; |
@@ -495,6 +511,7 @@ | ||
495 | 511 | "FLOAT$(",floatstr_function, |
496 | 512 | "SYSTEM$(",system_function, |
497 | 513 | "FINPUT$(",finput_function, |
514 | + "GETDIR$(",getdir_function, | |
498 | 515 | // Additional functions follow |
499 | 516 | ADDITIONAL_STR_FUNCTIONS |
500 | 517 | }; |
@@ -512,7 +529,9 @@ | ||
512 | 529 | f=str_func_list[i+1]; |
513 | 530 | err=f(); |
514 | 531 | } else { |
515 | - return ERR_SYNTAX; | |
532 | + // Check if static method of a class | |
533 | + err=static_method('$'); | |
534 | + //return ERR_SYNTAX; | |
516 | 535 | } |
517 | 536 | if (err) return err; |
518 | 537 | if (g_source[g_srcpos]!=')') return ERR_SYNTAX; |
@@ -522,6 +541,18 @@ | ||
522 | 541 | |
523 | 542 | // Aliases follow |
524 | 543 | |
544 | +char* peek_function(){ | |
545 | + return peek_function_sub(8); | |
546 | +} | |
547 | + | |
548 | +char* peek16_function(){ | |
549 | + return peek_function_sub(16); | |
550 | +} | |
551 | + | |
552 | +char* peek32_function(){ | |
553 | + return peek_function_sub(32); | |
554 | +} | |
555 | + | |
525 | 556 | char* gcolor_function(){ |
526 | 557 | return graphic_statement(FUNC_GCOLOR); |
527 | 558 | } |
@@ -541,6 +572,8 @@ | ||
541 | 572 | "GOSUB(",gosub_function, |
542 | 573 | "STRNCMP(",strncmp_function, |
543 | 574 | "PEEK(",peek_function, |
575 | + "PEEK16(",peek16_function, | |
576 | + "PEEK32(",peek32_function, | |
544 | 577 | "LEN(",len_function, |
545 | 578 | "ASC(",asc_function, |
546 | 579 | "SGN(",sgn_function, |
@@ -562,6 +595,8 @@ | ||
562 | 595 | "FREMOVE(",fremove_statement, |
563 | 596 | "FEOF(",feof_function, |
564 | 597 | "PLAYWAVE(",playwave_function, |
598 | + "NEW(",new_function, | |
599 | + "SETDIR(",setdir_function, | |
565 | 600 | // Additional functions follow |
566 | 601 | ADDITIONAL_INT_FUNCTIONS |
567 | 602 | }; |
@@ -579,7 +614,9 @@ | ||
579 | 614 | f=int_func_list[i+1]; |
580 | 615 | err=f(); |
581 | 616 | } else { |
582 | - return ERR_SYNTAX; | |
617 | + // Check if static method of a class | |
618 | + err=static_method(0); | |
619 | + //return ERR_SYNTAX; | |
583 | 620 | } |
584 | 621 | if (err) return err; |
585 | 622 | if (g_source[g_srcpos]!=')') return ERR_SYNTAX; |
@@ -5,6 +5,10 @@ | ||
5 | 5 | http://hp.vector.co.jp/authors/VA016157/ |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include "compiler.h" |
9 | 13 | #include "main.h" |
10 | 14 |
@@ -24,6 +28,7 @@ | ||
24 | 28 | // handling values and strings. |
25 | 29 | int g_sdepth; |
26 | 30 | int g_maxsdepth; |
31 | +char g_allow_shift_obj; | |
27 | 32 | |
28 | 33 | // Following var shows what type of variable was defined |
29 | 34 | // in compiling the last code. |
@@ -75,5 +80,10 @@ | ||
75 | 80 | // Number of long name variables |
76 | 81 | int g_long_name_var_num; |
77 | 82 | |
83 | +// Class name being compiled | |
84 | +int g_class; | |
85 | +// Flag to compile class file | |
86 | +int g_compiling_class; | |
87 | + | |
78 | 88 | // General purpose integer used for asigning value with pointer |
79 | 89 | int g_temp; |
@@ -57,13 +57,13 @@ | ||
57 | 57 | IEC1bits.U1TXIE=0; |
58 | 58 | IEC1bits.U1RXIE=0; |
59 | 59 | // Free buffer area |
60 | - if (g_serial_buff) free_temp_str((char*)g_serial_buff); | |
60 | + if (g_serial_buff) free_non_temp_str((char*)g_serial_buff); | |
61 | 61 | g_serial_buff=0; |
62 | 62 | } else { |
63 | 63 | // Prepare buffer for SERIALIN |
64 | 64 | if (bsize==0) bsize=baud/400; // Area corresponds to ~1/40 sec (> 1/60 sec) |
65 | 65 | g_serial_buff_size=bsize; |
66 | - if (g_serial_buff) free_temp_str((char*)g_serial_buff); | |
66 | + if (g_serial_buff) free_non_temp_str((char*)g_serial_buff); | |
67 | 67 | g_serial_buff=(short*)alloc_memory((bsize+1)/2,get_permanent_var_num()); |
68 | 68 | g_serial_buff_read_pos=g_serial_buff_write_pos=0; |
69 | 69 | // Initialize I/O ports |
@@ -5,6 +5,10 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include <xc.h> |
9 | 13 | #include "main.h" |
10 | 14 | #include "compiler.h" |
@@ -21,6 +25,20 @@ | ||
21 | 25 | static int g_prev_x=0; |
22 | 26 | static int g_prev_y=0; |
23 | 27 | |
28 | +int lib_setdir(int mode,char* path){ | |
29 | + int ret; | |
30 | + ret=FSchdir(path); | |
31 | + if (mode==LIB_SETDIR && ret) err_file(); | |
32 | + return ret; | |
33 | +} | |
34 | + | |
35 | +int lib_getdir(){ | |
36 | + char* path; | |
37 | + path=calloc_memory(32,-1); | |
38 | + FSgetcwd (path,128); | |
39 | + return (int)path; | |
40 | +} | |
41 | + | |
24 | 42 | int lib_read(int mode, unsigned int label){ |
25 | 43 | unsigned int i,code,code2; |
26 | 44 | static unsigned int pos=0; |
@@ -405,7 +423,7 @@ | ||
405 | 423 | case 2: |
406 | 424 | // Reset PCG and use it |
407 | 425 | if (g_pcg_font) { |
408 | - free_temp_str(g_pcg_font); | |
426 | + free_non_temp_str(g_pcg_font); | |
409 | 427 | g_pcg_font=0; |
410 | 428 | } |
411 | 429 | // Continue to case 1: |
@@ -1012,6 +1030,11 @@ | ||
1012 | 1030 | case LIB_SETDRAWCOUNT: |
1013 | 1031 | drawcount=(v0&0x0000FFFF); |
1014 | 1032 | return v0; |
1033 | + case LIB_GETDIR: | |
1034 | + return lib_getdir(); | |
1035 | + case LIB_SETDIRFUNC: | |
1036 | + case LIB_SETDIR: | |
1037 | + return lib_setdir(a3,(char*)v0); | |
1015 | 1038 | case LIB_DRAWCOUNT: |
1016 | 1039 | return drawcount; |
1017 | 1040 | case LIB_SYSTEM: |
@@ -5,6 +5,10 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include "compiler.h" |
9 | 13 | |
10 | 14 | unsigned int g_label; |
@@ -7,8 +7,8 @@ | ||
7 | 7 | |
8 | 8 | #define MEGALOPA |
9 | 9 | #define SYSVER1 "Megalopa" |
10 | -#define SYSVER2 "1.1" | |
11 | -#define BASVER "KM-1301" | |
10 | +#define SYSVER2 "1.2" | |
11 | +#define BASVER "KM-1302" | |
12 | 12 | |
13 | 13 | #define INIFILE "MACHIKAM.INI" // 初期設定ファイル |
14 | 14 | #define HEXFILE "MACHIKAM.HEX" // 実行中HEXファイル名がこれと一致した場合はエディタ起動 |
@@ -5,6 +5,10 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include "compiler.h" |
9 | 13 | |
10 | 14 | /* |
@@ -13,17 +17,35 @@ | ||
13 | 17 | This number also includes temporary area used for string construction etc. |
14 | 18 | Temporary area is cleared every line of BASIC code in alloc_memory(). |
15 | 19 | ALLOC_BLOCK_NUM: # of blocks that can be used for memory allocation. |
16 | - This # also includes the ones for ALLOC_VAR_NUM. | |
20 | + This # includes the ones for ALLOC_VAR_NUM, ALLOC_PCG_BLOCK etc, ALLOC_LNV_BLOCK, | |
21 | + ALLOC_PERM_BLOCK. | |
17 | 22 | After ALLOC_VAR_NUM area, dedicated memory area and permanent area follows. |
18 | - Currently, only PCG is used for permanent pourpose. | |
19 | - 10 permanant blocks can be used. | |
20 | - Therefore, ALLOC_VAR_NUM+11 == ALLOC_BLOCK_NUM | |
21 | 23 | ALLOC_PERM_BLOCK: Start # of permanent blocks. |
22 | 24 | The blocks after this number is permanently stored. |
23 | 25 | Therefore, it must be released when it's not used any more. |
24 | 26 | */ |
25 | 27 | |
28 | +static int g_temp_var_num_candidate=ALLOC_PERM_BLOCK; | |
29 | + | |
30 | +#define DELETE_LIST_SIZE 10 | |
31 | +static int g_deleted_num; | |
32 | +static int g_deleted_pointer[DELETE_LIST_SIZE]; | |
33 | +static int g_deleted_size[DELETE_LIST_SIZE]; | |
34 | + | |
35 | +void register_deleted_block(int pointer, int size){ | |
36 | + // There is maximum | |
37 | + if (DELETE_LIST_SIZE<=g_deleted_num) return; | |
38 | + if (g_deleted_num) { | |
39 | + // Avoid duplication | |
40 | + if (g_deleted_pointer[g_deleted_num-1]==pointer) return; | |
41 | + } | |
42 | + g_deleted_pointer[g_deleted_num]=pointer; | |
43 | + g_deleted_size[g_deleted_num]=size; | |
44 | + g_deleted_num++; | |
45 | +} | |
46 | + | |
26 | 47 | void set_free_area(void* begin, void* end){ |
48 | + // Initialize heap area | |
27 | 49 | int i; |
28 | 50 | for(i=0;i<ALLOC_BLOCK_NUM;i++){ |
29 | 51 | g_var_size[i]=0; |
@@ -30,6 +52,7 @@ | ||
30 | 52 | } |
31 | 53 | g_heap_mem=(int*)begin; |
32 | 54 | g_max_mem=(int)((end-begin)/4); |
55 | + g_deleted_num=0; | |
33 | 56 | } |
34 | 57 | |
35 | 58 | void* calloc_memory(int size, int var_num){ |
@@ -85,6 +108,24 @@ | ||
85 | 108 | g_var_size[var_num]=0; |
86 | 109 | g_var_pointer[var_num]=0; |
87 | 110 | while(1){ |
111 | + // Try the block previously deleted, not for temporary block. | |
112 | + // This is for fast allocation of memory for class object. | |
113 | + if (var_num<26 || ALLOC_VAR_NUM<=var_num) { | |
114 | + candidate=0; | |
115 | + while(g_deleted_num){ | |
116 | + // Check if the last deleted block fits | |
117 | + // If not, these cannot be used anymore | |
118 | + g_deleted_num--; | |
119 | + if (size<=g_deleted_size[g_deleted_num]) { | |
120 | + candidate=g_deleted_pointer[g_deleted_num]; | |
121 | + break; | |
122 | + } | |
123 | + } | |
124 | + if (candidate || g_deleted_num) { | |
125 | + // Candidate found | |
126 | + break; | |
127 | + } | |
128 | + } | |
88 | 129 | // Try the block after last block |
89 | 130 | candidate=0; |
90 | 131 | for(i=0;i<ALLOC_BLOCK_NUM;i++){ |
@@ -93,7 +134,29 @@ | ||
93 | 134 | candidate=g_var_pointer[i]+g_var_size[i]; |
94 | 135 | } |
95 | 136 | } |
96 | - if (candidate+size<=g_max_mem) break; | |
137 | + if (candidate+size<=g_max_mem) { | |
138 | + // Check after deleted block | |
139 | + j=candidate; | |
140 | + for(i=0;i<g_deleted_num;i++){ | |
141 | + if (j<g_deleted_pointer[i]+g_deleted_size[i]) { | |
142 | + j=g_deleted_pointer[i]+g_deleted_size[i]; | |
143 | + } | |
144 | + } | |
145 | + if (j+size<=g_max_mem) { | |
146 | + // Candidate block found after previously deleted blokcs | |
147 | + candidate=j; | |
148 | + break; | |
149 | + } else { | |
150 | + // Candidate is before previously deleted blocks, | |
151 | + // and there is no candidate block after previously deleted blocks. | |
152 | + // Therefore, use the current candidate, which may invade previously | |
153 | + // deleted blocks. Therefore, erase the previously deleted blocks list. | |
154 | + g_deleted_num=0; | |
155 | + break; | |
156 | + } | |
157 | + } | |
158 | + // Peviously deleted blocks cannot be used any more | |
159 | + g_deleted_num=0; | |
97 | 160 | // Check between blocks |
98 | 161 | // Note that there is at least one block with zero pointer and zero size (see above). |
99 | 162 | for(i=0;i<ALLOC_BLOCK_NUM;i++){ |
@@ -132,21 +195,64 @@ | ||
132 | 195 | if (!str) return; |
133 | 196 | pointer=(int)str-(int)g_heap_mem; |
134 | 197 | pointer>>=2; |
135 | - for(i=0;i<ALLOC_BLOCK_NUM;i++){ | |
198 | + for(i=26;i<ALLOC_VAR_NUM;i++){ | |
136 | 199 | if (g_var_pointer[i]==pointer) { |
137 | - g_var_size[i]=0; | |
138 | - break; | |
200 | + if (g_var_size[i] && g_var_mem[i]==(int)str) { | |
201 | + register_deleted_block(pointer,g_var_size[i]); | |
202 | + g_var_size[i]=0; | |
203 | + } | |
139 | 204 | } |
140 | 205 | } |
141 | 206 | } |
142 | 207 | |
208 | +void free_non_temp_str(char* str){ | |
209 | + int i,pointer; | |
210 | + if (!str) return; | |
211 | + pointer=(int)str-(int)g_heap_mem; | |
212 | + pointer>>=2; | |
213 | + for(i=0;i<26;i++){ | |
214 | + if (g_var_pointer[i]==pointer) { | |
215 | + if (g_var_size[i] && g_var_mem[i]==(int)str) { | |
216 | + register_deleted_block(pointer,g_var_size[i]); | |
217 | + g_var_size[i]=0; | |
218 | + g_var_mem[i]=0; | |
219 | + } | |
220 | + } | |
221 | + } | |
222 | + for(i=ALLOC_VAR_NUM;i<ALLOC_BLOCK_NUM;i++){ | |
223 | + if (g_var_pointer[i]==pointer) { | |
224 | + if (g_var_size[i] && g_var_mem[i]==(int)str) { | |
225 | + register_deleted_block(pointer,g_var_size[i]); | |
226 | + g_var_size[i]=0; | |
227 | + g_var_mem[i]=0; | |
228 | + if (ALLOC_PERM_BLOCK<=i) g_temp_var_num_candidate=i; | |
229 | + } | |
230 | + } | |
231 | + } | |
232 | +} | |
233 | + | |
234 | +void free_perm_str(char* str){ | |
235 | + int i,pointer; | |
236 | + if (!str) return; | |
237 | + pointer=(int)str-(int)g_heap_mem; | |
238 | + pointer>>=2; | |
239 | + // Search permanent block and delete a block if found. | |
240 | + for(i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){ | |
241 | + if (g_var_pointer[i]==pointer) { | |
242 | + if (g_var_size[i] && g_var_mem[i]==(int)str) { | |
243 | + register_deleted_block(pointer,g_var_size[i]); | |
244 | + g_var_size[i]=0; | |
245 | + g_temp_var_num_candidate=i; | |
246 | + break; | |
247 | + } | |
248 | + } | |
249 | + } | |
250 | +} | |
251 | + | |
143 | 252 | void move_to_perm_block(int var_num){ |
144 | 253 | int i; |
145 | 254 | // Find available permanent block |
146 | - for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){ | |
147 | - if (g_var_size[i]==0) break; | |
148 | - } | |
149 | - if (ALLOC_BLOCK_NUM<=i) err_no_block(); // Not found | |
255 | + i=get_permanent_var_num(); | |
150 | 256 | // Available block found. |
151 | 257 | // Copy value from variable. |
152 | 258 | g_var_size[i]=g_var_size[var_num]; |
@@ -157,7 +263,7 @@ | ||
157 | 263 | g_var_mem[var_num]=0; |
158 | 264 | } |
159 | 265 | |
160 | -void move_from_perm_block(int var_num){ | |
266 | +int move_from_perm_block_if_exists(int var_num){ | |
161 | 267 | int i,pointer; |
162 | 268 | pointer=(int)g_var_mem[var_num]-(int)g_heap_mem; |
163 | 269 | pointer>>=2; |
@@ -165,7 +271,7 @@ | ||
165 | 271 | for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++){ |
166 | 272 | if (0<g_var_size[i] && g_var_pointer[i]==pointer) break; |
167 | 273 | } |
168 | - if (ALLOC_BLOCK_NUM<=i) err_unknown(); // Not found | |
274 | + if (ALLOC_BLOCK_NUM<=i) return 0; // Not found | |
169 | 275 | // Stored block found. |
170 | 276 | // Replace pointer |
171 | 277 | g_var_size[var_num]=g_var_size[i]; |
@@ -172,13 +278,50 @@ | ||
172 | 278 | g_var_pointer[var_num]=g_var_pointer[i]; |
173 | 279 | // Clear block |
174 | 280 | g_var_size[i]=0; |
281 | + g_temp_var_num_candidate=i; | |
282 | + return 1; | |
175 | 283 | } |
176 | 284 | |
285 | +void move_from_perm_block(int var_num){ | |
286 | + if (move_from_perm_block_if_exists(var_num)) return; // Found | |
287 | + err_unknown(); // Not found | |
288 | +} | |
289 | + | |
177 | 290 | int get_permanent_var_num(){ |
178 | 291 | int i; |
292 | + // Try candidate first | |
293 | + if (!g_var_size[g_temp_var_num_candidate]) { | |
294 | + if (ALLOC_PERM_BLOCK<g_temp_var_num_candidate && | |
295 | + g_temp_var_num_candidate<ALLOC_BLOCK_NUM) { | |
296 | + return g_temp_var_num_candidate++; | |
297 | + } | |
298 | + } | |
299 | + // Candidate is not available. Seek all. | |
179 | 300 | for (i=ALLOC_PERM_BLOCK;i<ALLOC_BLOCK_NUM;i++) { |
180 | - if (g_var_size[i]==0) return i; | |
301 | + if (g_var_size[i]==0) { | |
302 | + g_temp_var_num_candidate=i+1; | |
303 | + return i; | |
304 | + } | |
181 | 305 | } |
182 | 306 | err_no_block(); |
183 | 307 | return 0; |
184 | 308 | } |
309 | + | |
310 | +int get_varnum_from_address(void* address){ | |
311 | + int i; | |
312 | + for (i=0;i<ALLOC_BLOCK_NUM;i++){ | |
313 | + if (g_var_mem[i]==(int)address) return i; | |
314 | + } | |
315 | + // not found | |
316 | + return -1; | |
317 | +} | |
318 | + | |
319 | +void* lib_calloc_memory(int size){ | |
320 | + // Allocate memory and return address | |
321 | + return calloc_memory(size,get_permanent_var_num()); | |
322 | +} | |
323 | + | |
324 | +void lib_delete(int* object){ | |
325 | + // Remove region that fit to object | |
326 | + free_non_temp_str((char*)object); | |
327 | +} |
@@ -5,6 +5,10 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include "compiler.h" |
9 | 13 | |
10 | 14 | /* |
@@ -5,6 +5,10 @@ | ||
5 | 5 | http://hp.vector.co.jp/authors/VA016157/ |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include <xc.h> |
9 | 13 | #include "api.h" |
10 | 14 | #include "compiler.h" |
@@ -44,10 +48,8 @@ | ||
44 | 48 | |
45 | 49 | // Set grobal pointer |
46 | 50 | g_gp=get_gp(); |
47 | - // Set source positions | |
51 | + // Set buffer positions | |
48 | 52 | buff=(char*)&(RAM[RAMSIZE-512]); |
49 | - g_source=(char*)(&buff[0]); | |
50 | - g_srcpos=0; | |
51 | 53 | // Set object positions |
52 | 54 | g_object=(int*)(&RAM[0]); |
53 | 55 | g_objpos=0; |
@@ -54,7 +56,8 @@ | ||
54 | 56 | g_objmax=g_object+(RAMSIZE-512)/4; // Buffer area excluded. |
55 | 57 | // Clear object area |
56 | 58 | for(i=0;i<RAMSIZE/4;i++) g_object[i]=0x00000000; |
57 | - // Initialize SD card file system | |
59 | + | |
60 | + // Check file error | |
58 | 61 | err=init_file(buff,appname); |
59 | 62 | if (err) { |
60 | 63 | setcursorcolor(COLOR_ERRORTEXT); |
@@ -63,6 +66,7 @@ | ||
63 | 66 | printchar('\n'); |
64 | 67 | return -1; |
65 | 68 | } |
69 | + close_file(); | |
66 | 70 | |
67 | 71 | // Initialize parameters |
68 | 72 | g_pcg_font=0; |
@@ -82,34 +86,9 @@ | ||
82 | 86 | printstr("Compiling..."); |
83 | 87 | |
84 | 88 | // Compile the file |
85 | - err=compile_file(); | |
86 | - close_file(); | |
87 | - if (err) { | |
88 | - // Compile error | |
89 | - printstr(err); | |
90 | - printstr("\nAround: '"); | |
91 | - for(i=0;i<5;i++){ | |
92 | - printchar(g_source[g_srcpos-2+i]); | |
93 | - } | |
94 | - printstr("' in line "); | |
95 | - printdec(g_line); | |
96 | - printstr("\n"); | |
97 | - for(i=g_srcpos;0x20<=g_source[i];i++); | |
98 | - g_source[i]=0x00; | |
99 | - for(i=g_srcpos;0x20<=g_source[i];i--); | |
100 | - printstr(g_source+i); | |
101 | - return g_fileline; | |
102 | - } | |
89 | + i=compile_and_link_main_file(buff,appname); | |
90 | + if (i) return i; | |
103 | 91 | |
104 | - // Link | |
105 | - err=link(); | |
106 | - if (err) { | |
107 | - // Link error | |
108 | - printstr(err); | |
109 | - printstr(resolve_label(g_label)); | |
110 | - return -2; | |
111 | - } | |
112 | - | |
113 | 92 | // All done |
114 | 93 | printstr("done\n"); |
115 | 94 | if(test) return 0; //コンパイルのみの場合 |
@@ -1,1646 +1,1743 @@ | ||
1 | -/* | |
2 | - This file is provided under the LGPL license ver 2.1. | |
3 | - Written by Katsumi. | |
4 | - http://hp.vector.co.jp/authors/VA016157/ | |
5 | - kmorimatsu@users.sourceforge.jp | |
6 | -*/ | |
7 | - | |
8 | -#include "api.h" | |
9 | -#include "compiler.h" | |
10 | - | |
11 | -char* rem_statement(){ | |
12 | - if (g_source[g_srcpos-4]<0x20) { | |
13 | - // This line contains only "REM" statement | |
14 | - // Delete $s6-setting command if exists. | |
15 | - if ((g_object[g_objpos-1]&0xffff0000)==0x34160000) g_objpos--; | |
16 | - } | |
17 | - while(0x20<=g_source[g_srcpos]){ | |
18 | - g_srcpos++; | |
19 | - } | |
20 | - return 0; | |
21 | -} | |
22 | - | |
23 | -char* sound_statement(){ | |
24 | - char *err; | |
25 | - err=get_label(); | |
26 | - if (err) return err; | |
27 | - if (g_label) { | |
28 | - // Label/number is constant. | |
29 | - // Linker will change following codes later. | |
30 | - // Note that 0x0814xxxx and 0x0815xxxx are specific codes for these. | |
31 | - check_obj_space(2); | |
32 | - g_object[g_objpos++]=0x08140000|((g_label>>16)&0x0000FFFF); // lui v0,xxxx | |
33 | - g_object[g_objpos++]=0x08150000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
34 | - } else { | |
35 | - // Label/number will be dynamically set when executing code. | |
36 | - err=get_value(); | |
37 | - if (err) return err; | |
38 | - call_lib_code(LIB_LABEL); | |
39 | - } | |
40 | - // 2nd param is optional | |
41 | - next_position(); | |
42 | - if (g_source[g_srcpos]==',') { | |
43 | - g_srcpos++; | |
44 | - check_obj_space(2); | |
45 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
46 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
47 | - err=get_value(); | |
48 | - if (err) return err; | |
49 | - check_obj_space(3); | |
50 | - g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
51 | - g_object[g_objpos++]=0x8FA20004; // lw v0,4(sp) | |
52 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
53 | - } else { | |
54 | - // Set 3 if omitted | |
55 | - check_obj_space(1); | |
56 | - g_object[g_objpos++]=0x24040003; // addiu a0,zero,xx | |
57 | - } | |
58 | - call_lib_code(LIB_SOUND); | |
59 | - return 0; | |
60 | -} | |
61 | -char* music_statement(){ | |
62 | - char *err; | |
63 | - err=get_string(); | |
64 | - if (err) return err; | |
65 | - // 2nd param is optional | |
66 | - next_position(); | |
67 | - if (g_source[g_srcpos]==',') { | |
68 | - g_srcpos++; | |
69 | - check_obj_space(2); | |
70 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
71 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
72 | - err=get_value(); | |
73 | - if (err) return err; | |
74 | - check_obj_space(3); | |
75 | - g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
76 | - g_object[g_objpos++]=0x8FA20004; // lw v0,4(sp) | |
77 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
78 | - } else { | |
79 | - // Set 3 if omitted | |
80 | - check_obj_space(1); | |
81 | - g_object[g_objpos++]=0x24040003; // addiu a0,zero,xx | |
82 | - } | |
83 | - call_lib_code(LIB_MUSIC); | |
84 | - return 0; | |
85 | -} | |
86 | - | |
87 | -char* exec_statement(){ | |
88 | - char *err; | |
89 | - char b1; | |
90 | - int i,prevpos; | |
91 | - b1=g_source[g_srcpos]; | |
92 | - while('0'<=b1 && b1<='9' || b1=='-' || b1=='$'){ | |
93 | - prevpos=g_objpos; | |
94 | - g_valueisconst=1; | |
95 | - err=get_simple_value(); | |
96 | - if (!g_valueisconst) err=ERR_SYNTAX; | |
97 | - if (err) return err; | |
98 | - check_obj_space(1); | |
99 | - g_objpos=prevpos; | |
100 | - g_object[g_objpos++]=g_intconst; | |
101 | - next_position(); | |
102 | - b1=g_source[g_srcpos]; | |
103 | - if (b1!=',') break; | |
104 | - g_srcpos++; | |
105 | - next_position(); | |
106 | - b1=g_source[g_srcpos]; | |
107 | - if (b1==0x0d || b1==0x0a) { | |
108 | - // Multiline DATA/EXEC statement | |
109 | - g_line++; | |
110 | - g_fileline++; | |
111 | - if (b1==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
112 | - g_srcpos++; | |
113 | - // Maintain at least 256 characters in cache. | |
114 | - if (256<=g_srcpos) read_file(256); | |
115 | - next_position(); | |
116 | - b1=g_source[g_srcpos]; | |
117 | - } | |
118 | - } | |
119 | - return 0; | |
120 | -} | |
121 | - | |
122 | -char* cdata_statement(){ | |
123 | - // 0x00000020, 0x00000021, 0x00000022, and 0x00000023 (add/addu/sub/subu zero,zero,zero) | |
124 | - // are the sign of data region | |
125 | - int beginpos,prevpos; | |
126 | - char* err; | |
127 | - char b1; | |
128 | - char* cpy; | |
129 | - int shift=0; | |
130 | - int i=0; | |
131 | - beginpos=g_objpos; | |
132 | - check_obj_space(2); | |
133 | - g_object[g_objpos++]=0x04110000; // bgezal zero,xxxx | |
134 | - g_object[g_objpos++]=0x00000020; // add zero,zero,zero | |
135 | - next_position(); | |
136 | - b1=g_source[g_srcpos]; | |
137 | - while('0'<=b1 && b1<='9' || b1=='-' || b1=='$'){ | |
138 | - prevpos=g_objpos; | |
139 | - g_valueisconst=1; | |
140 | - err=get_simple_value(); | |
141 | - if (!g_valueisconst) err=ERR_SYNTAX; | |
142 | - if (g_intconst<0x00 || 0xff<g_intconst) err=ERR_SYNTAX; | |
143 | - if (err) return err; | |
144 | - g_objpos=prevpos; | |
145 | - i|=g_intconst<<shift; | |
146 | - shift+=8; | |
147 | - if (32<=shift) { | |
148 | - check_obj_space(1); | |
149 | - g_object[g_objpos++]=i; | |
150 | - shift=0; | |
151 | - i=0; | |
152 | - } | |
153 | - next_position(); | |
154 | - b1=g_source[g_srcpos]; | |
155 | - if (b1!=',') break; | |
156 | - g_srcpos++; | |
157 | - next_position(); | |
158 | - b1=g_source[g_srcpos]; | |
159 | - if (b1==0x0d || b1==0x0a) { | |
160 | - // Multiline CDATA statement | |
161 | - g_line++; | |
162 | - g_fileline++; | |
163 | - if (b1==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
164 | - g_srcpos++; | |
165 | - // Maintain at least 256 characters in cache. | |
166 | - if (256<=g_srcpos) read_file(256); | |
167 | - next_position(); | |
168 | - b1=g_source[g_srcpos]; | |
169 | - } | |
170 | - } | |
171 | - // Write the last 1-3 bytes and shift data if total # is not multipes of 4. | |
172 | - if (0<shift) { | |
173 | - // Convert shift value from bit-shift to data byte-shift. | |
174 | - shift=4-shift/8; | |
175 | - check_obj_space(1); | |
176 | - g_object[g_objpos++]=i; | |
177 | - for(cpy=(char*)&g_object[g_objpos]-1;(char*)&g_object[beginpos+2]<cpy;cpy--){ | |
178 | - cpy[0]=cpy[0-shift]; | |
179 | - } | |
180 | - } | |
181 | - // Determine the size of data | |
182 | - i=g_objpos-beginpos-1; | |
183 | - g_object[beginpos] =0x04110000|i; // bgezal zero,xxxx | |
184 | - g_object[beginpos+1]=0x00000020|shift; // add zero,zero,zero | |
185 | - return 0; | |
186 | -} | |
187 | - | |
188 | -char* data_statement(){ | |
189 | - // 0x00000020, 0x00000021, 0x00000022, and 0x00000023 (add/addu/sub/subu zero,zero,zero) | |
190 | - // are the sign of data region | |
191 | - int i,prevpos; | |
192 | - char* err; | |
193 | - while(1){ | |
194 | - prevpos=g_objpos; | |
195 | - check_obj_space(2); | |
196 | - g_object[g_objpos++]=0x04110000; // bgezal zero,xxxx | |
197 | - g_object[g_objpos++]=0x00000020; // add zero,zero,zero | |
198 | - next_position(); | |
199 | - if (g_source[g_srcpos]=='"') { | |
200 | - // Constant string | |
201 | - // Store pointer to string. This is 3 words bellow of current position | |
202 | - g_object[g_objpos]=(int)(&g_object[g_objpos+3]); | |
203 | - g_objpos++; | |
204 | - g_object[prevpos]=0x04110002; // bgezal zero,xxxx | |
205 | - err=simple_string(); | |
206 | - if (err) return err; | |
207 | - next_position(); | |
208 | - if (g_source[g_srcpos]==',') { | |
209 | - g_srcpos++; | |
210 | - continue; | |
211 | - } | |
212 | - return 0; | |
213 | - } | |
214 | - err=exec_statement(); | |
215 | - if (err) return err; | |
216 | - // Determine the size of data | |
217 | - i=g_objpos-prevpos-1; | |
218 | - g_object[prevpos]=0x04110000|i; // bgezal zero,xxxx | |
219 | - if (g_source[g_srcpos]=='"') { | |
220 | - // Constant string | |
221 | - continue; | |
222 | - } | |
223 | - return 0; | |
224 | - } | |
225 | -} | |
226 | - | |
227 | -char* clear_statement(){ | |
228 | - call_lib_code(LIB_CLEAR); | |
229 | - return 0; | |
230 | -} | |
231 | - | |
232 | -char* poke_statement(){ | |
233 | - char* err; | |
234 | - err=get_value(); | |
235 | - if (err) return err; | |
236 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
237 | - g_srcpos++; | |
238 | - check_obj_space(2); | |
239 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
240 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
241 | - err=get_value(); | |
242 | - if (err) return err; | |
243 | - check_obj_space(3); | |
244 | - g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
245 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
246 | - g_object[g_objpos++]=0xA0620000; // sb v0,0(v1) | |
247 | - return 0; | |
248 | -} | |
249 | - | |
250 | -char* dim_statement(){ | |
251 | - char* err; | |
252 | - char b1; | |
253 | - int i; | |
254 | - int spos; | |
255 | - int stack; | |
256 | - while(1){ | |
257 | - stack=0; | |
258 | - next_position(); | |
259 | - i=get_var_number(); | |
260 | - if (i<0) return ERR_SYNTAX; | |
261 | - if (g_source[g_srcpos]=='#') g_srcpos++; | |
262 | - next_position(); | |
263 | - if (g_source[g_srcpos]!='(') return ERR_SYNTAX; | |
264 | - check_obj_space(1); | |
265 | - spos=g_objpos++; // addiu sp,sp,xxxx | |
266 | - do { | |
267 | - g_srcpos++; | |
268 | - err=get_value(); | |
269 | - if (err) return err; | |
270 | - stack+=4; | |
271 | - check_obj_space(1); | |
272 | - g_object[g_objpos++]=0xAFA20000|stack; // sw v0,8(sp) | |
273 | - } while (g_source[g_srcpos]==','); | |
274 | - if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
275 | - g_srcpos++; | |
276 | - check_obj_space(3); | |
277 | - g_object[g_objpos++]=0x24040000|(i); // addiu a0,zero,xx | |
278 | - g_object[g_objpos++]=0x24050000|(stack/4); // addiu a1,zero,xxxx | |
279 | - g_object[g_objpos++]=0x03A01025; // or v0,sp,zero | |
280 | - call_lib_code(LIB_DIM); | |
281 | - // Stack -/+ | |
282 | - check_obj_space(1); | |
283 | - g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xxxx | |
284 | - stack=(0-stack)&0x0000FFFF; | |
285 | - g_object[spos]=0x27BD0000|stack; // addiu sp,sp,xxxx | |
286 | - next_position(); | |
287 | - if (g_source[g_srcpos]!=',') break; | |
288 | - g_srcpos++; | |
289 | - } | |
290 | - return 0; | |
291 | -} | |
292 | - | |
293 | -char* label_statement(){ | |
294 | - char* err; | |
295 | - char b1; | |
296 | - b1=g_source[g_srcpos]; | |
297 | - if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; // Number is not allowed here. | |
298 | - err=get_label(); | |
299 | - if (err) return err; | |
300 | - // Check existing label with the same name here. | |
301 | - if (search_label(g_label)) { | |
302 | - // Error: duplicate labels | |
303 | - printstr("Label "); | |
304 | - printstr(resolve_label(g_label)); | |
305 | - return ERR_MULTIPLE_LABEL; | |
306 | - } | |
307 | - check_obj_space(2); | |
308 | - g_object[g_objpos++]=0x3C160000|((g_label>>16)&0x0000FFFF); //lui s6,yyyy; | |
309 | - g_object[g_objpos++]=0x36D60000|(g_label&0x0000FFFF); //ori s6,s6,zzzz; | |
310 | - return 0; | |
311 | -} | |
312 | - | |
313 | -char* restore_statement(){ | |
314 | - char* err; | |
315 | - err=get_label(); | |
316 | - if (err) return err; | |
317 | - if (g_label) { | |
318 | - // Constant label/number | |
319 | - // Use 32 bit mode also for values<65536 | |
320 | - // This code will be replaced to code for v0 for pointer in linker. | |
321 | - check_obj_space(2); | |
322 | - g_object[g_objpos++]=0x3C020000|(g_label>>16); // lui v0,xxxx | |
323 | - g_object[g_objpos++]=0x34420000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
324 | - } else { | |
325 | - // Dynamic number | |
326 | - err=get_value(); | |
327 | - if (err) return err; | |
328 | - } | |
329 | - call_lib_code(LIB_RESTORE); | |
330 | - return 0; | |
331 | -} | |
332 | - | |
333 | -char* gosub_statement_sub(){ | |
334 | - char* err; | |
335 | - err=get_label(); | |
336 | - if (err) return err; | |
337 | - if (g_label) { | |
338 | - // Label/number is constant. | |
339 | - // Linker will change following codes later. | |
340 | - // Note that 0x0812xxxx and 0x0813xxxx are specific codes for these. | |
341 | - check_obj_space(6); | |
342 | - g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
343 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
344 | - g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
345 | - g_object[g_objpos++]=0x08120000|((g_label>>16)&0x0000FFFF); // nop | |
346 | - // label1: | |
347 | - g_object[g_objpos++]=0x08130000|(g_label&0x0000FFFF); // j xxxx | |
348 | - g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
349 | - // label2: | |
350 | - } else { | |
351 | - // Label/number will be dynamically set when executing code. | |
352 | - err=get_value(); | |
353 | - if (err) return err; | |
354 | - call_lib_code(LIB_LABEL); | |
355 | - check_obj_space(6); | |
356 | - g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
357 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
358 | - g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
359 | - g_object[g_objpos++]=0x00000000; // nop | |
360 | - // label1: | |
361 | - g_object[g_objpos++]=0x00400008; // jr v0 | |
362 | - g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
363 | - // label2: | |
364 | - } | |
365 | - return 0; | |
366 | -} | |
367 | - | |
368 | -char* gosub_statement(){ | |
369 | - char* err; | |
370 | - int opos,spos,stack; | |
371 | - opos=g_objpos; | |
372 | - spos=g_srcpos; | |
373 | - err=gosub_statement_sub(); | |
374 | - if (err) return err; | |
375 | - next_position(); | |
376 | - // If there is no 2nd argument, return. | |
377 | - if (g_source[g_srcpos]!=',') return 0; | |
378 | - | |
379 | - // There is (at least) 2nd argument. | |
380 | - // Rewind object and construct argument-creating routine. | |
381 | - g_objpos=opos; | |
382 | - stack=4; | |
383 | - g_object[g_objpos++]=0x27BD0000; // addiu sp,sp,-xx | |
384 | - do { | |
385 | - g_srcpos++; | |
386 | - stack+=4; | |
387 | - err=get_stringFloatOrValue(); | |
388 | - if (err) return err; | |
389 | - check_obj_space(1); | |
390 | - g_object[g_objpos++]=0xAFA20000|stack; // sw v0,xx(sp) | |
391 | - next_position(); | |
392 | - } while(g_source[g_srcpos]==','); | |
393 | - check_obj_space(2); | |
394 | - g_object[g_objpos++]=0xAFB50004; // sw s5,4(sp) | |
395 | - g_object[g_objpos++]=0x03A0A821; // addu s5,sp,zero | |
396 | - g_object[opos]|=((0-stack)&0xFFFF); // addiu sp,sp,-xx (See above) | |
397 | - // Rewind source and construct GOSUB routine again. | |
398 | - opos=spos; | |
399 | - spos=g_srcpos; | |
400 | - g_srcpos=opos; | |
401 | - err=gosub_statement_sub(); | |
402 | - if (err) return err; | |
403 | - // Remove stack | |
404 | - check_obj_space(2); | |
405 | - g_object[g_objpos++]=0x8FB50004; // lw s5,4(sp) | |
406 | - g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx | |
407 | - // All done, go back to wright source position | |
408 | - g_srcpos=spos; | |
409 | - return 0; | |
410 | -} | |
411 | - | |
412 | -char* return_statement(){ | |
413 | - char* err; | |
414 | - char b1; | |
415 | - next_position(); | |
416 | - b1=g_source[g_srcpos]; | |
417 | - if (0x20<b1 && b1!=':') { | |
418 | - // There is a return value. | |
419 | - err=get_stringFloatOrValue(); | |
420 | - if (err) return err; | |
421 | - } | |
422 | - check_obj_space(3); | |
423 | - g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
424 | - g_object[g_objpos++]=0x00600008; // jr v1 | |
425 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
426 | - return 0; | |
427 | -} | |
428 | - | |
429 | -char* goto_statement(){ | |
430 | - char* err; | |
431 | - err=get_label(); | |
432 | - if (err) return err; | |
433 | - if (g_label) { | |
434 | - // Label/number is constant. | |
435 | - // Linker will change following codes later. | |
436 | - // Note that 0x0810xxxx and 0x0811xxxx are specific codes for these. | |
437 | - check_obj_space(2); | |
438 | - g_object[g_objpos++]=0x08100000|((g_label>>16)&0x0000FFFF); // j xxxx | |
439 | - g_object[g_objpos++]=0x08110000|(g_label&0x0000FFFF); // nop | |
440 | - } else { | |
441 | - // Label/number will be dynamically set when executing code. | |
442 | - err=get_value(); | |
443 | - if (err) return err; | |
444 | - call_lib_code(LIB_LABEL); | |
445 | - check_obj_space(2); | |
446 | - g_object[g_objpos++]=0x00400008; // jr v0 | |
447 | - g_object[g_objpos++]=0x00000000; // nop | |
448 | - } | |
449 | - return 0; | |
450 | -} | |
451 | - | |
452 | -char* if_statement(){ | |
453 | - char* err; | |
454 | - int prevpos,bpos; | |
455 | - // Get value. | |
456 | - err=get_floatOrValue(); | |
457 | - if (err) return err; | |
458 | - // Check "THEN" | |
459 | - if (!nextCodeIs("THEN")) return ERR_SYNTAX; | |
460 | - // Check if statement follows after THEN statement | |
461 | - next_position(); | |
462 | - if (nextCodeIs("REM")) { | |
463 | - // If REM statement follows, skip comment words. | |
464 | - rem_statement(); | |
465 | - } | |
466 | - if (g_source[g_srcpos]<0x20) { | |
467 | - // End of line. | |
468 | - // Use IF-THEN-ENDIF mode (multiple line mode) | |
469 | - check_obj_space(3); | |
470 | - g_object[g_objpos++]=0x30000000; // nop (see linker) | |
471 | - g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
472 | - g_object[g_objpos++]=0x30000000; // nop (see linker) | |
473 | - return 0; | |
474 | - } | |
475 | - // One line mode | |
476 | - // If $v0=0 then skip. | |
477 | - bpos=g_objpos; | |
478 | - check_obj_space(2); | |
479 | - g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
480 | - g_object[g_objpos++]=0x00000000; // nop | |
481 | - prevpos=g_srcpos; | |
482 | - if (statement()) { | |
483 | - // May be label | |
484 | - g_srcpos=prevpos; | |
485 | - err=goto_statement(); | |
486 | - if (err) return err; | |
487 | - } else { | |
488 | - // Must be statement(s) | |
489 | - while(1) { | |
490 | - if (g_source[g_srcpos]!=':') break; | |
491 | - g_srcpos++; | |
492 | - err=statement(); | |
493 | - if (err) return err; | |
494 | - } | |
495 | - } | |
496 | - // Check if "ELSE" exists. | |
497 | - if (!nextCodeIs("ELSE ")) { | |
498 | - // "ELSE" not found. This is the end of "IF" statement. | |
499 | - // Previous branch command must jump to this position. | |
500 | - g_object[bpos]=0x10400000|(g_objpos-bpos-1); // beq v0,zero,xxxx | |
501 | - return 0; | |
502 | - } | |
503 | - // Skip after ELSE if required. | |
504 | - check_obj_space(2); | |
505 | - g_object[g_objpos++]=0x10000000; // beq zero,zero,xxxx | |
506 | - g_object[g_objpos++]=0x00000000; // nop | |
507 | - // Previous branch command must jump to this position. | |
508 | - g_object[bpos]=0x10400000|(g_objpos-bpos-1); // beq v0,zero,xxxx | |
509 | - bpos=g_objpos-2; | |
510 | - // Next statement is either label or general statement | |
511 | - prevpos=g_srcpos; | |
512 | - if (statement()) { | |
513 | - // May be label | |
514 | - g_srcpos=prevpos; | |
515 | - err=goto_statement(); | |
516 | - if (err) return err; | |
517 | - } else { | |
518 | - // Must be statement(s) | |
519 | - while(1) { | |
520 | - if (g_source[g_srcpos]!=':') break; | |
521 | - g_srcpos++; | |
522 | - err=statement(); | |
523 | - if (err) return err; | |
524 | - } | |
525 | - } | |
526 | - // Previous branch command must jump to this position. | |
527 | - g_object[bpos]=0x10000000|(g_objpos-bpos-1); // beq zero,zero,xxxx | |
528 | - return 0; | |
529 | -} | |
530 | - | |
531 | -char* elseif_statement(void){ | |
532 | - // Multiple line mode | |
533 | - char* err; | |
534 | - g_object[g_objpos++]=0x08160100; // breakif (see linker) | |
535 | - g_object[g_objpos++]=0x30008000; // nop (see linker) | |
536 | - // Get value. | |
537 | - err=get_floatOrValue(); | |
538 | - if (err) return err; | |
539 | - // Check "THEN" | |
540 | - if (!nextCodeIs("THEN")) return ERR_SYNTAX; | |
541 | - // Check if statement follows after THEN statement | |
542 | - if (nextCodeIs("REM")) { | |
543 | - // If REM statement follows, skip comment words. | |
544 | - rem_statement(); | |
545 | - } | |
546 | - if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
547 | - // Statement didn't follow after THEM statement (that is correct). | |
548 | - g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
549 | - g_object[g_objpos++]=0x30000000; // nop (see linker) | |
550 | - return 0; | |
551 | - | |
552 | -} | |
553 | - | |
554 | -char* else_statement(void){ | |
555 | - // Multiple line mode | |
556 | - g_object[g_objpos++]=0x08160100; // breakif (see linker) | |
557 | - g_object[g_objpos++]=0x30008000; // nop (see linker) | |
558 | - g_object[g_objpos++]=0x30000000; // nop (see linker) | |
559 | - // Check if statement follows after THEN statement | |
560 | - if (nextCodeIs("REM")) { | |
561 | - // If REM statement follows, skip comment words. | |
562 | - rem_statement(); | |
563 | - } | |
564 | - if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
565 | - // Statement didn't follow after THEM statement (that is correct). | |
566 | - return 0; | |
567 | -} | |
568 | - | |
569 | -char* endif_statement(void){ | |
570 | - // Multiple line mode | |
571 | - g_object[g_objpos++]=0x30008000; // nop (see linker) | |
572 | - g_object[g_objpos++]=0x30008000; // nop (see linker) | |
573 | - // Check if statement follows after THEN statement | |
574 | - if (nextCodeIs("REM")) { | |
575 | - // If REM statement follows, skip comment words. | |
576 | - rem_statement(); | |
577 | - } | |
578 | - if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
579 | - // Statement didn't follow after THEM statement (that is correct). | |
580 | - return 0; | |
581 | -} | |
582 | - | |
583 | -char* end_statement(void){ | |
584 | - int i; | |
585 | - i=(int)&g_end_addr; | |
586 | - i-=g_gp; | |
587 | - check_obj_space(3); | |
588 | - g_object[g_objpos++]=0x8F820000|(i&0x0000FFFF); // lw v0,xxxx(gp) | |
589 | - g_object[g_objpos++]=0x00400008; // jr v0 | |
590 | - g_object[g_objpos++]=0x00000000; // nop | |
591 | - return 0; | |
592 | -} | |
593 | - | |
594 | -char* let_dim_sub(int i){ | |
595 | - char* err; | |
596 | - g_srcpos++; | |
597 | - err=get_value(); | |
598 | - if (err) return err; | |
599 | - check_obj_space(4); | |
600 | - g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
601 | - g_object[g_objpos++]=0x8FC30000|(i*4); // lw v1,xx(s8) | |
602 | - g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
603 | - g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
604 | - while(g_source[g_srcpos]==','){ | |
605 | - g_srcpos++; | |
606 | - err=get_value(); | |
607 | - if (err) return err; | |
608 | - check_obj_space(4); | |
609 | - g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
610 | - g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
611 | - g_object[g_objpos++]=0x8C630000; // lw v1,0(v1) | |
612 | - g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
613 | - g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
614 | - } | |
615 | - if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
616 | - g_srcpos++; | |
617 | - return 0; | |
618 | -}; | |
619 | - | |
620 | -char* let_statement(){ | |
621 | - char* err; | |
622 | - char b2,b3; | |
623 | - int i; | |
624 | - next_position(); | |
625 | - i=get_var_number(); | |
626 | - if (i<0) return ERR_SYNTAX; | |
627 | - b2=g_source[g_srcpos]; | |
628 | - b3=g_source[g_srcpos+1]; | |
629 | - if (b2=='#' && b3=='(') { | |
630 | - // Float dimension | |
631 | - g_srcpos++; | |
632 | - check_obj_space(1); | |
633 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
634 | - let_dim_sub(i); | |
635 | - next_position(); | |
636 | - if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
637 | - g_srcpos++; | |
638 | - err=get_float(); | |
639 | - if (err) return err; | |
640 | - check_obj_space(3); | |
641 | - g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
642 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
643 | - g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
644 | - return 0; | |
645 | - } else if (b2=='#') { | |
646 | - // Float A-Z | |
647 | - g_srcpos++; | |
648 | - next_position(); | |
649 | - if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
650 | - g_srcpos++; | |
651 | - err=get_float(); | |
652 | - if (err) return err; | |
653 | - check_obj_space(1); | |
654 | - g_object[g_objpos++]=0xAFC20000|(i*4); // sw v0,xxx(s8) | |
655 | - return 0; | |
656 | - } else if (b2=='$') { | |
657 | - // String | |
658 | - g_srcpos++; | |
659 | - next_position(); | |
660 | - if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
661 | - g_srcpos++; | |
662 | - err=get_string(); | |
663 | - if (err) return err; | |
664 | - check_obj_space(1); | |
665 | - g_object[g_objpos++]=0x24040000|(i); //addiu a0,zero,xx | |
666 | - call_lib_code(LIB_LETSTR); | |
667 | - return 0; | |
668 | - } else if (b2=='(') { | |
669 | - // Dimension | |
670 | - check_obj_space(1); | |
671 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
672 | - let_dim_sub(i); | |
673 | - next_position(); | |
674 | - if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
675 | - g_srcpos++; | |
676 | - err=get_value(); | |
677 | - if (err) return err; | |
678 | - check_obj_space(3); | |
679 | - g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
680 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
681 | - g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
682 | - return 0; | |
683 | - } else { | |
684 | - // Integer A-Z | |
685 | - next_position(); | |
686 | - if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
687 | - g_srcpos++; | |
688 | - err=get_value(); | |
689 | - if (err) return err; | |
690 | - check_obj_space(1); | |
691 | - g_object[g_objpos++]=0xAFC20000|(i*4); // sw v0,xxx(s8) | |
692 | - } | |
693 | - return 0; | |
694 | -} | |
695 | - | |
696 | -char* print_statement_main(enum libs lib_printstr, enum libs lib_string){ | |
697 | - char* err; | |
698 | - char b1; | |
699 | - int i; | |
700 | - int status=0;// 1:',' 2:';' 0:none | |
701 | - while(1){ | |
702 | - next_position(); | |
703 | - if (endOfStatement()) break; | |
704 | - if (!strncmp(g_source+g_srcpos,"ELSE " ,5)) break; | |
705 | - err=get_stringFloatOrValue(); | |
706 | - if (err) return err; | |
707 | - switch(g_lastvar){ | |
708 | - case VAR_INTEGER: | |
709 | - // Use DEC$() function. | |
710 | - call_lib_code(LIB_DEC); | |
711 | - break; | |
712 | - case VAR_FLOAT: | |
713 | - // Use FLOAT$() function. | |
714 | - check_obj_space(2); | |
715 | - g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
716 | - g_object[g_objpos++]=0x34020000; //ori v0,zero,0x0000 | |
717 | - call_lib_code(LIB_SPRINTF); | |
718 | - break; | |
719 | - case VAR_STRING: | |
720 | - default: | |
721 | - break; | |
722 | - } | |
723 | - // Call printstr() function | |
724 | - // First argument is the pointer to string | |
725 | - call_lib_code(lib_printstr); | |
726 | - next_position(); | |
727 | - b1=g_source[g_srcpos]; | |
728 | - if (b1==',') { | |
729 | - status=1; | |
730 | - g_srcpos++; | |
731 | - // Call lib_string() function for comma (,) | |
732 | - check_obj_space(1); | |
733 | - g_object[g_objpos++]=0x34020001; // ori v0,zero,1 | |
734 | - call_lib_code(lib_string); | |
735 | - } else if (b1==';') { | |
736 | - status=2; | |
737 | - g_srcpos++; | |
738 | - } else { | |
739 | - status=0; | |
740 | - } | |
741 | - } | |
742 | - if (status==0) { | |
743 | - // Call lib_string() function for CR (\n) | |
744 | - check_obj_space(1); | |
745 | - g_object[g_objpos++]=0x34020000; // ori v0,zero,0 | |
746 | - call_lib_code(lib_string); | |
747 | - } | |
748 | - return 0; | |
749 | -} | |
750 | - | |
751 | -char* break_statement(){ | |
752 | - check_obj_space(2); | |
753 | - g_object[g_objpos++]=0x08160000; // j xxxx (See link() function) | |
754 | - g_object[g_objpos++]=0x00000000; // nop | |
755 | - return 0; | |
756 | -} | |
757 | - | |
758 | -char* continue_statement(){ | |
759 | - check_obj_space(2); | |
760 | - g_object[g_objpos++]=0x08160008; // j xxxx (See link() function) | |
761 | - g_object[g_objpos++]=0x00000000; // nop | |
762 | - return 0; | |
763 | -} | |
764 | - | |
765 | -char* for_statement(){ | |
766 | - char* err; | |
767 | -// char b1; | |
768 | - int i; | |
769 | - int prepos=g_srcpos; | |
770 | - // Initialization of variable | |
771 | -// next_position(); | |
772 | -// b1=g_source[g_srcpos]; | |
773 | - i=get_var_number(); | |
774 | -// if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; | |
775 | - if (i<0) return ERR_SYNTAX; | |
776 | - g_srcpos=prepos; | |
777 | - err=let_statement(); | |
778 | - if (err) return err; | |
779 | - // Check if "TO" exists | |
780 | - if (!nextCodeIs("TO ")) return ERR_SYNTAX; | |
781 | - err=get_value(); | |
782 | - if (err) return err; | |
783 | - // Usage of stack: | |
784 | - // 12(sp): "TO" value | |
785 | - // 8(sp): "STEP" value | |
786 | - // 4(sp): Address to return to in "NEXT" statement. | |
787 | - // Store "TO" value in stack | |
788 | - check_obj_space(2); | |
789 | - g_object[g_objpos++]=0x0820FFF4; // addiu sp,sp,-12 (see linker) | |
790 | - g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
791 | - // Check if "STEP" exists | |
792 | - g_valueisconst=1; | |
793 | - if (nextCodeIs("STEP ")) { | |
794 | - // "STEP" exists. Get value | |
795 | - err=get_value(); | |
796 | - if (err) return err; | |
797 | - } else { | |
798 | - // "STEP" not exist. Use "1". | |
799 | - check_obj_space(1); | |
800 | - g_object[g_objpos++]=0x24020001; // addiu v0,zero,1 | |
801 | - g_intconst=1; | |
802 | - } | |
803 | - check_obj_space(14); | |
804 | - g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) (STEP value) | |
805 | - g_object[g_objpos++]=0x04130004; // bgezall zero,check | |
806 | -// g_object[g_objpos++]=0x8FC40000|((b1-'A')*4); // lw a0,xx(s8) (current var value) | |
807 | - g_object[g_objpos++]=0x8FC40000|(i*4); // lw a0,xx(s8) (current var value) | |
808 | - // After executing "NEXT" statement, process reaches following line. | |
809 | - // Update variable value by adding STEP value | |
810 | - // Note that STEP value is loaded onto $v0 in NEXT statement | |
811 | -// g_object[g_objpos++]=0x8FC40000|((b1-'A')*4); // lw a0,xx(s8) (current var value) | |
812 | - g_object[g_objpos++]=0x8FC40000|(i*4); // lw a0,xx(s8) (current var value) | |
813 | - g_object[g_objpos++]=0x00822021; // addu a0,a0,v0 | |
814 | -// g_object[g_objpos++]=0xAFC40000|((b1-'A')*4); // sw a0,xx(s8) (new var value) | |
815 | - g_object[g_objpos++]=0xAFC40000|(i*4); // sw a0,xx(s8) (new var value) | |
816 | - // Value-checking routine and storing ra in stack | |
817 | - // check: | |
818 | - g_object[g_objpos++]=0x8FA3000C; // lw v1,12(sp) (TO value) | |
819 | - g_object[g_objpos++]=0x00641823; // subu v1,v1,a0 | |
820 | - g_object[g_objpos++]=0x04420001; // bltzl v0,negative | |
821 | - g_object[g_objpos++]=0x00031823; // subu v1,zero,v1 | |
822 | - // negative: | |
823 | - g_object[g_objpos++]=0x04610003; // bgez v1,continue | |
824 | - g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
825 | - break_statement(); // (2 words) | |
826 | - // continue: | |
827 | - return 0; | |
828 | -} | |
829 | - | |
830 | -char* next_statement(){ | |
831 | - // Return to address stored in 4($sp) | |
832 | - // while set $v0 to 8($sp) (see for_statement) | |
833 | - // Following assembly must be 4 words. | |
834 | - // If the number of words will be changed, link.c must be reviced for CONTINUE statement. | |
835 | - check_obj_space(4); | |
836 | - g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
837 | - g_object[g_objpos++]=0x03E00008; // jr ra | |
838 | - g_object[g_objpos++]=0x8FA20008; // lw v0,8(sp) (STEP value) | |
839 | - g_object[g_objpos++]=0x0830000C; // addiu sp,sp,12 (see linker) | |
840 | - return 0; | |
841 | -} | |
842 | - | |
843 | -char* do_statement(){ | |
844 | - char* err; | |
845 | - // Usage of stack: | |
846 | - // 4(sp): Address to return to in "DO" statement. | |
847 | - check_obj_space(3); | |
848 | - g_object[g_objpos++]=0x04130001;// bgezall zero,label1: | |
849 | - g_object[g_objpos++]=0x0822FFFC;// addiu sp,sp,-4 (see linker) | |
850 | - // label1: | |
851 | - g_object[g_objpos++]=0xAFBF0004;// sw ra,4(sp) | |
852 | - if (nextCodeIs("WHILE ")) { | |
853 | - // DO WHILE | |
854 | - err=get_floatOrValue(); | |
855 | - if (err) return err; | |
856 | - check_obj_space(2); | |
857 | - g_object[g_objpos++]=0x14400003; // bne v0,zero,labe2 | |
858 | - g_object[g_objpos++]=0x00000000; // nop | |
859 | - return break_statement(); // (2 words) | |
860 | - // label2: | |
861 | - | |
862 | - } else if (nextCodeIs("UNTIL ")) { | |
863 | - // DO UNTIL | |
864 | - err=get_floatOrValue(); | |
865 | - if (err) return err; | |
866 | - check_obj_space(2); | |
867 | - g_object[g_objpos++]=0x10400003; // beq v0,zero,label2 | |
868 | - g_object[g_objpos++]=0x00000000; // nop | |
869 | - return break_statement(); // (2 words) | |
870 | - // label2: | |
871 | - } else { | |
872 | - // DO statement without WHILE/UNTIL | |
873 | - return 0; | |
874 | - } | |
875 | -} | |
876 | - | |
877 | -char* loop_statement(){ | |
878 | - char* err; | |
879 | - int opos; | |
880 | - opos=g_objpos; | |
881 | - if (nextCodeIs("WHILE ")) { | |
882 | - // LOOP WHILE | |
883 | - err=get_floatOrValue(); | |
884 | - if (err) return err; | |
885 | - check_obj_space(1); | |
886 | - g_object[g_objpos++]=0x10400003; // beq v0,zero,label1 | |
887 | - } else if (nextCodeIs("UNTIL ")) { | |
888 | - // LOOP UNTIL | |
889 | - err=get_floatOrValue(); | |
890 | - if (err) return err; | |
891 | - check_obj_space(1); | |
892 | - g_object[g_objpos++]=0x14400003; // bne v0,zero,label | |
893 | - } else { | |
894 | - // LOOP statement without WHILE/UNTIL | |
895 | - } | |
896 | - check_obj_space(4); | |
897 | - g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
898 | - g_object[g_objpos++]=0x03E00008; // jr ra | |
899 | - opos=g_objpos+1-opos; | |
900 | - g_object[g_objpos++]=0x3000F000|opos; // nop (See linker, used for CONTINUE statement) | |
901 | - // label1: | |
902 | - g_object[g_objpos++]=0x08320004; // addiu sp,sp,4 (See link() function) | |
903 | - return 0; | |
904 | -} | |
905 | - | |
906 | -char* while_statement(){ | |
907 | - char* err; | |
908 | - check_obj_space(3); | |
909 | - g_object[g_objpos++]=0x04130001; // bgezall zero,label1: | |
910 | - g_object[g_objpos++]=0x0821FFFC; // addiu sp,sp,-4 (see linker) | |
911 | - // label1: | |
912 | - g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
913 | - err=get_floatOrValue(); | |
914 | - if (err) return err; | |
915 | - check_obj_space(2); | |
916 | - g_object[g_objpos++]=0x14400003; // bne v0,zero,label2 | |
917 | - g_object[g_objpos++]=0x00000000; // nop | |
918 | - return break_statement(); // (2 words) | |
919 | - // label2: | |
920 | -} | |
921 | - | |
922 | -char* wend_statement(){ | |
923 | - check_obj_space(4); | |
924 | - g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
925 | - g_object[g_objpos++]=0x03E00008; // jr ra | |
926 | - g_object[g_objpos++]=0x3000F003; // nop (See linker, used for CONTINUE statement) | |
927 | - // label1: | |
928 | - g_object[g_objpos++]=0x08310004; // addiu sp,sp,4 (See link() function) | |
929 | - return 0; | |
930 | -} | |
931 | - | |
932 | -char* param4_statement(enum libs lib){ | |
933 | - // lib is either LIB_PALETTE or LIB_GPALETTE | |
934 | - // PALETTE N,R,G,B | |
935 | - char* err; | |
936 | - // Get N | |
937 | - err=get_value(); | |
938 | - if (err) return err; | |
939 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
940 | - g_srcpos++; | |
941 | - check_obj_space(2); | |
942 | - g_object[g_objpos++]=0x27BDFFF4; // addiu sp,sp,-12 | |
943 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
944 | - // Get R | |
945 | - err=get_value(); | |
946 | - if (err) return err; | |
947 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
948 | - g_srcpos++; | |
949 | - check_obj_space(1); | |
950 | - g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
951 | - // Get G | |
952 | - err=get_value(); | |
953 | - if (err) return err; | |
954 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
955 | - g_srcpos++; | |
956 | - check_obj_space(1); | |
957 | - g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
958 | - // Get B | |
959 | - err=get_value(); | |
960 | - if (err) return err; | |
961 | - call_lib_code(lib); | |
962 | - check_obj_space(1); | |
963 | - g_object[g_objpos++]=0x27BD000C; // addiu sp,sp,12 | |
964 | - return 0; | |
965 | -} | |
966 | - | |
967 | -char* param3_statement(enum libs lib){ | |
968 | - char* err; | |
969 | - // Get 1st parameter | |
970 | - err=get_value(); | |
971 | - if (err) return err; | |
972 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
973 | - g_srcpos++; | |
974 | - check_obj_space(2); | |
975 | - g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
976 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
977 | - // Get 2nd parameter | |
978 | - err=get_value(); | |
979 | - if (err) return err; | |
980 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
981 | - g_srcpos++; | |
982 | - check_obj_space(1); | |
983 | - g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
984 | - // Get 3rd parameter | |
985 | - err=get_value(); | |
986 | - if (err) return err; | |
987 | - call_lib_code(lib); | |
988 | - check_obj_space(1); | |
989 | - g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
990 | - return 0; | |
991 | -} | |
992 | - | |
993 | -char* bgcolor_statement(){ | |
994 | - // BGCOLOR R,G,B | |
995 | - return param3_statement(LIB_BGCOLOR); | |
996 | -} | |
997 | - | |
998 | -char* pcg_statement(){ | |
999 | - // PCG ASCII,D1,D2 | |
1000 | - return param3_statement(LIB_PCG); | |
1001 | -} | |
1002 | - | |
1003 | -char* usepcg_statement(){ | |
1004 | - int objpos=g_objpos; | |
1005 | - if (get_value()) { | |
1006 | - // Getting integer failed. | |
1007 | - // It supporsed to be not parameter | |
1008 | - // and same as parameter=1. | |
1009 | - g_objpos=objpos; | |
1010 | - check_obj_space(1); | |
1011 | - g_object[g_objpos++]=0x34020001; //ori v0,zero,0x01 | |
1012 | - } | |
1013 | - call_lib_code(LIB_USEPCG); | |
1014 | - return 0; | |
1015 | -} | |
1016 | - | |
1017 | -char* usegraphic_statement(){ | |
1018 | - int objpos=g_objpos; | |
1019 | - if (get_value()) { | |
1020 | - // Getting integer failed. | |
1021 | - // It supporsed to be not parameter | |
1022 | - // and same as parameter=1. | |
1023 | - g_objpos=objpos; | |
1024 | - check_obj_space(1); | |
1025 | - g_object[g_objpos++]=0x34020001; //ori v0,zero,0x01 | |
1026 | - } | |
1027 | - call_lib_code(LIB_USEGRAPHIC); | |
1028 | - return 0; | |
1029 | -} | |
1030 | - | |
1031 | -char* cls_statement(){ | |
1032 | - call_lib_code(LIB_CLS); | |
1033 | - return 0; | |
1034 | -} | |
1035 | - | |
1036 | -char* gcls_statement(){ | |
1037 | - call_lib_code(LIB_GCLS); | |
1038 | - return 0; | |
1039 | -} | |
1040 | - | |
1041 | -char* color_statement(){ | |
1042 | - char* err; | |
1043 | - err=get_value(); | |
1044 | - if (err) return err; | |
1045 | - call_lib_code(LIB_COLOR); | |
1046 | - return 0; | |
1047 | -} | |
1048 | - | |
1049 | -char* gcolor_statement(){ | |
1050 | - char* err; | |
1051 | - err=get_value(); | |
1052 | - if (err) return err; | |
1053 | - call_lib_code(LIB_GCOLOR); | |
1054 | - return 0; | |
1055 | -} | |
1056 | - | |
1057 | -char* param2_statement(enum libs lib){ | |
1058 | - char* err; | |
1059 | - // Get 1st | |
1060 | - err=get_value(); | |
1061 | - if (err) return err; | |
1062 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1063 | - g_srcpos++; | |
1064 | - check_obj_space(2); | |
1065 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
1066 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1067 | - // Get 2nd | |
1068 | - err=get_value(); | |
1069 | - if (err) return err; | |
1070 | - call_lib_code(lib); | |
1071 | - check_obj_space(1); | |
1072 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
1073 | - return 0; | |
1074 | -} | |
1075 | - | |
1076 | -char* system_statement(){ | |
1077 | - // SYSTEM X,Y | |
1078 | - char* err; | |
1079 | - // Get 1st | |
1080 | - err=get_value(); | |
1081 | - if (err) return err; | |
1082 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1083 | - g_srcpos++; | |
1084 | - check_obj_space(2); | |
1085 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
1086 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1087 | - // Get 2nd | |
1088 | - err=get_value(); | |
1089 | - if (err) return err; | |
1090 | - check_obj_space(2); | |
1091 | - g_object[g_objpos++]=0x8FA40004; // lw a0,4(sp) | |
1092 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
1093 | - call_lib_code(LIB_SYSTEM); | |
1094 | - return 0; | |
1095 | -} | |
1096 | - | |
1097 | -char* cursor_statement(){ | |
1098 | - // CURSOR X,Y | |
1099 | - return param2_statement(LIB_CURSOR); | |
1100 | -} | |
1101 | - | |
1102 | -char* scroll_statement(){ | |
1103 | - // SCROLL X,Y | |
1104 | - return param2_statement(LIB_SCROLL); | |
1105 | -} | |
1106 | - | |
1107 | -char* drawcount_statement(){ | |
1108 | - char* err; | |
1109 | - err=get_value(); | |
1110 | - if (err) return err; | |
1111 | - call_lib_code(LIB_SETDRAWCOUNT); | |
1112 | - return 0; | |
1113 | -} | |
1114 | - | |
1115 | -char* wait_statement(){ | |
1116 | - char* err; | |
1117 | - err=get_value(); | |
1118 | - if (err) return err; | |
1119 | - call_lib_code(LIB_WAIT); | |
1120 | - return 0; | |
1121 | -} | |
1122 | - | |
1123 | -char* width_statement(){ | |
1124 | - char* err; | |
1125 | - err=get_value(); | |
1126 | - if (err) return err; | |
1127 | - call_lib_code(LIB_WIDTH); | |
1128 | - return 0; | |
1129 | -} | |
1130 | - | |
1131 | -char* var_statement_sub(int a0, int a1){ | |
1132 | - // Construct parameter-setting scripts | |
1133 | - if (a0&0xffff0000) { | |
1134 | - check_obj_space(1); | |
1135 | - g_object[g_objpos++]=0x3C040000|(a0>>16); // lui a0,XXXX | |
1136 | - if (a0&0x0000ffff) { | |
1137 | - check_obj_space(1); | |
1138 | - g_object[g_objpos++]=0x34840000|(a0&0xffff); // ori a0,a0,XXXX | |
1139 | - } | |
1140 | - } else if (a0&0x0000ffff) { | |
1141 | - check_obj_space(1); | |
1142 | - g_object[g_objpos++]=0x34040000|(a0&0xffff); // ori a0,zero,xxxx | |
1143 | - } | |
1144 | - if (a1&0xffff0000) { | |
1145 | - check_obj_space(1); | |
1146 | - g_object[g_objpos++]=0x3C050000|(a1>>16); // lui a1,XXXX | |
1147 | - if (a1&0x0000ffff) { | |
1148 | - check_obj_space(1); | |
1149 | - g_object[g_objpos++]=0x34A50000|(a1&0xffff); // ori a1,a1,XXXX | |
1150 | - } | |
1151 | - } else if (a1&0x0000ffff) { | |
1152 | - check_obj_space(1); | |
1153 | - g_object[g_objpos++]=0x34050000|(a1&0xffff); // ori a1,zero,xxxx | |
1154 | - } else if (a0&0xff000000) { | |
1155 | - // # of variables is 4. Reset $a1 to let lib_var() know that there is no more variables to store. | |
1156 | - check_obj_space(1); | |
1157 | - g_object[g_objpos++]=0x34050000; // ori a1,zero,0 | |
1158 | - } | |
1159 | - return 0; | |
1160 | -} | |
1161 | - | |
1162 | -char* var_statement(){ | |
1163 | - char* err; | |
1164 | - int i,j,a0,a1; | |
1165 | - static int prevpos; | |
1166 | - short stack; | |
1167 | - do { | |
1168 | - // For stack, 4 bytes are used for return address, | |
1169 | - // 4 bytes are used in lib_var(), | |
1170 | - // and additinal bytes are used for storing variable values. | |
1171 | - stack=8; | |
1172 | - a0=a1=0; | |
1173 | - for (i=0;i<8;i++){ | |
1174 | - // Determine the variable number from source code | |
1175 | - j=get_var_number(); | |
1176 | - if (j<0) return ERR_SYNTAX; | |
1177 | - stack+=4; | |
1178 | - // Create parameters in $a0, or $a1 | |
1179 | - if (i<4) { | |
1180 | - a0=(a0<<8)|(j+1); | |
1181 | - } else { | |
1182 | - a1=(a1<<8)|(j+1); | |
1183 | - } | |
1184 | - // Check remaining variable(s) | |
1185 | - if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') g_srcpos++; | |
1186 | - next_position(); | |
1187 | - if (g_source[g_srcpos]!=',') break; | |
1188 | - g_srcpos++; | |
1189 | - } | |
1190 | - // Jump to push routine, first | |
1191 | - check_obj_space(2); | |
1192 | - prevpos=g_objpos; | |
1193 | - g_object[g_objpos++]=0x04130000; // bgezall zero,label1 | |
1194 | - g_object[g_objpos++]=0x27BD0000|((0-stack)&0xffff); // addiu sp,sp,-xx | |
1195 | - // Process will be here after RETURN statement | |
1196 | - // Pop routine | |
1197 | - err=var_statement_sub(a0,a1); // Prepare a0, and a1 | |
1198 | - if (err) return err; | |
1199 | - call_lib_code(LIB_VAR_POP); | |
1200 | - // Restore stack and return | |
1201 | - check_obj_space(3); | |
1202 | - g_object[g_objpos++]=0x8FA30000|stack; // lw v1,xx(sp) | |
1203 | - g_object[g_objpos++]=0x00600008; // jr v1 | |
1204 | - g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx | |
1205 | - // Push rotine | |
1206 | - g_object[prevpos]|=g_objpos-prevpos-1; // label1: | |
1207 | - check_obj_space(1); | |
1208 | - g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
1209 | - err=var_statement_sub(a0,a1); // Prepare a0, and a1 | |
1210 | - if (err) return err; | |
1211 | - call_lib_code(LIB_VAR_PUSH); | |
1212 | - | |
1213 | - } while (g_source[g_srcpos-1]==','); | |
1214 | - return 0; | |
1215 | -} | |
1216 | - | |
1217 | - | |
1218 | -char* graphic_statement(enum functions func){ | |
1219 | - /* | |
1220 | - PSET X1,Y1[,C] | |
1221 | - LINE X1,Y1,X2,Y2[,C] | |
1222 | - BOXFILL X1,Y1,X2,Y2[,C] | |
1223 | - CIRCLE X1,Y1,R[,C] | |
1224 | - CIRCLEFILL X1,Y1,R[,C] | |
1225 | - GPRINT X1,Y1,C,BC,S$ | |
1226 | - PUTBMP X1,Y1,M,N,BMP | |
1227 | - 4(sp): X1 | |
1228 | - 8(sp): Y1 | |
1229 | - 12(sp): X2/R/M | |
1230 | - 16(sp): Y2/N | |
1231 | - v0: C/S$/BMP | |
1232 | - */ | |
1233 | - char* err; | |
1234 | - int spos; | |
1235 | - int paramnum; | |
1236 | - switch(func){ | |
1237 | - case FUNC_PSET:// X1,Y1[,C] | |
1238 | - case FUNC_GCOLOR:// X1,Y1 | |
1239 | - case FUNC_POINT:// X1,Y1 | |
1240 | - paramnum=2; | |
1241 | - break; | |
1242 | - case FUNC_CIRCLE:// X1,Y1,R[,C] | |
1243 | - case FUNC_CIRCLEFILL:// X1,Y1,R[,C] | |
1244 | - paramnum=3; | |
1245 | - break; | |
1246 | - case FUNC_LINE:// X1,Y1,X2,Y2[,C] | |
1247 | - case FUNC_BOXFILL:// X1,Y1,X2,Y2[,C] | |
1248 | - paramnum=4; | |
1249 | - break; | |
1250 | - case FUNC_GPRINT:// X1,Y1,C,BC,S$ | |
1251 | - case FUNC_PUTBMP:// X1,Y1,M,N,BMP | |
1252 | - paramnum=5; | |
1253 | - break; | |
1254 | - default: | |
1255 | - return ERR_UNKNOWN; | |
1256 | - } | |
1257 | - | |
1258 | - next_position(); | |
1259 | - if (g_source[g_srcpos]==',') { | |
1260 | - // X1 and Y1 is omitted. Set 0x80000000 for both. | |
1261 | - check_obj_space(4); | |
1262 | - g_object[g_objpos++]=0x27BDFFF0; // addiu sp,sp,-16 | |
1263 | - g_object[g_objpos++]=0x3C028000; // lui v0,0x0080 | |
1264 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1265 | - g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1266 | - } else { | |
1267 | - // X1 | |
1268 | - err=get_value(); | |
1269 | - if (err) return err; | |
1270 | - check_obj_space(2); | |
1271 | - g_object[g_objpos++]=0x27BDFFF0; // addiu sp,sp,-16 | |
1272 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1273 | - // Y1 | |
1274 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1275 | - g_srcpos++; | |
1276 | - err=get_value(); | |
1277 | - if (err) return err; | |
1278 | - check_obj_space(1); | |
1279 | - g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1280 | - } | |
1281 | - if (2<paramnum) { | |
1282 | - // X2, R, or M | |
1283 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1284 | - g_srcpos++; | |
1285 | - err=get_value(); | |
1286 | - if (err) return err; | |
1287 | - check_obj_space(1); | |
1288 | - g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
1289 | - if (3<paramnum) { | |
1290 | - // Y2, BC, or N | |
1291 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1292 | - g_srcpos++; | |
1293 | - err=get_value(); | |
1294 | - if (err) return err; | |
1295 | - check_obj_space(1); | |
1296 | - g_object[g_objpos++]=0xAFA20010; // sw v0,16(sp) | |
1297 | - } | |
1298 | - } | |
1299 | - if (func==FUNC_GPRINT) { | |
1300 | - // S$ | |
1301 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1302 | - g_srcpos++; | |
1303 | - err=get_string(); | |
1304 | - if (err) return err; | |
1305 | - } else if (func==FUNC_PUTBMP) { | |
1306 | - // BMP | |
1307 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1308 | - g_srcpos++; | |
1309 | - spos=g_srcpos; | |
1310 | - err=get_label(); | |
1311 | - if (g_label && !err) { | |
1312 | - if (search_var_name(g_label)!=-1) { | |
1313 | - // This is a long var name. | |
1314 | - g_label=0; | |
1315 | - g_srcpos=spos; | |
1316 | - } | |
1317 | - } | |
1318 | - if (g_label && !err) { | |
1319 | - // Label/number is constant. | |
1320 | - // Linker will change following codes later. | |
1321 | - // Note that 0x0814xxxx and 0x0815xxxx are specific codes for these. | |
1322 | - check_obj_space(2); | |
1323 | - g_object[g_objpos++]=0x08140000|((g_label>>16)&0x0000FFFF); // lui v0,xxxx | |
1324 | - g_object[g_objpos++]=0x08150000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
1325 | - // Change func to FUNC_PUTBMP2 (label mode). | |
1326 | - func=FUNC_PUTBMP2; | |
1327 | - } else { | |
1328 | - err=get_value(); | |
1329 | - if (err) return err; | |
1330 | - } | |
1331 | - } else { | |
1332 | - // [,C] | |
1333 | - if (g_source[g_srcpos]==',') { | |
1334 | - g_srcpos++; | |
1335 | - err=get_value(); | |
1336 | - if (err) return err; | |
1337 | - } else { | |
1338 | - // If C is omitted, use -1. | |
1339 | - check_obj_space(1); | |
1340 | - g_object[g_objpos++]=0x2402FFFF; // addiu v0,zero,-1 | |
1341 | - } | |
1342 | - } | |
1343 | - // Call library | |
1344 | - call_lib_code(LIB_GRAPHIC | func); | |
1345 | - // Restore stack pointer | |
1346 | - check_obj_space(1); | |
1347 | - g_object[g_objpos++]=0x27BD0010; // addiu sp,sp,16 | |
1348 | - return 0; | |
1349 | -} | |
1350 | - | |
1351 | -char* fopen_statement_main(enum functions func){ | |
1352 | - // func is either FUNC_FOPENST or FUNC_FOPEN | |
1353 | - char* err; | |
1354 | - // Get 1st | |
1355 | - err=get_string(); | |
1356 | - if (err) return err; | |
1357 | - if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1358 | - g_srcpos++; | |
1359 | - check_obj_space(2); | |
1360 | - g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
1361 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1362 | - // Get 2nd | |
1363 | - err=get_string(); | |
1364 | - if (err) return err; | |
1365 | - check_obj_space(1); | |
1366 | - g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1367 | - // Get 3rd | |
1368 | - if (g_source[g_srcpos]==',') { | |
1369 | - g_srcpos++; | |
1370 | - err=get_value(); | |
1371 | - if (err) return err; | |
1372 | - } else { | |
1373 | - // If 3rd parameter is omitted, use 0. | |
1374 | - check_obj_space(1); | |
1375 | - g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
1376 | - } | |
1377 | - call_lib_code(LIB_FILE | func); | |
1378 | - check_obj_space(1); | |
1379 | - g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
1380 | - return 0; | |
1381 | -} | |
1382 | - | |
1383 | -char* file_statement(){ | |
1384 | - char* err; | |
1385 | - err=get_value(); | |
1386 | - if (err) return err; | |
1387 | - call_lib_code(LIB_FILE | FUNC_FILE); | |
1388 | - return 0; | |
1389 | -} | |
1390 | - | |
1391 | -char* fclose_statement(){ | |
1392 | - char* err; | |
1393 | - int orgpos=g_srcpos; | |
1394 | - if (endOfStatement()) { | |
1395 | - // If no argument, use 0 | |
1396 | - check_obj_space(1); | |
1397 | - g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
1398 | - } else { | |
1399 | - err=get_value(); | |
1400 | - if (err) return err; | |
1401 | - } | |
1402 | - call_lib_code(LIB_FILE | FUNC_FCLOSE); | |
1403 | - return 0; | |
1404 | -} | |
1405 | - | |
1406 | -char* fget_statement(){ | |
1407 | - return param2_statement(LIB_FILE | FUNC_FGET); | |
1408 | -} | |
1409 | - | |
1410 | -char* fput_statement(){ | |
1411 | - return param2_statement(LIB_FILE | FUNC_FPUT); | |
1412 | -} | |
1413 | - | |
1414 | -char* fseek_statement(){ | |
1415 | - char* err; | |
1416 | - err=get_value(); | |
1417 | - if (err) return err; | |
1418 | - call_lib_code(LIB_FILE | FUNC_FSEEK); | |
1419 | - return 0; | |
1420 | -} | |
1421 | - | |
1422 | -char* fputc_statement(){ | |
1423 | - char* err; | |
1424 | - err=get_value(); | |
1425 | - if (err) return err; | |
1426 | - call_lib_code(LIB_FILE | FUNC_FPUTC); | |
1427 | - return 0; | |
1428 | -} | |
1429 | - | |
1430 | -char* fremove_statement(){ | |
1431 | - char* err; | |
1432 | - err=get_string(); | |
1433 | - if (err) return err; | |
1434 | - call_lib_code(LIB_FILE | FUNC_FREMOVE); | |
1435 | - return 0; | |
1436 | -} | |
1437 | - | |
1438 | -char* usevar_statement(){ | |
1439 | - char* err; | |
1440 | - int i; | |
1441 | - do { | |
1442 | - next_position(); | |
1443 | - i=check_var_name(); | |
1444 | - if (i<65536) return ERR_SYNTAX; | |
1445 | - err=register_var_name(i); | |
1446 | - if (err) return err; | |
1447 | - if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') g_srcpos++; | |
1448 | - next_position(); | |
1449 | - if (g_source[g_srcpos]==',') { | |
1450 | - g_srcpos++; | |
1451 | - } else { | |
1452 | - break; | |
1453 | - } | |
1454 | - } while(1); | |
1455 | - return 0; | |
1456 | -} | |
1457 | - | |
1458 | -char* playwave_statement(){ | |
1459 | - char* err; | |
1460 | - err=get_string(); | |
1461 | - if (err) return err; | |
1462 | - check_obj_space(2); | |
1463 | - g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
1464 | - g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1465 | - if (g_source[g_srcpos]==',') { | |
1466 | - g_srcpos++; | |
1467 | - // Get 2nd | |
1468 | - err=get_value(); | |
1469 | - if (err) return err; | |
1470 | - } else { | |
1471 | - // If 2rd parameter is omitted, use 0. | |
1472 | - check_obj_space(1); | |
1473 | - g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
1474 | - } | |
1475 | - call_lib_code(LIB_PLAYWAVE); | |
1476 | - check_obj_space(1); | |
1477 | - g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
1478 | - return 0; | |
1479 | -} | |
1480 | - | |
1481 | -#ifdef __DEBUG | |
1482 | - char* debug_statement(){ | |
1483 | - call_lib_code(LIB_DEBUG); | |
1484 | - return 0; | |
1485 | - } | |
1486 | -#endif | |
1487 | - | |
1488 | -// Aliases follow | |
1489 | - | |
1490 | -char* palette_statement(){ | |
1491 | - return param4_statement(LIB_PALETTE); | |
1492 | -} | |
1493 | - | |
1494 | -char* gpalette_statement(){ | |
1495 | - return param4_statement(LIB_GPALETTE); | |
1496 | -} | |
1497 | - | |
1498 | -char* print_statement(){ | |
1499 | - return print_statement_main(LIB_PRINTSTR,LIB_STRING); | |
1500 | -} | |
1501 | - | |
1502 | -char* pset_statement(){ | |
1503 | - return graphic_statement(FUNC_PSET); | |
1504 | -} | |
1505 | - | |
1506 | -char* line_statement(){ | |
1507 | - return graphic_statement(FUNC_LINE); | |
1508 | -} | |
1509 | - | |
1510 | -char* boxfill_statement(){ | |
1511 | - return graphic_statement(FUNC_BOXFILL); | |
1512 | -} | |
1513 | - | |
1514 | -char* circle_statement(){ | |
1515 | - return graphic_statement(FUNC_CIRCLE); | |
1516 | -} | |
1517 | - | |
1518 | -char* circlefill_statement(){ | |
1519 | - return graphic_statement(FUNC_CIRCLEFILL); | |
1520 | -} | |
1521 | - | |
1522 | -char* gprint_statement(){ | |
1523 | - return graphic_statement(FUNC_GPRINT); | |
1524 | -} | |
1525 | - | |
1526 | -char* putbmp_statement(){ | |
1527 | - return graphic_statement(FUNC_PUTBMP); | |
1528 | -} | |
1529 | - | |
1530 | -char* point_statement(){ | |
1531 | - return graphic_statement(FUNC_POINT); | |
1532 | -} | |
1533 | - | |
1534 | -char* fopen_statement(){ | |
1535 | - return fopen_statement_main(FUNC_FOPENST); | |
1536 | -} | |
1537 | - | |
1538 | -char* fprint_statement(){ | |
1539 | - return print_statement_main(LIB_FILE | FUNC_FPRINTSTR,LIB_FILE | FUNC_FSTRING); | |
1540 | -} | |
1541 | - | |
1542 | -static const void* statement_list[]={ | |
1543 | - "REM",rem_statement, | |
1544 | - "SOUND ",sound_statement, | |
1545 | - "MUSIC ",music_statement, | |
1546 | - "DRAWCOUNT ",drawcount_statement, | |
1547 | - "CURSOR ",cursor_statement, | |
1548 | - "PALETTE ",palette_statement, | |
1549 | - "GPALETTE ",gpalette_statement, | |
1550 | - "BGCOLOR ",bgcolor_statement, | |
1551 | - "CLS",cls_statement, | |
1552 | - "GCLS",gcls_statement, | |
1553 | - "COLOR ",color_statement, | |
1554 | - "GCOLOR ",gcolor_statement, | |
1555 | - "RESTORE ",restore_statement, | |
1556 | - "DATA ",data_statement, | |
1557 | - "CDATA ",cdata_statement, | |
1558 | - "LABEL ",label_statement, | |
1559 | - "DIM ",dim_statement, | |
1560 | - "CLEAR",clear_statement, | |
1561 | - "PRINT",print_statement, | |
1562 | - "IF ",if_statement, | |
1563 | - "ELSEIF ",elseif_statement, | |
1564 | - "ELSE",else_statement, | |
1565 | - "ENDIF",endif_statement, | |
1566 | - "END",end_statement, | |
1567 | - "EXEC ",exec_statement, | |
1568 | - "GOTO ",goto_statement, | |
1569 | - "GOSUB ",gosub_statement, | |
1570 | - "RETURN",return_statement, | |
1571 | - "POKE ",poke_statement, | |
1572 | - "FOR ",for_statement, | |
1573 | - "NEXT",next_statement, | |
1574 | - "LET ",let_statement, | |
1575 | - "PCG ",pcg_statement, | |
1576 | - "USEPCG",usepcg_statement, | |
1577 | - "SCROLL ",scroll_statement, | |
1578 | - "WAIT ",wait_statement, | |
1579 | - "USEGRAPHIC",usegraphic_statement, | |
1580 | - "PSET ",pset_statement, | |
1581 | - "LINE ",line_statement, | |
1582 | - "BOXFILL ",boxfill_statement, | |
1583 | - "CIRCLE ",circle_statement, | |
1584 | - "CIRCLEFILL ",circlefill_statement, | |
1585 | - "GPRINT ",gprint_statement, | |
1586 | - "PUTBMP ",putbmp_statement, | |
1587 | - "POINT ",point_statement, | |
1588 | - "VAR ",var_statement, | |
1589 | - "DO",do_statement, | |
1590 | - "LOOP",loop_statement, | |
1591 | - "WHILE ",while_statement, | |
1592 | - "WEND",wend_statement, | |
1593 | - "BREAK",break_statement, | |
1594 | - "CONTINUE",continue_statement, | |
1595 | - "SYSTEM",system_statement, | |
1596 | - "WIDTH ",width_statement, | |
1597 | - "FOPEN ",fopen_statement, | |
1598 | - "FILE ",file_statement, | |
1599 | - "FCLOSE",fclose_statement, | |
1600 | - "FPRINT ",fprint_statement, | |
1601 | - "FGET ",fget_statement, | |
1602 | - "FPUT ",fput_statement, | |
1603 | - "FPUTC ",fputc_statement, | |
1604 | - "FSEEK ",fseek_statement, | |
1605 | - "FREMOVE ",fremove_statement, | |
1606 | - "USEVAR ",usevar_statement, | |
1607 | - "PLAYWAVE ",playwave_statement, | |
1608 | - // List of additional statements follows | |
1609 | - ADDITIONAL_STATEMENTS | |
1610 | -}; | |
1611 | - | |
1612 | -char* statement(void){ | |
1613 | - char* err; | |
1614 | - int prevpos; | |
1615 | - int i; | |
1616 | - char* (*f)(); | |
1617 | - // Clear flag for temp area usage. | |
1618 | - g_temp_area_used=0; | |
1619 | - // Initialize stack handler used for value | |
1620 | - g_sdepth=g_maxsdepth=0; | |
1621 | - // Seek the statement | |
1622 | - for (i=0;i<sizeof(statement_list)/sizeof(statement_list[0]);i+=2){ | |
1623 | - if (nextCodeIs((char*)statement_list[i])) break; | |
1624 | - } | |
1625 | - if (i<sizeof(statement_list)/sizeof(statement_list[0])) { | |
1626 | - // Statement found. Call it. | |
1627 | - f=statement_list[i+1]; | |
1628 | - err=f(); | |
1629 | -#ifdef __DEBUG | |
1630 | - } else if (nextCodeIs("DEBUG")) { | |
1631 | - err=debug_statement(); | |
1632 | -#endif | |
1633 | - } else { | |
1634 | - err=let_statement(); | |
1635 | - } | |
1636 | - if (err) return err; | |
1637 | - // Stack handler must be zero here. | |
1638 | - if (g_sdepth!=0) return ERR_UNKNOWN; | |
1639 | - // Check if temp area is used | |
1640 | - if (g_temp_area_used) { | |
1641 | - // Temp area is used. Insert a garbage collection flag setting routine. | |
1642 | - check_obj_space(1); | |
1643 | - g_object[g_objpos++]=0x7ED6F000;// ext s6,s6,0,31 | |
1644 | - } | |
1645 | - return 0; | |
1646 | -} | |
1 | +/* | |
2 | + This file is provided under the LGPL license ver 2.1. | |
3 | + Written by Katsumi. | |
4 | + http://hp.vector.co.jp/authors/VA016157/ | |
5 | + kmorimatsu@users.sourceforge.jp | |
6 | +*/ | |
7 | + | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
12 | +#include "api.h" | |
13 | +#include "compiler.h" | |
14 | + | |
15 | +char* rem_statement(){ | |
16 | + if (g_source[g_srcpos-4]<0x20) { | |
17 | + // This line contains only "REM" statement | |
18 | + // Delete $s6-setting command if exists. | |
19 | + if ((g_object[g_objpos-1]&0xffff0000)==0x34160000) g_objpos--; | |
20 | + } | |
21 | + while(0xE0 & g_source[g_srcpos]){ | |
22 | + g_srcpos++; | |
23 | + } | |
24 | + return 0; | |
25 | +} | |
26 | + | |
27 | +char* sound_statement(){ | |
28 | + char *err; | |
29 | + err=get_label(); | |
30 | + if (err) return err; | |
31 | + if (g_label) { | |
32 | + // Label/number is constant. | |
33 | + // Linker will change following codes later. | |
34 | + // Note that 0x0814xxxx and 0x0815xxxx are specific codes for these. | |
35 | + check_obj_space(2); | |
36 | + g_object[g_objpos++]=0x08140000|((g_label>>16)&0x0000FFFF); // lui v0,xxxx | |
37 | + g_object[g_objpos++]=0x08150000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
38 | + } else { | |
39 | + // Label/number will be dynamically set when executing code. | |
40 | + err=get_value(); | |
41 | + if (err) return err; | |
42 | + call_lib_code(LIB_LABEL); | |
43 | + } | |
44 | + // 2nd param is optional | |
45 | + next_position(); | |
46 | + if (g_source[g_srcpos]==',') { | |
47 | + g_srcpos++; | |
48 | + check_obj_space(2); | |
49 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
50 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
51 | + err=get_value(); | |
52 | + if (err) return err; | |
53 | + check_obj_space(3); | |
54 | + g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
55 | + g_object[g_objpos++]=0x8FA20004; // lw v0,4(sp) | |
56 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
57 | + } else { | |
58 | + // Set 3 if omitted | |
59 | + check_obj_space(1); | |
60 | + g_object[g_objpos++]=0x24040003; // addiu a0,zero,xx | |
61 | + } | |
62 | + call_lib_code(LIB_SOUND); | |
63 | + return 0; | |
64 | +} | |
65 | +char* music_statement(){ | |
66 | + char *err; | |
67 | + err=get_string(); | |
68 | + if (err) return err; | |
69 | + // 2nd param is optional | |
70 | + next_position(); | |
71 | + if (g_source[g_srcpos]==',') { | |
72 | + g_srcpos++; | |
73 | + check_obj_space(2); | |
74 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
75 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
76 | + err=get_value(); | |
77 | + if (err) return err; | |
78 | + check_obj_space(3); | |
79 | + g_object[g_objpos++]=0x00402021; // addu a0,v0,zero | |
80 | + g_object[g_objpos++]=0x8FA20004; // lw v0,4(sp) | |
81 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
82 | + } else { | |
83 | + // Set 3 if omitted | |
84 | + check_obj_space(1); | |
85 | + g_object[g_objpos++]=0x24040003; // addiu a0,zero,xx | |
86 | + } | |
87 | + call_lib_code(LIB_MUSIC); | |
88 | + return 0; | |
89 | +} | |
90 | + | |
91 | +char* exec_statement(){ | |
92 | + char *err; | |
93 | + char b1; | |
94 | + int i,prevpos; | |
95 | + b1=g_source[g_srcpos]; | |
96 | + while('0'<=b1 && b1<='9' || b1=='-' || b1=='$'){ | |
97 | + prevpos=g_objpos; | |
98 | + g_valueisconst=1; | |
99 | + err=get_simple_value(); | |
100 | + if (!g_valueisconst) err=ERR_SYNTAX; | |
101 | + if (err) return err; | |
102 | + check_obj_space(1); | |
103 | + g_objpos=prevpos; | |
104 | + g_object[g_objpos++]=g_intconst; | |
105 | + next_position(); | |
106 | + b1=g_source[g_srcpos]; | |
107 | + if (b1!=',') break; | |
108 | + g_srcpos++; | |
109 | + next_position(); | |
110 | + b1=g_source[g_srcpos]; | |
111 | + if (b1==0x0d || b1==0x0a) { | |
112 | + // Multiline DATA/EXEC statement | |
113 | + g_line++; | |
114 | + g_fileline++; | |
115 | + if (b1==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
116 | + g_srcpos++; | |
117 | + // Maintain at least 256 characters in cache. | |
118 | + if (256<=g_srcpos) read_file(256); | |
119 | + next_position(); | |
120 | + b1=g_source[g_srcpos]; | |
121 | + } | |
122 | + } | |
123 | + return 0; | |
124 | +} | |
125 | + | |
126 | +char* cdata_statement(){ | |
127 | + // 0x00000020, 0x00000021, 0x00000022, and 0x00000023 (add/addu/sub/subu zero,zero,zero) | |
128 | + // are the sign of data region | |
129 | + int beginpos,prevpos; | |
130 | + char* err; | |
131 | + char b1; | |
132 | + char* cpy; | |
133 | + int shift=0; | |
134 | + int i=0; | |
135 | + // This statement is not valid in class file. | |
136 | + if (g_compiling_class) return ERR_INVALID_CLASS; | |
137 | + beginpos=g_objpos; | |
138 | + check_obj_space(2); | |
139 | + g_object[g_objpos++]=0x04110000; // bgezal zero,xxxx | |
140 | + g_object[g_objpos++]=0x00000020; // add zero,zero,zero | |
141 | + next_position(); | |
142 | + b1=g_source[g_srcpos]; | |
143 | + while('0'<=b1 && b1<='9' || b1=='-' || b1=='$'){ | |
144 | + prevpos=g_objpos; | |
145 | + g_valueisconst=1; | |
146 | + err=get_simple_value(); | |
147 | + if (!g_valueisconst) err=ERR_SYNTAX; | |
148 | + if (g_intconst<0x00 || 0xff<g_intconst) err=ERR_SYNTAX; | |
149 | + if (err) return err; | |
150 | + g_objpos=prevpos; | |
151 | + i|=g_intconst<<shift; | |
152 | + shift+=8; | |
153 | + if (32<=shift) { | |
154 | + check_obj_space(1); | |
155 | + g_object[g_objpos++]=i; | |
156 | + shift=0; | |
157 | + i=0; | |
158 | + } | |
159 | + next_position(); | |
160 | + b1=g_source[g_srcpos]; | |
161 | + if (b1!=',') break; | |
162 | + g_srcpos++; | |
163 | + next_position(); | |
164 | + b1=g_source[g_srcpos]; | |
165 | + if (b1==0x0d || b1==0x0a) { | |
166 | + // Multiline CDATA statement | |
167 | + g_line++; | |
168 | + g_fileline++; | |
169 | + if (b1==0x0D && g_source[g_srcpos+1]==0x0A) g_srcpos++; | |
170 | + g_srcpos++; | |
171 | + // Maintain at least 256 characters in cache. | |
172 | + if (256<=g_srcpos) read_file(256); | |
173 | + next_position(); | |
174 | + b1=g_source[g_srcpos]; | |
175 | + } | |
176 | + } | |
177 | + // Write the last 1-3 bytes and shift data if total # is not multipes of 4. | |
178 | + if (0<shift) { | |
179 | + // Convert shift value from bit-shift to data byte-shift. | |
180 | + shift=4-shift/8; | |
181 | + check_obj_space(1); | |
182 | + g_object[g_objpos++]=i; | |
183 | + for(cpy=(char*)&g_object[g_objpos]-1;(char*)&g_object[beginpos+2]<cpy;cpy--){ | |
184 | + cpy[0]=cpy[0-shift]; | |
185 | + } | |
186 | + } | |
187 | + // Determine the size of data | |
188 | + i=g_objpos-beginpos-1; | |
189 | + g_object[beginpos] =0x04110000|i; // bgezal zero,xxxx | |
190 | + g_object[beginpos+1]=0x00000020|shift; // add zero,zero,zero | |
191 | + return 0; | |
192 | +} | |
193 | + | |
194 | +char* data_statement(){ | |
195 | + // 0x00000020, 0x00000021, 0x00000022, and 0x00000023 (add/addu/sub/subu zero,zero,zero) | |
196 | + // are the sign of data region | |
197 | + int i,prevpos; | |
198 | + char* err; | |
199 | + // This statement is not valid in class file. | |
200 | + if (g_compiling_class) return ERR_INVALID_CLASS; | |
201 | + while(1){ | |
202 | + prevpos=g_objpos; | |
203 | + check_obj_space(2); | |
204 | + g_object[g_objpos++]=0x04110000; // bgezal zero,xxxx | |
205 | + g_object[g_objpos++]=0x00000020; // add zero,zero,zero | |
206 | + next_position(); | |
207 | + if (g_source[g_srcpos]=='"') { | |
208 | + // Constant string | |
209 | + // Store pointer to string. This is 3 words bellow of current position | |
210 | + g_object[g_objpos]=(int)(&g_object[g_objpos+3]); | |
211 | + g_objpos++; | |
212 | + g_object[prevpos]=0x04110002; // bgezal zero,xxxx | |
213 | + err=simple_string(); | |
214 | + if (err) return err; | |
215 | + next_position(); | |
216 | + if (g_source[g_srcpos]==',') { | |
217 | + g_srcpos++; | |
218 | + continue; | |
219 | + } | |
220 | + return 0; | |
221 | + } | |
222 | + err=exec_statement(); | |
223 | + if (err) return err; | |
224 | + // Determine the size of data | |
225 | + i=g_objpos-prevpos-1; | |
226 | + g_object[prevpos]=0x04110000|i; // bgezal zero,xxxx | |
227 | + if (g_source[g_srcpos]=='"') { | |
228 | + // Constant string | |
229 | + continue; | |
230 | + } | |
231 | + return 0; | |
232 | + } | |
233 | +} | |
234 | + | |
235 | +char* clear_statement(){ | |
236 | + call_lib_code(LIB_CLEAR); | |
237 | + return 0; | |
238 | +} | |
239 | + | |
240 | +char* poke_statement_sub(int bits){ | |
241 | + char* err; | |
242 | + err=get_value(); | |
243 | + if (err) return err; | |
244 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
245 | + g_srcpos++; | |
246 | + check_obj_space(2); | |
247 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
248 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
249 | + err=get_value(); | |
250 | + if (err) return err; | |
251 | + check_obj_space(3); | |
252 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
253 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
254 | + switch(bits){ | |
255 | + case 32: | |
256 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
257 | + break; | |
258 | + case 16: | |
259 | + g_object[g_objpos++]=0xA4620000; // sh v0,0(v1) | |
260 | + break; | |
261 | + case 8: | |
262 | + default: | |
263 | + g_object[g_objpos++]=0xA0620000; // sb v0,0(v1) | |
264 | + break; | |
265 | + } | |
266 | + return 0; | |
267 | +} | |
268 | + | |
269 | +char* dim_statement(){ | |
270 | + char* err; | |
271 | + char b1; | |
272 | + int i; | |
273 | + int spos; | |
274 | + int stack; | |
275 | + while(1){ | |
276 | + stack=0; | |
277 | + next_position(); | |
278 | + i=get_var_number(); | |
279 | + if (i<0) return ERR_SYNTAX; | |
280 | + if (g_source[g_srcpos]=='#') g_srcpos++; | |
281 | + next_position(); | |
282 | + if (g_source[g_srcpos]!='(') return ERR_SYNTAX; | |
283 | + check_obj_space(1); | |
284 | + spos=g_objpos++; // addiu sp,sp,xxxx | |
285 | + do { | |
286 | + g_srcpos++; | |
287 | + err=get_value(); | |
288 | + if (err) return err; | |
289 | + stack+=4; | |
290 | + check_obj_space(1); | |
291 | + g_object[g_objpos++]=0xAFA20000|stack; // sw v0,8(sp) | |
292 | + } while (g_source[g_srcpos]==','); | |
293 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
294 | + g_srcpos++; | |
295 | + check_obj_space(3); | |
296 | + g_object[g_objpos++]=0x24040000|(i); // addiu a0,zero,xx | |
297 | + g_object[g_objpos++]=0x24050000|(stack/4); // addiu a1,zero,xxxx | |
298 | + g_object[g_objpos++]=0x03A01025; // or v0,sp,zero | |
299 | + call_lib_code(LIB_DIM); | |
300 | + // Stack -/+ | |
301 | + check_obj_space(1); | |
302 | + g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xxxx | |
303 | + stack=(0-stack)&0x0000FFFF; | |
304 | + g_object[spos]=0x27BD0000|stack; // addiu sp,sp,xxxx | |
305 | + next_position(); | |
306 | + if (g_source[g_srcpos]!=',') break; | |
307 | + g_srcpos++; | |
308 | + } | |
309 | + return 0; | |
310 | +} | |
311 | + | |
312 | +char* label_statement(){ | |
313 | + char* err; | |
314 | + char b1; | |
315 | + b1=g_source[g_srcpos]; | |
316 | + if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; // Number is not allowed here. | |
317 | + err=get_label(); | |
318 | + if (err) return err; | |
319 | + // Check existing label with the same name here. | |
320 | + if (search_label(g_label)) { | |
321 | + // Error: duplicate labels | |
322 | + printstr("Label "); | |
323 | + printstr(resolve_label(g_label)); | |
324 | + return ERR_MULTIPLE_LABEL; | |
325 | + } | |
326 | + check_obj_space(2); | |
327 | + g_object[g_objpos++]=0x3C160000|((g_label>>16)&0x0000FFFF); //lui s6,yyyy; | |
328 | + g_object[g_objpos++]=0x36D60000|(g_label&0x0000FFFF); //ori s6,s6,zzzz; | |
329 | + return 0; | |
330 | +} | |
331 | + | |
332 | +char* restore_statement(){ | |
333 | + char* err; | |
334 | + // This statement is not valid in class file. | |
335 | + if (g_compiling_class) return ERR_INVALID_CLASS; | |
336 | + err=get_label(); | |
337 | + if (err) return err; | |
338 | + if (g_label) { | |
339 | + // Constant label/number | |
340 | + // Use 32 bit mode also for values<65536 | |
341 | + // This code will be replaced to code for v0 for pointer in linker. | |
342 | + check_obj_space(2); | |
343 | + g_object[g_objpos++]=0x3C020000|(g_label>>16); // lui v0,xxxx | |
344 | + g_object[g_objpos++]=0x34420000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
345 | + } else { | |
346 | + // Dynamic number | |
347 | + err=get_value(); | |
348 | + if (err) return err; | |
349 | + } | |
350 | + call_lib_code(LIB_RESTORE); | |
351 | + return 0; | |
352 | +} | |
353 | + | |
354 | +char* gosub_statement_sub(){ | |
355 | + char* err; | |
356 | + err=get_label(); | |
357 | + if (err) return err; | |
358 | + if (g_label) { | |
359 | + // Label/number is constant. | |
360 | + // Linker will change following codes later. | |
361 | + // Note that 0x0812xxxx and 0x0813xxxx are specific codes for these. | |
362 | + check_obj_space(7); | |
363 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
364 | + g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
365 | + g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5) | |
366 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
367 | + g_object[g_objpos++]=0x08120000|((g_label>>16)&0x0000FFFF); // nop | |
368 | + // label1: | |
369 | + g_object[g_objpos++]=0x08130000|(g_label&0x0000FFFF); // j xxxx | |
370 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
371 | + // label2: | |
372 | + } else { | |
373 | + // Label/number will be dynamically set when executing code. | |
374 | + err=get_value(); | |
375 | + if (err) return err; | |
376 | + call_lib_code(LIB_LABEL); | |
377 | + check_obj_space(7); | |
378 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
379 | + g_object[g_objpos++]=0x04130003; // bgezall zero,label1 | |
380 | + g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5) | |
381 | + g_object[g_objpos++]=0x10000003; // beq zero,zero,label2 | |
382 | + g_object[g_objpos++]=0x00000000; // nop | |
383 | + // label1: | |
384 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
385 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
386 | + // label2: | |
387 | + } | |
388 | + return 0; | |
389 | +} | |
390 | + | |
391 | +char* gosub_statement(){ | |
392 | + char* err; | |
393 | + int opos,spos,stack; | |
394 | + // Skip label first (see below) | |
395 | + opos=g_objpos; | |
396 | + spos=g_srcpos; | |
397 | + err=gosub_statement_sub(); | |
398 | + if (err) return err; | |
399 | + next_position(); | |
400 | + // Rewind object and construct argument-creating routine. | |
401 | + g_objpos=opos; | |
402 | + // Begin parameter(s) construction routine | |
403 | + g_object[g_objpos++]=0x8EA20000|ARGS_S5_V0_OBJ; // lw v0,-8(s5) | |
404 | + err=prepare_args_stack(','); | |
405 | + if (err) return err; | |
406 | + // Rewind source and construct GOSUB routine again. | |
407 | + opos=spos; | |
408 | + spos=g_srcpos; | |
409 | + g_srcpos=opos; | |
410 | + err=gosub_statement_sub(); | |
411 | + if (err) return err; | |
412 | + // Remove stack | |
413 | + err=remove_args_stack(); | |
414 | + if (err) return err; | |
415 | + // All done, go back to right source position | |
416 | + g_srcpos=spos; | |
417 | + return 0; | |
418 | +} | |
419 | + | |
420 | +char* return_statement(){ | |
421 | + char* err; | |
422 | + char b1; | |
423 | + next_position(); | |
424 | + b1=g_source[g_srcpos]; | |
425 | + if (0x20<b1 && b1!=':') { | |
426 | + // There is a return value. | |
427 | + err=get_stringFloatOrValue(); | |
428 | + if (err) return err; | |
429 | + } | |
430 | + check_obj_space(4); | |
431 | + g_object[g_objpos++]=0x8EBD0000|ARGS_S5_SP; // lw sp,-12(s5) | |
432 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
433 | + g_object[g_objpos++]=0x00600008; // jr v1 | |
434 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
435 | + return 0; | |
436 | +} | |
437 | + | |
438 | +char* goto_statement(){ | |
439 | + char* err; | |
440 | + err=get_label(); | |
441 | + if (err) return err; | |
442 | + if (g_label) { | |
443 | + // Label/number is constant. | |
444 | + // Linker will change following codes later. | |
445 | + // Note that 0x0810xxxx and 0x0811xxxx are specific codes for these. | |
446 | + check_obj_space(2); | |
447 | + g_object[g_objpos++]=0x08100000|((g_label>>16)&0x0000FFFF); // j xxxx | |
448 | + g_object[g_objpos++]=0x08110000|(g_label&0x0000FFFF); // nop | |
449 | + } else { | |
450 | + // Label/number will be dynamically set when executing code. | |
451 | + err=get_value(); | |
452 | + if (err) return err; | |
453 | + call_lib_code(LIB_LABEL); | |
454 | + check_obj_space(2); | |
455 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
456 | + g_object[g_objpos++]=0x00000000; // nop | |
457 | + } | |
458 | + return 0; | |
459 | +} | |
460 | + | |
461 | +char* if_statement(){ | |
462 | + char* err; | |
463 | + int prevpos,bpos; | |
464 | + // Get value. | |
465 | + err=get_floatOrValue(); | |
466 | + if (err) return err; | |
467 | + // Check "THEN" | |
468 | + if (!nextCodeIs("THEN")) return ERR_SYNTAX; | |
469 | + // Check if statement follows after THEN statement | |
470 | + next_position(); | |
471 | + if (nextCodeIs("REM")) { | |
472 | + // If REM statement follows, skip comment words. | |
473 | + rem_statement(); | |
474 | + } | |
475 | + if (g_source[g_srcpos]<0x20) { | |
476 | + // End of line. | |
477 | + // Use IF-THEN-ENDIF mode (multiple line mode) | |
478 | + check_obj_space(3); | |
479 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
480 | + g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
481 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
482 | + return 0; | |
483 | + } | |
484 | + // One line mode | |
485 | + // If $v0=0 then skip. | |
486 | + bpos=g_objpos; | |
487 | + check_obj_space(2); | |
488 | + g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
489 | + g_object[g_objpos++]=0x00000000; // nop | |
490 | + prevpos=g_srcpos; | |
491 | + if (statement()) { | |
492 | + // May be label | |
493 | + g_srcpos=prevpos; | |
494 | + err=goto_statement(); | |
495 | + if (err) return err; | |
496 | + } else { | |
497 | + // Must be statement(s) | |
498 | + while(1) { | |
499 | + if (g_source[g_srcpos]!=':') break; | |
500 | + g_srcpos++; | |
501 | + err=statement(); | |
502 | + if (err) return err; | |
503 | + } | |
504 | + } | |
505 | + // Check if "ELSE" exists. | |
506 | + if (!nextCodeIs("ELSE ")) { | |
507 | + // "ELSE" not found. This is the end of "IF" statement. | |
508 | + // Previous branch command must jump to this position. | |
509 | + g_object[bpos]=0x10400000|(g_objpos-bpos-1); // beq v0,zero,xxxx | |
510 | + return 0; | |
511 | + } | |
512 | + // Skip after ELSE if required. | |
513 | + check_obj_space(2); | |
514 | + g_object[g_objpos++]=0x10000000; // beq zero,zero,xxxx | |
515 | + g_object[g_objpos++]=0x00000000; // nop | |
516 | + // Previous branch command must jump to this position. | |
517 | + g_object[bpos]=0x10400000|(g_objpos-bpos-1); // beq v0,zero,xxxx | |
518 | + bpos=g_objpos-2; | |
519 | + // Next statement is either label or general statement | |
520 | + prevpos=g_srcpos; | |
521 | + if (statement()) { | |
522 | + // May be label | |
523 | + g_srcpos=prevpos; | |
524 | + err=goto_statement(); | |
525 | + if (err) return err; | |
526 | + } else { | |
527 | + // Must be statement(s) | |
528 | + while(1) { | |
529 | + if (g_source[g_srcpos]!=':') break; | |
530 | + g_srcpos++; | |
531 | + err=statement(); | |
532 | + if (err) return err; | |
533 | + } | |
534 | + } | |
535 | + // Previous branch command must jump to this position. | |
536 | + g_object[bpos]=0x10000000|(g_objpos-bpos-1); // beq zero,zero,xxxx | |
537 | + return 0; | |
538 | +} | |
539 | + | |
540 | +char* elseif_statement(void){ | |
541 | + // Multiple line mode | |
542 | + char* err; | |
543 | + g_object[g_objpos++]=0x08160100; // breakif (see linker) | |
544 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
545 | + // Get value. | |
546 | + err=get_floatOrValue(); | |
547 | + if (err) return err; | |
548 | + // Check "THEN" | |
549 | + if (!nextCodeIs("THEN")) return ERR_SYNTAX; | |
550 | + // Check if statement follows after THEN statement | |
551 | + if (nextCodeIs("REM")) { | |
552 | + // If REM statement follows, skip comment words. | |
553 | + rem_statement(); | |
554 | + } | |
555 | + if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
556 | + // Statement didn't follow after THEM statement (that is correct). | |
557 | + g_object[g_objpos++]=0x10400000; // beq v0,zero,xxxx | |
558 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
559 | + return 0; | |
560 | + | |
561 | +} | |
562 | + | |
563 | +char* else_statement(void){ | |
564 | + // Multiple line mode | |
565 | + g_object[g_objpos++]=0x08160100; // breakif (see linker) | |
566 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
567 | + g_object[g_objpos++]=0x30000000; // nop (see linker) | |
568 | + // Check if statement follows after THEN statement | |
569 | + if (nextCodeIs("REM")) { | |
570 | + // If REM statement follows, skip comment words. | |
571 | + rem_statement(); | |
572 | + } | |
573 | + if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
574 | + // Statement didn't follow after THEM statement (that is correct). | |
575 | + return 0; | |
576 | +} | |
577 | + | |
578 | +char* endif_statement(void){ | |
579 | + // Multiple line mode | |
580 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
581 | + g_object[g_objpos++]=0x30008000; // nop (see linker) | |
582 | + // Check if statement follows after THEN statement | |
583 | + if (nextCodeIs("REM")) { | |
584 | + // If REM statement follows, skip comment words. | |
585 | + rem_statement(); | |
586 | + } | |
587 | + if (0x20<=g_source[g_srcpos]) return ERR_SYNTAX; | |
588 | + // Statement didn't follow after THEM statement (that is correct). | |
589 | + return 0; | |
590 | +} | |
591 | + | |
592 | +char* end_statement(void){ | |
593 | + int i; | |
594 | + i=(int)&g_end_addr; | |
595 | + i-=g_gp; | |
596 | + check_obj_space(3); | |
597 | + g_object[g_objpos++]=0x8F820000|(i&0x0000FFFF); // lw v0,xxxx(gp) | |
598 | + g_object[g_objpos++]=0x00400008; // jr v0 | |
599 | + g_object[g_objpos++]=0x00000000; // nop | |
600 | + return 0; | |
601 | +} | |
602 | + | |
603 | +char* let_dim_sub(int i){ | |
604 | + char* err; | |
605 | + g_srcpos++; | |
606 | + err=get_value(); | |
607 | + if (err) return err; | |
608 | + check_obj_space(4); | |
609 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
610 | + g_object[g_objpos++]=0x8FC30000|(i*4); // lw v1,xx(s8) | |
611 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
612 | + g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
613 | + while(g_source[g_srcpos]==','){ | |
614 | + g_srcpos++; | |
615 | + err=get_value(); | |
616 | + if (err) return err; | |
617 | + check_obj_space(4); | |
618 | + g_object[g_objpos++]=0x00021080; // sll v0,v0,0x2 | |
619 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
620 | + g_object[g_objpos++]=0x8C630000; // lw v1,0(v1) | |
621 | + g_object[g_objpos++]=0x00621821; // addu v1,v1,v0 | |
622 | + g_object[g_objpos++]=0xAFA30004; // sw v1,4(sp) | |
623 | + } | |
624 | + if (g_source[g_srcpos]!=')') return ERR_SYNTAX; | |
625 | + g_srcpos++; | |
626 | + return 0; | |
627 | +}; | |
628 | + | |
629 | +char* let_statement(){ | |
630 | + char* err; | |
631 | + char b2,b3; | |
632 | + int i,spos,opos; | |
633 | + next_position(); | |
634 | + i=get_var_number(); | |
635 | + if (i<0) return ERR_SYNTAX; | |
636 | + b2=g_source[g_srcpos]; | |
637 | + b3=g_source[g_srcpos+1]; | |
638 | + if (b2=='#' && b3=='(') { | |
639 | + // Float dimension | |
640 | + g_srcpos++; | |
641 | + check_obj_space(1); | |
642 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
643 | + let_dim_sub(i); | |
644 | + next_position(); | |
645 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
646 | + g_srcpos++; | |
647 | + err=get_float(); | |
648 | + if (err) return err; | |
649 | + check_obj_space(3); | |
650 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
651 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
652 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
653 | + return 0; | |
654 | + } else if (b2=='#') { | |
655 | + // Float A-Z | |
656 | + g_srcpos++; | |
657 | + next_position(); | |
658 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
659 | + g_srcpos++; | |
660 | + err=get_float(); | |
661 | + if (err) return err; | |
662 | + check_obj_space(1); | |
663 | + g_object[g_objpos++]=0xAFC20000|(i*4); // sw v0,xxx(s8) | |
664 | + return 0; | |
665 | + } else if (b2=='$') { | |
666 | + // String | |
667 | + g_srcpos++; | |
668 | + next_position(); | |
669 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
670 | + g_srcpos++; | |
671 | + err=get_string(); | |
672 | + if (err) return err; | |
673 | + check_obj_space(1); | |
674 | + g_object[g_objpos++]=0x24040000|(i); //addiu a0,zero,xx | |
675 | + call_lib_code(LIB_LETSTR); | |
676 | + return 0; | |
677 | + } else if (b2=='(') { | |
678 | + // Dimension | |
679 | + check_obj_space(1); | |
680 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
681 | + let_dim_sub(i); | |
682 | + if (g_source[g_srcpos]=='.') { | |
683 | + // This is an object. Determine the filed of this object. | |
684 | + // 4(sp) contains the address of dimension value | |
685 | + // The dimension value is the pointer to object | |
686 | + g_srcpos++; | |
687 | + check_obj_space(3); | |
688 | + g_object[g_objpos++]=0x8FA20004; // lw v0,4(sp) | |
689 | + g_object[g_objpos++]=0x8C420000; // lw v0,0(v0) + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
690 | + return let_object_field(); | |
691 | + } | |
692 | + next_position(); | |
693 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
694 | + g_srcpos++; | |
695 | + err=get_value(); | |
696 | + if (err) return err; | |
697 | + check_obj_space(3); | |
698 | + g_object[g_objpos++]=0x8FA30004; // lw v1,4(sp) | |
699 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
700 | + g_object[g_objpos++]=0xAC620000; // sw v0,0(v1) | |
701 | + return 0; | |
702 | + } else if (b2=='.') { | |
703 | + // Field of object | |
704 | + g_srcpos++; | |
705 | + check_obj_space(1); | |
706 | + g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
707 | + return let_object_field(); | |
708 | + } else { | |
709 | + // Integer A-Z | |
710 | + next_position(); | |
711 | + if (g_source[g_srcpos]!='=') return ERR_SYNTAX; | |
712 | + g_srcpos++; | |
713 | + err=get_value(); | |
714 | + if (err) return err; | |
715 | + check_obj_space(1); | |
716 | + g_object[g_objpos++]=0xAFC20000|(i*4); // sw v0,xxx(s8) | |
717 | + } | |
718 | + return 0; | |
719 | +} | |
720 | + | |
721 | +char* print_statement_main(enum libs lib_printstr, enum libs lib_string){ | |
722 | + char* err; | |
723 | + char b1; | |
724 | + int i; | |
725 | + int status=0;// 1:',' 2:';' 0:none | |
726 | + while(1){ | |
727 | + next_position(); | |
728 | + if (endOfStatement()) break; | |
729 | + if (!strncmp(g_source+g_srcpos,"ELSE " ,5)) break; | |
730 | + err=get_stringFloatOrValue(); | |
731 | + if (err) return err; | |
732 | + switch(g_lastvar){ | |
733 | + case VAR_INTEGER: | |
734 | + // Use DEC$() function. | |
735 | + call_lib_code(LIB_DEC); | |
736 | + break; | |
737 | + case VAR_FLOAT: | |
738 | + // Use FLOAT$() function. | |
739 | + check_obj_space(2); | |
740 | + g_object[g_objpos++]=0x00022021; //addu a0,zero,v0 | |
741 | + g_object[g_objpos++]=0x34020000; //ori v0,zero,0x0000 | |
742 | + call_lib_code(LIB_SPRINTF); | |
743 | + break; | |
744 | + case VAR_STRING: | |
745 | + default: | |
746 | + break; | |
747 | + } | |
748 | + // Call printstr() function | |
749 | + // First argument is the pointer to string | |
750 | + call_lib_code(lib_printstr); | |
751 | + next_position(); | |
752 | + b1=g_source[g_srcpos]; | |
753 | + if (b1==',') { | |
754 | + status=1; | |
755 | + g_srcpos++; | |
756 | + // Call lib_string() function for comma (,) | |
757 | + check_obj_space(1); | |
758 | + g_object[g_objpos++]=0x34020001; // ori v0,zero,1 | |
759 | + call_lib_code(lib_string); | |
760 | + } else if (b1==';') { | |
761 | + status=2; | |
762 | + g_srcpos++; | |
763 | + } else { | |
764 | + status=0; | |
765 | + } | |
766 | + } | |
767 | + if (status==0) { | |
768 | + // Call lib_string() function for CR (\n) | |
769 | + check_obj_space(1); | |
770 | + g_object[g_objpos++]=0x34020000; // ori v0,zero,0 | |
771 | + call_lib_code(lib_string); | |
772 | + } | |
773 | + return 0; | |
774 | +} | |
775 | + | |
776 | +char* break_statement(){ | |
777 | + check_obj_space(2); | |
778 | + g_object[g_objpos++]=0x08160000; // j xxxx (See link() function) | |
779 | + g_object[g_objpos++]=0x00000000; // nop | |
780 | + return 0; | |
781 | +} | |
782 | + | |
783 | +char* continue_statement(){ | |
784 | + check_obj_space(2); | |
785 | + g_object[g_objpos++]=0x08160008; // j xxxx (See link() function) | |
786 | + g_object[g_objpos++]=0x00000000; // nop | |
787 | + return 0; | |
788 | +} | |
789 | + | |
790 | +char* for_statement(){ | |
791 | + char* err; | |
792 | +// char b1; | |
793 | + int i; | |
794 | + int prepos=g_srcpos; | |
795 | + // Initialization of variable | |
796 | +// next_position(); | |
797 | +// b1=g_source[g_srcpos]; | |
798 | + i=get_var_number(); | |
799 | +// if (b1<'A' || 'Z'<b1) return ERR_SYNTAX; | |
800 | + if (i<0) return ERR_SYNTAX; | |
801 | + g_srcpos=prepos; | |
802 | + err=let_statement(); | |
803 | + if (err) return err; | |
804 | + // Check if "TO" exists | |
805 | + if (!nextCodeIs("TO ")) return ERR_SYNTAX; | |
806 | + err=get_value(); | |
807 | + if (err) return err; | |
808 | + // Usage of stack: | |
809 | + // 12(sp): "TO" value | |
810 | + // 8(sp): "STEP" value | |
811 | + // 4(sp): Address to return to in "NEXT" statement. | |
812 | + // Store "TO" value in stack | |
813 | + check_obj_space(2); | |
814 | + g_object[g_objpos++]=0x0820FFF4; // addiu sp,sp,-12 (see linker) | |
815 | + g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
816 | + // Check if "STEP" exists | |
817 | + g_valueisconst=1; | |
818 | + if (nextCodeIs("STEP ")) { | |
819 | + // "STEP" exists. Get value | |
820 | + err=get_value(); | |
821 | + if (err) return err; | |
822 | + } else { | |
823 | + // "STEP" not exist. Use "1". | |
824 | + check_obj_space(1); | |
825 | + g_object[g_objpos++]=0x24020001; // addiu v0,zero,1 | |
826 | + g_intconst=1; | |
827 | + } | |
828 | + check_obj_space(14); | |
829 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) (STEP value) | |
830 | + g_object[g_objpos++]=0x04130004; // bgezall zero,check | |
831 | +// g_object[g_objpos++]=0x8FC40000|((b1-'A')*4); // lw a0,xx(s8) (current var value) | |
832 | + g_object[g_objpos++]=0x8FC40000|(i*4); // lw a0,xx(s8) (current var value) | |
833 | + // After executing "NEXT" statement, process reaches following line. | |
834 | + // Update variable value by adding STEP value | |
835 | + // Note that STEP value is loaded onto $v0 in NEXT statement | |
836 | +// g_object[g_objpos++]=0x8FC40000|((b1-'A')*4); // lw a0,xx(s8) (current var value) | |
837 | + g_object[g_objpos++]=0x8FC40000|(i*4); // lw a0,xx(s8) (current var value) | |
838 | + g_object[g_objpos++]=0x00822021; // addu a0,a0,v0 | |
839 | +// g_object[g_objpos++]=0xAFC40000|((b1-'A')*4); // sw a0,xx(s8) (new var value) | |
840 | + g_object[g_objpos++]=0xAFC40000|(i*4); // sw a0,xx(s8) (new var value) | |
841 | + // Value-checking routine and storing ra in stack | |
842 | + // check: | |
843 | + g_object[g_objpos++]=0x8FA3000C; // lw v1,12(sp) (TO value) | |
844 | + g_object[g_objpos++]=0x00641823; // subu v1,v1,a0 | |
845 | + g_object[g_objpos++]=0x04420001; // bltzl v0,negative | |
846 | + g_object[g_objpos++]=0x00031823; // subu v1,zero,v1 | |
847 | + // negative: | |
848 | + g_object[g_objpos++]=0x04610003; // bgez v1,continue | |
849 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
850 | + break_statement(); // (2 words) | |
851 | + // continue: | |
852 | + return 0; | |
853 | +} | |
854 | + | |
855 | +char* next_statement(){ | |
856 | + // Return to address stored in 4($sp) | |
857 | + // while set $v0 to 8($sp) (see for_statement) | |
858 | + // Following assembly must be 4 words. | |
859 | + // If the number of words will be changed, link.c must be reviced for CONTINUE statement. | |
860 | + check_obj_space(4); | |
861 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
862 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
863 | + g_object[g_objpos++]=0x8FA20008; // lw v0,8(sp) (STEP value) | |
864 | + g_object[g_objpos++]=0x0830000C; // addiu sp,sp,12 (see linker) | |
865 | + return 0; | |
866 | +} | |
867 | + | |
868 | +char* do_statement(){ | |
869 | + char* err; | |
870 | + // Usage of stack: | |
871 | + // 4(sp): Address to return to in "DO" statement. | |
872 | + check_obj_space(3); | |
873 | + g_object[g_objpos++]=0x04130001;// bgezall zero,label1: | |
874 | + g_object[g_objpos++]=0x0822FFFC;// addiu sp,sp,-4 (see linker) | |
875 | + // label1: | |
876 | + g_object[g_objpos++]=0xAFBF0004;// sw ra,4(sp) | |
877 | + if (nextCodeIs("WHILE ")) { | |
878 | + // DO WHILE | |
879 | + err=get_floatOrValue(); | |
880 | + if (err) return err; | |
881 | + check_obj_space(2); | |
882 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,labe2 | |
883 | + g_object[g_objpos++]=0x00000000; // nop | |
884 | + return break_statement(); // (2 words) | |
885 | + // label2: | |
886 | + | |
887 | + } else if (nextCodeIs("UNTIL ")) { | |
888 | + // DO UNTIL | |
889 | + err=get_floatOrValue(); | |
890 | + if (err) return err; | |
891 | + check_obj_space(2); | |
892 | + g_object[g_objpos++]=0x10400003; // beq v0,zero,label2 | |
893 | + g_object[g_objpos++]=0x00000000; // nop | |
894 | + return break_statement(); // (2 words) | |
895 | + // label2: | |
896 | + } else { | |
897 | + // DO statement without WHILE/UNTIL | |
898 | + return 0; | |
899 | + } | |
900 | +} | |
901 | + | |
902 | +char* loop_statement(){ | |
903 | + char* err; | |
904 | + int opos; | |
905 | + opos=g_objpos; | |
906 | + if (nextCodeIs("WHILE ")) { | |
907 | + // LOOP WHILE | |
908 | + err=get_floatOrValue(); | |
909 | + if (err) return err; | |
910 | + check_obj_space(1); | |
911 | + g_object[g_objpos++]=0x10400003; // beq v0,zero,label1 | |
912 | + } else if (nextCodeIs("UNTIL ")) { | |
913 | + // LOOP UNTIL | |
914 | + err=get_floatOrValue(); | |
915 | + if (err) return err; | |
916 | + check_obj_space(1); | |
917 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,label | |
918 | + } else { | |
919 | + // LOOP statement without WHILE/UNTIL | |
920 | + } | |
921 | + check_obj_space(4); | |
922 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
923 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
924 | + opos=g_objpos+1-opos; | |
925 | + g_object[g_objpos++]=0x3000F000|opos; // nop (See linker, used for CONTINUE statement) | |
926 | + // label1: | |
927 | + g_object[g_objpos++]=0x08320004; // addiu sp,sp,4 (See link() function) | |
928 | + return 0; | |
929 | +} | |
930 | + | |
931 | +char* while_statement(){ | |
932 | + char* err; | |
933 | + check_obj_space(3); | |
934 | + g_object[g_objpos++]=0x04130001; // bgezall zero,label1: | |
935 | + g_object[g_objpos++]=0x0821FFFC; // addiu sp,sp,-4 (see linker) | |
936 | + // label1: | |
937 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
938 | + err=get_floatOrValue(); | |
939 | + if (err) return err; | |
940 | + check_obj_space(2); | |
941 | + g_object[g_objpos++]=0x14400003; // bne v0,zero,label2 | |
942 | + g_object[g_objpos++]=0x00000000; // nop | |
943 | + return break_statement(); // (2 words) | |
944 | + // label2: | |
945 | +} | |
946 | + | |
947 | +char* wend_statement(){ | |
948 | + check_obj_space(4); | |
949 | + g_object[g_objpos++]=0x8FBF0004; // lw ra,4(sp) | |
950 | + g_object[g_objpos++]=0x03E00008; // jr ra | |
951 | + g_object[g_objpos++]=0x3000F003; // nop (See linker, used for CONTINUE statement) | |
952 | + // label1: | |
953 | + g_object[g_objpos++]=0x08310004; // addiu sp,sp,4 (See link() function) | |
954 | + return 0; | |
955 | +} | |
956 | + | |
957 | +char* param4_statement(enum libs lib){ | |
958 | + // lib is either LIB_PALETTE or LIB_GPALETTE | |
959 | + // PALETTE N,R,G,B | |
960 | + char* err; | |
961 | + // Get N | |
962 | + err=get_value(); | |
963 | + if (err) return err; | |
964 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
965 | + g_srcpos++; | |
966 | + check_obj_space(2); | |
967 | + g_object[g_objpos++]=0x27BDFFF4; // addiu sp,sp,-12 | |
968 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
969 | + // Get R | |
970 | + err=get_value(); | |
971 | + if (err) return err; | |
972 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
973 | + g_srcpos++; | |
974 | + check_obj_space(1); | |
975 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
976 | + // Get G | |
977 | + err=get_value(); | |
978 | + if (err) return err; | |
979 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
980 | + g_srcpos++; | |
981 | + check_obj_space(1); | |
982 | + g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
983 | + // Get B | |
984 | + err=get_value(); | |
985 | + if (err) return err; | |
986 | + call_lib_code(lib); | |
987 | + check_obj_space(1); | |
988 | + g_object[g_objpos++]=0x27BD000C; // addiu sp,sp,12 | |
989 | + return 0; | |
990 | +} | |
991 | + | |
992 | +char* param3_statement(enum libs lib){ | |
993 | + char* err; | |
994 | + // Get 1st parameter | |
995 | + err=get_value(); | |
996 | + if (err) return err; | |
997 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
998 | + g_srcpos++; | |
999 | + check_obj_space(2); | |
1000 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
1001 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1002 | + // Get 2nd parameter | |
1003 | + err=get_value(); | |
1004 | + if (err) return err; | |
1005 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1006 | + g_srcpos++; | |
1007 | + check_obj_space(1); | |
1008 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1009 | + // Get 3rd parameter | |
1010 | + err=get_value(); | |
1011 | + if (err) return err; | |
1012 | + call_lib_code(lib); | |
1013 | + check_obj_space(1); | |
1014 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
1015 | + return 0; | |
1016 | +} | |
1017 | + | |
1018 | +char* bgcolor_statement(){ | |
1019 | + // BGCOLOR R,G,B | |
1020 | + return param3_statement(LIB_BGCOLOR); | |
1021 | +} | |
1022 | + | |
1023 | +char* pcg_statement(){ | |
1024 | + // PCG ASCII,D1,D2 | |
1025 | + return param3_statement(LIB_PCG); | |
1026 | +} | |
1027 | + | |
1028 | +char* usepcg_statement(){ | |
1029 | + int objpos=g_objpos; | |
1030 | + if (get_value()) { | |
1031 | + // Getting integer failed. | |
1032 | + // It supporsed to be not parameter | |
1033 | + // and same as parameter=1. | |
1034 | + g_objpos=objpos; | |
1035 | + check_obj_space(1); | |
1036 | + g_object[g_objpos++]=0x34020001; //ori v0,zero,0x01 | |
1037 | + } | |
1038 | + call_lib_code(LIB_USEPCG); | |
1039 | + return 0; | |
1040 | +} | |
1041 | + | |
1042 | +char* usegraphic_statement(){ | |
1043 | + int objpos=g_objpos; | |
1044 | + if (get_value()) { | |
1045 | + // Getting integer failed. | |
1046 | + // It supporsed to be not parameter | |
1047 | + // and same as parameter=1. | |
1048 | + g_objpos=objpos; | |
1049 | + check_obj_space(1); | |
1050 | + g_object[g_objpos++]=0x34020001; //ori v0,zero,0x01 | |
1051 | + } | |
1052 | + call_lib_code(LIB_USEGRAPHIC); | |
1053 | + return 0; | |
1054 | +} | |
1055 | + | |
1056 | +char* cls_statement(){ | |
1057 | + call_lib_code(LIB_CLS); | |
1058 | + return 0; | |
1059 | +} | |
1060 | + | |
1061 | +char* gcls_statement(){ | |
1062 | + call_lib_code(LIB_GCLS); | |
1063 | + return 0; | |
1064 | +} | |
1065 | + | |
1066 | +char* color_statement(){ | |
1067 | + char* err; | |
1068 | + err=get_value(); | |
1069 | + if (err) return err; | |
1070 | + call_lib_code(LIB_COLOR); | |
1071 | + return 0; | |
1072 | +} | |
1073 | + | |
1074 | +char* gcolor_statement(){ | |
1075 | + char* err; | |
1076 | + err=get_value(); | |
1077 | + if (err) return err; | |
1078 | + call_lib_code(LIB_GCOLOR); | |
1079 | + return 0; | |
1080 | +} | |
1081 | + | |
1082 | +char* param2_statement(enum libs lib){ | |
1083 | + char* err; | |
1084 | + // Get 1st | |
1085 | + err=get_value(); | |
1086 | + if (err) return err; | |
1087 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1088 | + g_srcpos++; | |
1089 | + check_obj_space(2); | |
1090 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
1091 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1092 | + // Get 2nd | |
1093 | + err=get_value(); | |
1094 | + if (err) return err; | |
1095 | + call_lib_code(lib); | |
1096 | + check_obj_space(1); | |
1097 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
1098 | + return 0; | |
1099 | +} | |
1100 | + | |
1101 | +char* system_statement(){ | |
1102 | + // SYSTEM X,Y | |
1103 | + char* err; | |
1104 | + // Get 1st | |
1105 | + err=get_value(); | |
1106 | + if (err) return err; | |
1107 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1108 | + g_srcpos++; | |
1109 | + check_obj_space(2); | |
1110 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
1111 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1112 | + // Get 2nd | |
1113 | + err=get_value(); | |
1114 | + if (err) return err; | |
1115 | + check_obj_space(2); | |
1116 | + g_object[g_objpos++]=0x8FA40004; // lw a0,4(sp) | |
1117 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
1118 | + call_lib_code(LIB_SYSTEM); | |
1119 | + return 0; | |
1120 | +} | |
1121 | + | |
1122 | +char* cursor_statement(){ | |
1123 | + // CURSOR X,Y | |
1124 | + return param2_statement(LIB_CURSOR); | |
1125 | +} | |
1126 | + | |
1127 | +char* scroll_statement(){ | |
1128 | + // SCROLL X,Y | |
1129 | + return param2_statement(LIB_SCROLL); | |
1130 | +} | |
1131 | + | |
1132 | +char* drawcount_statement(){ | |
1133 | + char* err; | |
1134 | + err=get_value(); | |
1135 | + if (err) return err; | |
1136 | + call_lib_code(LIB_SETDRAWCOUNT); | |
1137 | + return 0; | |
1138 | +} | |
1139 | + | |
1140 | +char* wait_statement(){ | |
1141 | + char* err; | |
1142 | + err=get_value(); | |
1143 | + if (err) return err; | |
1144 | + call_lib_code(LIB_WAIT); | |
1145 | + return 0; | |
1146 | +} | |
1147 | + | |
1148 | +char* width_statement(){ | |
1149 | + char* err; | |
1150 | + err=get_value(); | |
1151 | + if (err) return err; | |
1152 | + call_lib_code(LIB_WIDTH); | |
1153 | + return 0; | |
1154 | +} | |
1155 | + | |
1156 | +char* var_statement_sub(int a0, int a1){ | |
1157 | + // Construct parameter-setting scripts | |
1158 | + if (a0&0xffff0000) { | |
1159 | + check_obj_space(1); | |
1160 | + g_object[g_objpos++]=0x3C040000|(a0>>16); // lui a0,XXXX | |
1161 | + if (a0&0x0000ffff) { | |
1162 | + check_obj_space(1); | |
1163 | + g_object[g_objpos++]=0x34840000|(a0&0xffff); // ori a0,a0,XXXX | |
1164 | + } | |
1165 | + } else if (a0&0x0000ffff) { | |
1166 | + check_obj_space(1); | |
1167 | + g_object[g_objpos++]=0x34040000|(a0&0xffff); // ori a0,zero,xxxx | |
1168 | + } | |
1169 | + if (a1&0xffff0000) { | |
1170 | + check_obj_space(1); | |
1171 | + g_object[g_objpos++]=0x3C050000|(a1>>16); // lui a1,XXXX | |
1172 | + if (a1&0x0000ffff) { | |
1173 | + check_obj_space(1); | |
1174 | + g_object[g_objpos++]=0x34A50000|(a1&0xffff); // ori a1,a1,XXXX | |
1175 | + } | |
1176 | + } else if (a1&0x0000ffff) { | |
1177 | + check_obj_space(1); | |
1178 | + g_object[g_objpos++]=0x34050000|(a1&0xffff); // ori a1,zero,xxxx | |
1179 | + } else if (a0&0xff000000) { | |
1180 | + // # of variables is 4. Reset $a1 to let lib_var() know that there is no more variables to store. | |
1181 | + check_obj_space(1); | |
1182 | + g_object[g_objpos++]=0x34050000; // ori a1,zero,0 | |
1183 | + } | |
1184 | + return 0; | |
1185 | +} | |
1186 | + | |
1187 | +char* var_statement(){ | |
1188 | + char* err; | |
1189 | + int i,j,a0,a1; | |
1190 | + static int prevpos; | |
1191 | + short stack; | |
1192 | + do { | |
1193 | + // For stack, 4 bytes are used for return address, | |
1194 | + // 4 bytes are used in lib_var(), | |
1195 | + // and additinal bytes are used for storing variable values. | |
1196 | + stack=8; | |
1197 | + a0=a1=0; | |
1198 | + for (i=0;i<8;i++){ | |
1199 | + // Determine the variable number from source code | |
1200 | + j=get_var_number(); | |
1201 | + if (j<0) return ERR_SYNTAX; | |
1202 | + stack+=4; | |
1203 | + // Create parameters in $a0, or $a1 | |
1204 | + if (i<4) { | |
1205 | + a0=(a0<<8)|(j+1); | |
1206 | + } else { | |
1207 | + a1=(a1<<8)|(j+1); | |
1208 | + } | |
1209 | + // Check remaining variable(s) | |
1210 | + if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') g_srcpos++; | |
1211 | + next_position(); | |
1212 | + if (g_source[g_srcpos]!=',') break; | |
1213 | + g_srcpos++; | |
1214 | + } | |
1215 | + // Jump to push routine, first | |
1216 | + check_obj_space(2); | |
1217 | + prevpos=g_objpos; | |
1218 | + g_object[g_objpos++]=0x04130000; // bgezall zero,label1 | |
1219 | + g_object[g_objpos++]=0x27BD0000|((0-stack)&0xffff); // addiu sp,sp,-xx | |
1220 | + // Process will be here after RETURN statement | |
1221 | + // Pop routine | |
1222 | + err=var_statement_sub(a0,a1); // Prepare a0, and a1 | |
1223 | + if (err) return err; | |
1224 | + call_lib_code(LIB_VAR_POP); | |
1225 | + // Restore stack and return | |
1226 | + check_obj_space(3); | |
1227 | + g_object[g_objpos++]=0x8FA30000|stack; // lw v1,xx(sp) | |
1228 | + g_object[g_objpos++]=0x00600008; // jr v1 | |
1229 | + g_object[g_objpos++]=0x27BD0000|stack; // addiu sp,sp,xx | |
1230 | + // Push rotine | |
1231 | + g_object[prevpos]|=g_objpos-prevpos-1; // label1: | |
1232 | + check_obj_space(1); | |
1233 | + g_object[g_objpos++]=0xAFBF0004; // sw ra,4(sp) | |
1234 | + err=var_statement_sub(a0,a1); // Prepare a0, and a1 | |
1235 | + if (err) return err; | |
1236 | + call_lib_code(LIB_VAR_PUSH); | |
1237 | + | |
1238 | + } while (g_source[g_srcpos-1]==','); | |
1239 | + // Renew sp stored in s5 stack. | |
1240 | + check_obj_space(1); | |
1241 | + g_object[g_objpos++]=0xAEBD0000|ARGS_S5_SP; // sw sp,-12(s5) | |
1242 | + return 0; | |
1243 | +} | |
1244 | + | |
1245 | + | |
1246 | +char* graphic_statement(enum functions func){ | |
1247 | + /* | |
1248 | + PSET X1,Y1[,C] | |
1249 | + LINE X1,Y1,X2,Y2[,C] | |
1250 | + BOXFILL X1,Y1,X2,Y2[,C] | |
1251 | + CIRCLE X1,Y1,R[,C] | |
1252 | + CIRCLEFILL X1,Y1,R[,C] | |
1253 | + GPRINT X1,Y1,C,BC,S$ | |
1254 | + PUTBMP X1,Y1,M,N,BMP | |
1255 | + 4(sp): X1 | |
1256 | + 8(sp): Y1 | |
1257 | + 12(sp): X2/R/M | |
1258 | + 16(sp): Y2/N | |
1259 | + v0: C/S$/BMP | |
1260 | + */ | |
1261 | + char* err; | |
1262 | + int spos; | |
1263 | + int paramnum; | |
1264 | + switch(func){ | |
1265 | + case FUNC_PSET:// X1,Y1[,C] | |
1266 | + case FUNC_GCOLOR:// X1,Y1 | |
1267 | + case FUNC_POINT:// X1,Y1 | |
1268 | + paramnum=2; | |
1269 | + break; | |
1270 | + case FUNC_CIRCLE:// X1,Y1,R[,C] | |
1271 | + case FUNC_CIRCLEFILL:// X1,Y1,R[,C] | |
1272 | + paramnum=3; | |
1273 | + break; | |
1274 | + case FUNC_LINE:// X1,Y1,X2,Y2[,C] | |
1275 | + case FUNC_BOXFILL:// X1,Y1,X2,Y2[,C] | |
1276 | + paramnum=4; | |
1277 | + break; | |
1278 | + case FUNC_GPRINT:// X1,Y1,C,BC,S$ | |
1279 | + case FUNC_PUTBMP:// X1,Y1,M,N,BMP | |
1280 | + paramnum=5; | |
1281 | + break; | |
1282 | + default: | |
1283 | + return ERR_UNKNOWN; | |
1284 | + } | |
1285 | + | |
1286 | + next_position(); | |
1287 | + if (g_source[g_srcpos]==',') { | |
1288 | + // X1 and Y1 is omitted. Set 0x80000000 for both. | |
1289 | + check_obj_space(4); | |
1290 | + g_object[g_objpos++]=0x27BDFFF0; // addiu sp,sp,-16 | |
1291 | + g_object[g_objpos++]=0x3C028000; // lui v0,0x0080 | |
1292 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1293 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1294 | + } else { | |
1295 | + // X1 | |
1296 | + err=get_value(); | |
1297 | + if (err) return err; | |
1298 | + check_obj_space(2); | |
1299 | + g_object[g_objpos++]=0x27BDFFF0; // addiu sp,sp,-16 | |
1300 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1301 | + // Y1 | |
1302 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1303 | + g_srcpos++; | |
1304 | + err=get_value(); | |
1305 | + if (err) return err; | |
1306 | + check_obj_space(1); | |
1307 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1308 | + } | |
1309 | + if (2<paramnum) { | |
1310 | + // X2, R, or M | |
1311 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1312 | + g_srcpos++; | |
1313 | + err=get_value(); | |
1314 | + if (err) return err; | |
1315 | + check_obj_space(1); | |
1316 | + g_object[g_objpos++]=0xAFA2000C; // sw v0,12(sp) | |
1317 | + if (3<paramnum) { | |
1318 | + // Y2, BC, or N | |
1319 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1320 | + g_srcpos++; | |
1321 | + err=get_value(); | |
1322 | + if (err) return err; | |
1323 | + check_obj_space(1); | |
1324 | + g_object[g_objpos++]=0xAFA20010; // sw v0,16(sp) | |
1325 | + } | |
1326 | + } | |
1327 | + if (func==FUNC_GPRINT) { | |
1328 | + // S$ | |
1329 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1330 | + g_srcpos++; | |
1331 | + err=get_string(); | |
1332 | + if (err) return err; | |
1333 | + } else if (func==FUNC_PUTBMP) { | |
1334 | + // BMP | |
1335 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1336 | + g_srcpos++; | |
1337 | + spos=g_srcpos; | |
1338 | + err=get_label(); | |
1339 | + if (g_label && !err) { | |
1340 | + if (search_var_name(g_label)!=-1) { | |
1341 | + // This is a long var name. | |
1342 | + g_label=0; | |
1343 | + g_srcpos=spos; | |
1344 | + } | |
1345 | + } | |
1346 | + if (g_label && !err) { | |
1347 | + // Label/number is constant. | |
1348 | + // Linker will change following codes later. | |
1349 | + // Note that 0x0814xxxx and 0x0815xxxx are specific codes for these. | |
1350 | + check_obj_space(2); | |
1351 | + g_object[g_objpos++]=0x08140000|((g_label>>16)&0x0000FFFF); // lui v0,xxxx | |
1352 | + g_object[g_objpos++]=0x08150000|(g_label&0x0000FFFF); // ori v0,v0,xxxx | |
1353 | + // Change func to FUNC_PUTBMP2 (label mode). | |
1354 | + func=FUNC_PUTBMP2; | |
1355 | + } else { | |
1356 | + err=get_value(); | |
1357 | + if (err) return err; | |
1358 | + } | |
1359 | + } else { | |
1360 | + // [,C] | |
1361 | + if (g_source[g_srcpos]==',') { | |
1362 | + g_srcpos++; | |
1363 | + err=get_value(); | |
1364 | + if (err) return err; | |
1365 | + } else { | |
1366 | + // If C is omitted, use -1. | |
1367 | + check_obj_space(1); | |
1368 | + g_object[g_objpos++]=0x2402FFFF; // addiu v0,zero,-1 | |
1369 | + } | |
1370 | + } | |
1371 | + // Call library | |
1372 | + call_lib_code(LIB_GRAPHIC | func); | |
1373 | + // Restore stack pointer | |
1374 | + check_obj_space(1); | |
1375 | + g_object[g_objpos++]=0x27BD0010; // addiu sp,sp,16 | |
1376 | + return 0; | |
1377 | +} | |
1378 | + | |
1379 | +char* fopen_statement_main(enum functions func){ | |
1380 | + // func is either FUNC_FOPENST or FUNC_FOPEN | |
1381 | + char* err; | |
1382 | + // Get 1st | |
1383 | + err=get_string(); | |
1384 | + if (err) return err; | |
1385 | + if (g_source[g_srcpos]!=',') return ERR_SYNTAX; | |
1386 | + g_srcpos++; | |
1387 | + check_obj_space(2); | |
1388 | + g_object[g_objpos++]=0x27BDFFF8; // addiu sp,sp,-8 | |
1389 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1390 | + // Get 2nd | |
1391 | + err=get_string(); | |
1392 | + if (err) return err; | |
1393 | + check_obj_space(1); | |
1394 | + g_object[g_objpos++]=0xAFA20008; // sw v0,8(sp) | |
1395 | + // Get 3rd | |
1396 | + if (g_source[g_srcpos]==',') { | |
1397 | + g_srcpos++; | |
1398 | + err=get_value(); | |
1399 | + if (err) return err; | |
1400 | + } else { | |
1401 | + // If 3rd parameter is omitted, use 0. | |
1402 | + check_obj_space(1); | |
1403 | + g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
1404 | + } | |
1405 | + call_lib_code(LIB_FILE | func); | |
1406 | + check_obj_space(1); | |
1407 | + g_object[g_objpos++]=0x27BD0008; // addiu sp,sp,8 | |
1408 | + return 0; | |
1409 | +} | |
1410 | + | |
1411 | +char* file_statement(){ | |
1412 | + char* err; | |
1413 | + err=get_value(); | |
1414 | + if (err) return err; | |
1415 | + call_lib_code(LIB_FILE | FUNC_FILE); | |
1416 | + return 0; | |
1417 | +} | |
1418 | + | |
1419 | +char* fclose_statement(){ | |
1420 | + char* err; | |
1421 | + int orgpos=g_srcpos; | |
1422 | + if (endOfStatement()) { | |
1423 | + // If no argument, use 0 | |
1424 | + check_obj_space(1); | |
1425 | + g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
1426 | + } else { | |
1427 | + err=get_value(); | |
1428 | + if (err) return err; | |
1429 | + } | |
1430 | + call_lib_code(LIB_FILE | FUNC_FCLOSE); | |
1431 | + return 0; | |
1432 | +} | |
1433 | + | |
1434 | +char* fget_statement(){ | |
1435 | + return param2_statement(LIB_FILE | FUNC_FGET); | |
1436 | +} | |
1437 | + | |
1438 | +char* fput_statement(){ | |
1439 | + return param2_statement(LIB_FILE | FUNC_FPUT); | |
1440 | +} | |
1441 | + | |
1442 | +char* fseek_statement(){ | |
1443 | + char* err; | |
1444 | + err=get_value(); | |
1445 | + if (err) return err; | |
1446 | + call_lib_code(LIB_FILE | FUNC_FSEEK); | |
1447 | + return 0; | |
1448 | +} | |
1449 | + | |
1450 | +char* fputc_statement(){ | |
1451 | + char* err; | |
1452 | + err=get_value(); | |
1453 | + if (err) return err; | |
1454 | + call_lib_code(LIB_FILE | FUNC_FPUTC); | |
1455 | + return 0; | |
1456 | +} | |
1457 | + | |
1458 | +char* fremove_statement(){ | |
1459 | + char* err; | |
1460 | + err=get_string(); | |
1461 | + if (err) return err; | |
1462 | + call_lib_code(LIB_FILE | FUNC_FREMOVE); | |
1463 | + return 0; | |
1464 | +} | |
1465 | + | |
1466 | +char* usevar_statement(){ | |
1467 | + char* err; | |
1468 | + int i; | |
1469 | + do { | |
1470 | + next_position(); | |
1471 | + i=check_var_name(); | |
1472 | + if (i<65536) return ERR_SYNTAX; | |
1473 | + err=register_var_name(i); | |
1474 | + if (err) return err; | |
1475 | + if (g_source[g_srcpos]=='#' || g_source[g_srcpos]=='$') g_srcpos++; | |
1476 | + next_position(); | |
1477 | + if (g_source[g_srcpos]==',') { | |
1478 | + g_srcpos++; | |
1479 | + } else { | |
1480 | + break; | |
1481 | + } | |
1482 | + } while(1); | |
1483 | + return 0; | |
1484 | +} | |
1485 | + | |
1486 | +char* playwave_statement(){ | |
1487 | + char* err; | |
1488 | + err=get_string(); | |
1489 | + if (err) return err; | |
1490 | + check_obj_space(2); | |
1491 | + g_object[g_objpos++]=0x27BDFFFC; // addiu sp,sp,-4 | |
1492 | + g_object[g_objpos++]=0xAFA20004; // sw v0,4(sp) | |
1493 | + if (g_source[g_srcpos]==',') { | |
1494 | + g_srcpos++; | |
1495 | + // Get 2nd | |
1496 | + err=get_value(); | |
1497 | + if (err) return err; | |
1498 | + } else { | |
1499 | + // If 2rd parameter is omitted, use 0. | |
1500 | + check_obj_space(1); | |
1501 | + g_object[g_objpos++]=0x24020000; // addiu v0,zero,0 | |
1502 | + } | |
1503 | + call_lib_code(LIB_PLAYWAVE); | |
1504 | + check_obj_space(1); | |
1505 | + g_object[g_objpos++]=0x27BD0004; // addiu sp,sp,4 | |
1506 | + return 0; | |
1507 | +} | |
1508 | + | |
1509 | +char* useclass_statement(){ | |
1510 | + char* err; | |
1511 | + int i; | |
1512 | + int* cmpdata; | |
1513 | + do { | |
1514 | + next_position(); | |
1515 | + i=check_var_name(); | |
1516 | + if (i<65536) return ERR_SYNTAX; | |
1517 | + // Check if the class already exists | |
1518 | + cmpdata_reset(); | |
1519 | + while(cmpdata=cmpdata_find(CMPDATA_CLASS)){ | |
1520 | + if (cmpdata[1]==i) { | |
1521 | + // The class was already defined. | |
1522 | + i=0; | |
1523 | + break; | |
1524 | + } | |
1525 | + } | |
1526 | + if (i) { | |
1527 | + // Remove a objects before USECLASS statement | |
1528 | + g_objpos=0; | |
1529 | + // Insert a NOP assembly. This will be replaced by jump statement. | |
1530 | + check_obj_space(1); | |
1531 | + g_object[g_objpos++]=0x00000000; // nop | |
1532 | + // Load new file to define class statement. | |
1533 | + g_class=i; | |
1534 | + return ERR_COMPILE_CLASS; | |
1535 | + } | |
1536 | + if (g_source[g_srcpos]==',') { | |
1537 | + g_srcpos++; | |
1538 | + } else { | |
1539 | + break; | |
1540 | + } | |
1541 | + } while(1); | |
1542 | + return 0; | |
1543 | +} | |
1544 | + | |
1545 | +char* setdir_statement(){ | |
1546 | + char* err; | |
1547 | + err=get_string(); | |
1548 | + if (err) return err; | |
1549 | + call_lib_code(LIB_SETDIR); | |
1550 | + return 0; | |
1551 | +} | |
1552 | + | |
1553 | +#ifdef __DEBUG | |
1554 | + char* debug_statement(){ | |
1555 | + call_lib_code(LIB_DEBUG); | |
1556 | + return 0; | |
1557 | + } | |
1558 | +#endif | |
1559 | + | |
1560 | +// Aliases follow | |
1561 | + | |
1562 | +char* poke_statement(){ | |
1563 | + return poke_statement_sub(8); | |
1564 | +} | |
1565 | + | |
1566 | +char* poke16_statement(){ | |
1567 | + return poke_statement_sub(16); | |
1568 | +} | |
1569 | + | |
1570 | +char* poke32_statement(){ | |
1571 | + return poke_statement_sub(32); | |
1572 | +} | |
1573 | + | |
1574 | +char* palette_statement(){ | |
1575 | + return param4_statement(LIB_PALETTE); | |
1576 | +} | |
1577 | + | |
1578 | +char* gpalette_statement(){ | |
1579 | + return param4_statement(LIB_GPALETTE); | |
1580 | +} | |
1581 | + | |
1582 | +char* print_statement(){ | |
1583 | + return print_statement_main(LIB_PRINTSTR,LIB_STRING); | |
1584 | +} | |
1585 | + | |
1586 | +char* pset_statement(){ | |
1587 | + return graphic_statement(FUNC_PSET); | |
1588 | +} | |
1589 | + | |
1590 | +char* line_statement(){ | |
1591 | + return graphic_statement(FUNC_LINE); | |
1592 | +} | |
1593 | + | |
1594 | +char* boxfill_statement(){ | |
1595 | + return graphic_statement(FUNC_BOXFILL); | |
1596 | +} | |
1597 | + | |
1598 | +char* circle_statement(){ | |
1599 | + return graphic_statement(FUNC_CIRCLE); | |
1600 | +} | |
1601 | + | |
1602 | +char* circlefill_statement(){ | |
1603 | + return graphic_statement(FUNC_CIRCLEFILL); | |
1604 | +} | |
1605 | + | |
1606 | +char* gprint_statement(){ | |
1607 | + return graphic_statement(FUNC_GPRINT); | |
1608 | +} | |
1609 | + | |
1610 | +char* putbmp_statement(){ | |
1611 | + return graphic_statement(FUNC_PUTBMP); | |
1612 | +} | |
1613 | + | |
1614 | +char* point_statement(){ | |
1615 | + return graphic_statement(FUNC_POINT); | |
1616 | +} | |
1617 | + | |
1618 | +char* fopen_statement(){ | |
1619 | + return fopen_statement_main(FUNC_FOPENST); | |
1620 | +} | |
1621 | + | |
1622 | +char* fprint_statement(){ | |
1623 | + return print_statement_main(LIB_FILE | FUNC_FPRINTSTR,LIB_FILE | FUNC_FSTRING); | |
1624 | +} | |
1625 | + | |
1626 | +static const void* statement_list[]={ | |
1627 | + "REM",rem_statement, | |
1628 | + "SOUND ",sound_statement, | |
1629 | + "MUSIC ",music_statement, | |
1630 | + "DRAWCOUNT ",drawcount_statement, | |
1631 | + "CURSOR ",cursor_statement, | |
1632 | + "PALETTE ",palette_statement, | |
1633 | + "GPALETTE ",gpalette_statement, | |
1634 | + "BGCOLOR ",bgcolor_statement, | |
1635 | + "CLS",cls_statement, | |
1636 | + "GCLS",gcls_statement, | |
1637 | + "COLOR ",color_statement, | |
1638 | + "GCOLOR ",gcolor_statement, | |
1639 | + "RESTORE ",restore_statement, | |
1640 | + "DATA ",data_statement, | |
1641 | + "CDATA ",cdata_statement, | |
1642 | + "LABEL ",label_statement, | |
1643 | + "DIM ",dim_statement, | |
1644 | + "CLEAR",clear_statement, | |
1645 | + "PRINT",print_statement, | |
1646 | + "IF ",if_statement, | |
1647 | + "ELSEIF ",elseif_statement, | |
1648 | + "ELSE",else_statement, | |
1649 | + "ENDIF",endif_statement, | |
1650 | + "END",end_statement, | |
1651 | + "EXEC ",exec_statement, | |
1652 | + "GOTO ",goto_statement, | |
1653 | + "GOSUB ",gosub_statement, | |
1654 | + "RETURN",return_statement, | |
1655 | + "POKE ",poke_statement, | |
1656 | + "POKE16 ",poke16_statement, | |
1657 | + "POKE32 ",poke32_statement, | |
1658 | + "FOR ",for_statement, | |
1659 | + "NEXT",next_statement, | |
1660 | + "LET ",let_statement, | |
1661 | + "PCG ",pcg_statement, | |
1662 | + "USEPCG",usepcg_statement, | |
1663 | + "SCROLL ",scroll_statement, | |
1664 | + "WAIT ",wait_statement, | |
1665 | + "USEGRAPHIC",usegraphic_statement, | |
1666 | + "PSET ",pset_statement, | |
1667 | + "LINE ",line_statement, | |
1668 | + "BOXFILL ",boxfill_statement, | |
1669 | + "CIRCLE ",circle_statement, | |
1670 | + "CIRCLEFILL ",circlefill_statement, | |
1671 | + "GPRINT ",gprint_statement, | |
1672 | + "PUTBMP ",putbmp_statement, | |
1673 | + "POINT ",point_statement, | |
1674 | + "VAR ",var_statement, | |
1675 | + "DO",do_statement, | |
1676 | + "LOOP",loop_statement, | |
1677 | + "WHILE ",while_statement, | |
1678 | + "WEND",wend_statement, | |
1679 | + "BREAK",break_statement, | |
1680 | + "CONTINUE",continue_statement, | |
1681 | + "SYSTEM",system_statement, | |
1682 | + "WIDTH ",width_statement, | |
1683 | + "FOPEN ",fopen_statement, | |
1684 | + "FILE ",file_statement, | |
1685 | + "FCLOSE",fclose_statement, | |
1686 | + "FPRINT ",fprint_statement, | |
1687 | + "FGET ",fget_statement, | |
1688 | + "FPUT ",fput_statement, | |
1689 | + "FPUTC ",fputc_statement, | |
1690 | + "FSEEK ",fseek_statement, | |
1691 | + "FREMOVE ",fremove_statement, | |
1692 | + "USEVAR ",usevar_statement, | |
1693 | + "PLAYWAVE ",playwave_statement, | |
1694 | + "USECLASS ",useclass_statement, | |
1695 | + "FIELD ",field_statement, | |
1696 | + "METHOD ",method_statement, | |
1697 | + "DELETE ",delete_statement, | |
1698 | + "CALL ",call_statement, | |
1699 | + "STATIC ",static_statement, | |
1700 | + "SETDIR ",setdir_statement, | |
1701 | + // List of additional statements follows | |
1702 | + ADDITIONAL_STATEMENTS | |
1703 | +}; | |
1704 | + | |
1705 | +char* statement(void){ | |
1706 | + char* err; | |
1707 | + int prevpos; | |
1708 | + int i; | |
1709 | + char* (*f)(); | |
1710 | + // Clear flag for temp area usage. | |
1711 | + g_temp_area_used=0; | |
1712 | + // Initialize stack handler used for value | |
1713 | + g_sdepth=g_maxsdepth=0; | |
1714 | + // Allow shifting code object when stack is used. | |
1715 | + // This will be disalloed when CMPDATA_UNSOLVED etc is used. | |
1716 | + g_allow_shift_obj=1; | |
1717 | + // Seek the statement | |
1718 | + for (i=0;i<sizeof(statement_list)/sizeof(statement_list[0]);i+=2){ | |
1719 | + if (nextCodeIs((char*)statement_list[i])) break; | |
1720 | + } | |
1721 | + if (i<sizeof(statement_list)/sizeof(statement_list[0])) { | |
1722 | + // Statement found. Call it. | |
1723 | + f=statement_list[i+1]; | |
1724 | + err=f(); | |
1725 | +#ifdef __DEBUG | |
1726 | + } else if (nextCodeIs("DEBUG")) { | |
1727 | + err=debug_statement(); | |
1728 | +#endif | |
1729 | + } else { | |
1730 | + err=let_statement(); | |
1731 | + } | |
1732 | + if (err) return err; | |
1733 | + // Stack handler must be zero here. | |
1734 | + if (g_sdepth!=0) return ERR_UNKNOWN; | |
1735 | + // Check if temp area is used | |
1736 | + if (g_temp_area_used) { | |
1737 | + // Temp area is used. Insert a garbage collection flag setting routine. | |
1738 | + check_obj_space(1); | |
1739 | + g_object[g_objpos++]=0x7ED6F000;// ext s6,s6,0,31 | |
1740 | + } | |
1741 | + return 0; | |
1742 | +} |
@@ -6,6 +6,10 @@ | ||
6 | 6 | */ |
7 | 7 | |
8 | 8 | /* |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
12 | +/* | |
9 | 13 | Public functions: |
10 | 14 | char* get_string(void); |
11 | 15 | char* simple_string(void); |
@@ -88,6 +92,21 @@ | ||
88 | 92 | g_temp_area_used=1; |
89 | 93 | return 0; |
90 | 94 | } |
95 | + if (g_source[g_srcpos]=='.') { | |
96 | + // This is an object field or method to return string | |
97 | + check_obj_space(1); | |
98 | + g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
99 | + g_srcpos++; | |
100 | + return string_obj_field(); | |
101 | + } else if (g_source[g_srcpos]=='(') { | |
102 | + // An array element contains pointer to an object. | |
103 | + g_srcpos++; | |
104 | + err=get_dim_value(i); | |
105 | + if (err) return err; | |
106 | + if (g_source[g_srcpos]!='.') return ERR_SYNTAX; | |
107 | + g_srcpos++; | |
108 | + return string_obj_field(); | |
109 | + } | |
91 | 110 | if (g_source[g_srcpos]!='$') return ERR_SYNTAX; |
92 | 111 | g_srcpos++; |
93 | 112 | // String variable |
@@ -194,7 +213,7 @@ | ||
194 | 213 | prevpos=g_objpos; |
195 | 214 | // Stack decrement command will be filled later |
196 | 215 | check_obj_space(1); |
197 | - g_objpos++; | |
216 | + g_object[g_objpos++]=0x00000000; // nop (will be replaced by "addiu sp,sp,-xx") | |
198 | 217 | } |
199 | 218 | err=get_string_sub(); |
200 | 219 | if (err) return err; |
@@ -201,8 +220,10 @@ | ||
201 | 220 | if (g_sdepth==0) { |
202 | 221 | if (g_maxsdepth==0) { |
203 | 222 | // Stack was not used. |
204 | - shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
205 | - g_objpos--; | |
223 | + if (g_allow_shift_obj) { | |
224 | + shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
225 | + g_objpos--; | |
226 | + } | |
206 | 227 | } else { |
207 | 228 | // Stack was used. |
208 | 229 | check_obj_space(1); |
@@ -6,6 +6,10 @@ | ||
6 | 6 | */ |
7 | 7 | |
8 | 8 | /* |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
12 | +/* | |
9 | 13 | Public function is only get_value(). |
10 | 14 | */ |
11 | 15 |
@@ -73,6 +77,13 @@ | ||
73 | 77 | check_obj_space(1); |
74 | 78 | g_object[g_objpos++]=0x00021023; // subu v0,zero,v0 |
75 | 79 | g_intconst=-g_intconst; |
80 | + } else if (b1=='&') { | |
81 | + // '&' operator | |
82 | + g_srcpos++; | |
83 | + i=get_var_number(); | |
84 | + if (i<0) return ERR_SYNTAX; | |
85 | + check_obj_space(1); | |
86 | + g_object[g_objpos++]=0x27C20000|(i*4); // addiu v0,s8,xxxx | |
76 | 87 | } else { |
77 | 88 | // Main routine of getting value here |
78 | 89 | if (b1=='+') g_srcpos++; // Ignore unary '+' operator |
@@ -92,6 +103,9 @@ | ||
92 | 103 | } else if ('A'<=b1 && b1<='F') { |
93 | 104 | i*=16; |
94 | 105 | i+=b1-'A'+0x0A; |
106 | + } else if (b1==' ') { // Skip ' ' | |
107 | + // Avoid "ELSE" statement etc | |
108 | + if ('F'<g_source[g_srcpos+2]) break; | |
95 | 109 | } else { |
96 | 110 | break; |
97 | 111 | } |
@@ -116,7 +130,7 @@ | ||
116 | 130 | if ('0'<=b1 && b1<='9') { |
117 | 131 | i*=10; |
118 | 132 | i+=b1-'0'; |
119 | - } else { | |
133 | + } else if (b1!=' ') { // Skip ' ' | |
120 | 134 | break; |
121 | 135 | } |
122 | 136 | g_srcpos++; |
@@ -123,7 +137,11 @@ | ||
123 | 137 | } |
124 | 138 | // The next character should not be '.' or 'E'. |
125 | 139 | // Or, it must be recognized as a float value. |
126 | - if (b1=='.' || b1=='E') return ERR_SYNTAX; | |
140 | + if (b1=='.') return ERR_SYNTAX; | |
141 | + if (b1=='E') { | |
142 | + b2=g_source[g_srcpos+1]; | |
143 | + if (b2==' ' || '0'<=b2 && b2<='9') return ERR_SYNTAX; | |
144 | + } | |
127 | 145 | g_intconst=i; |
128 | 146 | if (i&0xFFFF0000) { |
129 | 147 | // 32 bit |
@@ -145,11 +163,19 @@ | ||
145 | 163 | if (g_source[g_srcpos]=='(') { |
146 | 164 | // Dimension |
147 | 165 | g_srcpos++; |
148 | - return get_dim_value(i); | |
166 | + err=get_dim_value(i); | |
167 | + if (err) return err; | |
168 | + } else { | |
169 | + // Simple value | |
170 | + check_obj_space(1); | |
171 | + g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
149 | 172 | } |
150 | - // Simple value | |
151 | - check_obj_space(1); | |
152 | - g_object[g_objpos++]=0x8FC20000|(i*4); // lw v0,xx(s8) | |
173 | + // Check if this is an object | |
174 | + if (g_source[g_srcpos]=='.') { | |
175 | + // This is an object. See the filed of it. | |
176 | + g_srcpos++; | |
177 | + return integer_obj_field(); | |
178 | + } | |
153 | 179 | } |
154 | 180 | } |
155 | 181 | // No error |
@@ -206,7 +232,7 @@ | ||
206 | 232 | prevpos=g_objpos; |
207 | 233 | // Stack decrement command will be filled later |
208 | 234 | check_obj_space(1); |
209 | - g_objpos++; | |
235 | + g_object[g_objpos++]=0x00000000; // nop (will be replaced by "addiu sp,sp,-xx") | |
210 | 236 | } |
211 | 237 | err=get_value_sub(priority(OP_VOID)); |
212 | 238 | if (err) return err; |
@@ -213,8 +239,10 @@ | ||
213 | 239 | if (g_sdepth==0) { |
214 | 240 | if (g_maxsdepth==0) { |
215 | 241 | // Stack was not used. |
216 | - shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
217 | - g_objpos--; | |
242 | + if (g_allow_shift_obj) { | |
243 | + shift_obj(&g_object[prevpos+1],&g_object[prevpos],g_objpos-prevpos-1); | |
244 | + g_objpos--; | |
245 | + } | |
218 | 246 | } else { |
219 | 247 | // Stack was used. |
220 | 248 | check_obj_space(1); |
@@ -5,6 +5,10 @@ | ||
5 | 5 | kmorimatsu@users.sourceforge.jp |
6 | 6 | */ |
7 | 7 | |
8 | +/* | |
9 | + This file is shared by Megalopa and Zoea | |
10 | +*/ | |
11 | + | |
8 | 12 | #include "compiler.h" |
9 | 13 | |
10 | 14 | /* |
@@ -14,106 +18,117 @@ | ||
14 | 18 | */ |
15 | 19 | |
16 | 20 | static const int reserved_var_names[]={ |
17 | - 0x000106b8, //ABS | |
18 | - 0x0001f67c, //ACOS | |
19 | - 0x0002414c, //ARGS | |
20 | - 0x0001090c, //ASC | |
21 | - 0x0002469f, //ASIN | |
22 | - 0x00024a8f, //ATAN | |
23 | - 0x002f7c1e, //ATAN2 | |
24 | - 0x0047c31c, //BREAK | |
25 | - 0x00575afe, //CDATA | |
26 | - 0x00036c3d, //CEIL | |
27 | - 0x000111af, //CHR | |
28 | - 0x0cb1b682, //CIRCLE | |
29 | - 0x005d1ea3, //CLEAR | |
30 | - 0x00011240, //CLS | |
31 | - 0x005f66cb, //COLOR | |
32 | - 0x000112ac, //COS | |
33 | - 0x0003a041, //COSH | |
34 | - 0x00616415, //CREAD | |
35 | - 0x0de593fb, //CURSOR | |
36 | - 0x00040fbe, //DATA | |
37 | - 0x00011644, //DEC | |
38 | - 0x000116de, //DIM | |
39 | - 0x000100a8, //DO | |
40 | - 0x0004fd8e, //ELSE | |
41 | - 0x1434a177, //ELSEIF | |
42 | - 0x00011c99, //END | |
43 | - 0x0091c927, //ENDIF | |
44 | - 0x00053854, //EXEC | |
45 | - 0x00011e0d, //EXP | |
46 | - 0x000579c8, //FABS | |
47 | - 0x16e3d4be, //FCLOSE | |
48 | - 0x00058fcf, //FEOF | |
49 | - 0x00059895, //FGET | |
50 | - 0x00a67500, //FGETC | |
51 | - 0x0005a3a2, //FILE | |
52 | - 0x177f0ca5, //FINPUT | |
53 | - 0x0005b1df, //FLEN | |
54 | - 0x00aa3445, //FLOAT | |
55 | - 0x00aa363b, //FLOOR | |
56 | - 0x0005b84d, //FMOD | |
57 | - 0x00ac5c9f, //FOPEN | |
58 | - 0x000121db, //FOR | |
59 | - 0x18352839, //FPRINT | |
60 | - 0x0005c865, //FPUT | |
61 | - 0x00ad2e40, //FPUTC | |
62 | - 0x00aefdec, //FSEEK | |
63 | - 0x00063b90, //GCLS | |
64 | - 0x1a808bcb, //GCOLOR | |
65 | - 0x00c60f03, //GOSUB | |
66 | - 0x0006796c, //GOTO | |
67 | - 0x1bcfcc39, //GPRINT | |
68 | - 0x00012a99, //HEX | |
69 | - 0x00010153, //IF | |
70 | - 0x00f8701a, //INKEY | |
71 | - 0x00f88ba5, //INPUT | |
72 | - 0x000130e9, //INT | |
73 | - 0x00092084, //KEYS | |
74 | - 0x013be43d, //LABEL | |
75 | - 0x00013ecf, //LEN | |
76 | - 0x00013ed5, //LET | |
77 | - 0x0009e96a, //LINE | |
78 | - 0x00014030, //LOG | |
79 | - 0x0145f324, //LOG10 | |
80 | - 0x000a07f9, //LOOP | |
81 | - 0x000abca3, //MODF | |
82 | - 0x016418d4, //MUSIC | |
83 | - 0x000b4321, //NEXT | |
84 | - 0x00014a5d, //NOT | |
85 | - 0x000152c0, //PCG | |
86 | - 0x000cacec, //PEEK | |
87 | - 0x00010252, //PI | |
88 | - 0x01ac8479, //POINT | |
89 | - 0x000ce05e, //POKE | |
90 | - 0x00015480, //POW | |
91 | - 0x01aea739, //PRINT | |
92 | - 0x000cf3d5, //PSET | |
93 | - 0x3cc0fe21, //PUTBMP | |
94 | - 0x000e18d5, //READ | |
95 | - 0x00015d2e, //REM | |
96 | - 0x425c9703, //RETURN | |
97 | - 0x00015e69, //RND | |
98 | - 0x45c26d49, //SCROLL | |
99 | - 0x00016287, //SGN | |
100 | - 0x000162cf, //SIN | |
101 | - 0x000ee52d, //SINH | |
102 | - 0x01f9a429, //SOUND | |
103 | - 0x000f0e49, //SQRT | |
104 | - 0x47f711de, //SYSTEM | |
105 | - 0x000166bf, //TAN | |
106 | - 0x000f72ed, //TANH | |
107 | - 0x02182fee, //TVRAM | |
108 | - 0x022c2a2d, //UNTIL | |
109 | - 0x4e8887d0, //USEPCG | |
110 | - 0x4e88a5f3, //USEVAR | |
111 | - 0x000170dd, //VAL | |
112 | - 0x000170e3, //VAR | |
113 | - 0x00119505, //WAIT | |
114 | - 0x0011a9e9, //WEND | |
115 | - 0x025aef62, //WHILE | |
116 | - 0x025b8d75, //WIDTH | |
21 | + 0x000106b8, /*ABS*/ | |
22 | + 0x0001f67c, /*ACOS*/ | |
23 | + 0x0002414c, /*ARGS*/ | |
24 | + 0x0001090c, /*ASC*/ | |
25 | + 0x0002469f, /*ASIN*/ | |
26 | + 0x00024a8f, /*ATAN*/ | |
27 | + 0x002f7c1e, /*ATAN2*/ | |
28 | + 0x0047c31c, /*BREAK*/ | |
29 | + 0x00035869, /*CALL*/ | |
30 | + 0x00575afe, /*CDATA*/ | |
31 | + 0x00036c3d, /*CEIL*/ | |
32 | + 0x000111af, /*CHR*/ | |
33 | + 0x0cb1b682, /*CIRCLE*/ | |
34 | + 0x005d1ea3, /*CLEAR*/ | |
35 | + 0x00011240, /*CLS*/ | |
36 | + 0x005f66cb, /*COLOR*/ | |
37 | + 0x000112ac, /*COS*/ | |
38 | + 0x0003a041, /*COSH*/ | |
39 | + 0x00616415, /*CREAD*/ | |
40 | + 0x0de593fb, /*CURSOR*/ | |
41 | + 0x00040fbe, /*DATA*/ | |
42 | + 0x00011644, /*DEC*/ | |
43 | + 0x0fe19c42, /*DELETE*/ | |
44 | + 0x000116de, /*DIM*/ | |
45 | + 0x000100a8, /*DO*/ | |
46 | + 0x0004fd8e, /*ELSE*/ | |
47 | + 0x1434a177, /*ELSEIF*/ | |
48 | + 0x00011c99, /*END*/ | |
49 | + 0x0091c927, /*ENDIF*/ | |
50 | + 0x00053854, /*EXEC*/ | |
51 | + 0x00011e0d, /*EXP*/ | |
52 | + 0x000579c8, /*FABS*/ | |
53 | + 0x16e3d4be, /*FCLOSE*/ | |
54 | + 0x00058fcf, /*FEOF*/ | |
55 | + 0x00059895, /*FGET*/ | |
56 | + 0x00a67500, /*FGETC*/ | |
57 | + 0x00a7e061, /*FIELD*/ | |
58 | + 0x0005a3a2, /*FILE*/ | |
59 | + 0x177f0ca5, /*FINPUT*/ | |
60 | + 0x0005b1df, /*FLEN*/ | |
61 | + 0x00aa3445, /*FLOAT*/ | |
62 | + 0x00aa363b, /*FLOOR*/ | |
63 | + 0x0005b84d, /*FMOD*/ | |
64 | + 0x00ac5c9f, /*FOPEN*/ | |
65 | + 0x000121db, /*FOR*/ | |
66 | + 0x18352839, /*FPRINT*/ | |
67 | + 0x0005c865, /*FPUT*/ | |
68 | + 0x00ad2e40, /*FPUTC*/ | |
69 | + 0x00aefdec, /*FSEEK*/ | |
70 | + 0x00063b90, /*GCLS*/ | |
71 | + 0x1a808bcb, /*GCOLOR*/ | |
72 | + 0x1ab733b3, /*GETDIR*/ | |
73 | + 0x00c60f03, /*GOSUB*/ | |
74 | + 0x0006796c, /*GOTO*/ | |
75 | + 0x1bcfcc39, /*GPRINT*/ | |
76 | + 0x00012a99, /*HEX*/ | |
77 | + 0x00010153, /*IF*/ | |
78 | + 0x00f8701a, /*INKEY*/ | |
79 | + 0x00f88ba5, /*INPUT*/ | |
80 | + 0x000130e9, /*INT*/ | |
81 | + 0x00092084, /*KEYS*/ | |
82 | + 0x013be43d, /*LABEL*/ | |
83 | + 0x00013ecf, /*LEN*/ | |
84 | + 0x00013ed5, /*LET*/ | |
85 | + 0x0009e96a, /*LINE*/ | |
86 | + 0x00014030, /*LOG*/ | |
87 | + 0x0145f324, /*LOG10*/ | |
88 | + 0x000a07f9, /*LOOP*/ | |
89 | + 0x000abca3, /*MODF*/ | |
90 | + 0x016418d4, /*MUSIC*/ | |
91 | + 0x000b4321, /*NEXT*/ | |
92 | + 0x000148f8, /*NEW*/ | |
93 | + 0x00014a5d, /*NOT*/ | |
94 | + 0x000152c0, /*PCG*/ | |
95 | + 0x000cacec, /*PEEK*/ | |
96 | + 0x3b1c6aea, /*PEEK16*/ | |
97 | + 0x3b1c6b2e, /*PEEK32*/ | |
98 | + 0x00010252, /*PI*/ | |
99 | + 0x01ac8479, /*POINT*/ | |
100 | + 0x000ce05e, /*POKE*/ | |
101 | + 0x3c20dc0a, /*POKE16*/ | |
102 | + 0x3c20dc4e, /*POKE32*/ | |
103 | + 0x00015480, /*POW*/ | |
104 | + 0x01aea739, /*PRINT*/ | |
105 | + 0x000cf3d5, /*PSET*/ | |
106 | + 0x3cb45fa4, /*PUBLIC*/ | |
107 | + 0x3cc0fe21, /*PUTBMP*/ | |
108 | + 0x000e18d5, /*READ*/ | |
109 | + 0x00015d2e, /*REM*/ | |
110 | + 0x425c9703, /*RETURN*/ | |
111 | + 0x00015e69, /*RND*/ | |
112 | + 0x45c26d49, /*SCROLL*/ | |
113 | + 0x45f6e3b3, /*SETDIR*/ | |
114 | + 0x00016287, /*SGN*/ | |
115 | + 0x000162cf, /*SIN*/ | |
116 | + 0x000ee52d, /*SINH*/ | |
117 | + 0x01f9a429, /*SOUND*/ | |
118 | + 0x000f0e49, /*SQRT*/ | |
119 | + 0x47f711de, /*SYSTEM*/ | |
120 | + 0x000166bf, /*TAN*/ | |
121 | + 0x000f72ed, /*TANH*/ | |
122 | + 0x02182fee, /*TVRAM*/ | |
123 | + 0x022c2a2d, /*UNTIL*/ | |
124 | + 0x4e8887d0, /*USEPCG*/ | |
125 | + 0x4e88a5f3, /*USEVAR*/ | |
126 | + 0x000170dd, /*VAL*/ | |
127 | + 0x000170e3, /*VAR*/ | |
128 | + 0x00119505, /*WAIT*/ | |
129 | + 0x0011a9e9, /*WEND*/ | |
130 | + 0x025aef62, /*WHILE*/ | |
131 | + 0x025b8d75, /*WIDTH*/ | |
117 | 132 | // Additional names follow |
118 | 133 | ADDITIONAL_RESERVED_VAR_NAMES |
119 | 134 | }; |
@@ -180,16 +195,41 @@ | ||
180 | 195 | */ |
181 | 196 | |
182 | 197 | int get_var_number(){ |
183 | - int i; | |
198 | + int i,j,spos; | |
199 | + int* record; | |
184 | 200 | // This must be a short or long var name. |
201 | + spos=g_srcpos; | |
185 | 202 | i=check_var_name(); |
186 | 203 | if (i<0) return -1; |
187 | 204 | // If it is a short name, immediately return. |
188 | 205 | if (i<26) return i; |
189 | - // Search long var names registered by USEVAR statement. | |
190 | - // If found, returns the value that can be used as the index of $s8 | |
191 | - i=search_var_name(i); | |
192 | - if (i<0) return -1; | |
206 | + // Check if CLASS::STATIC | |
207 | + if (g_source[g_srcpos]==':' && g_source[g_srcpos+1]==':') { | |
208 | + // This is CLASS::STATIC | |
209 | + g_srcpos++; | |
210 | + g_srcpos++; | |
211 | + j=check_var_name(); | |
212 | + if (j<26) return -1; | |
213 | + cmpdata_reset(); | |
214 | + while(record=cmpdata_find(CMPDATA_STATIC)){ | |
215 | + if (record[1]!=i) continue; | |
216 | + if (record[2]!=j) continue; | |
217 | + // Found CLASS::STATIC | |
218 | + i=record[0]&0x0000FFFF; | |
219 | + j=0; | |
220 | + break; | |
221 | + } | |
222 | + if (j) { | |
223 | + // Not found. Maybe a static method | |
224 | + g_srcpos=spos; | |
225 | + return -1; | |
226 | + } | |
227 | + } else { | |
228 | + // Search long var names registered by USEVAR statement. | |
229 | + // If found, returns the value that can be used as the index of $s8 | |
230 | + i=search_var_name(i); | |
231 | + if (i<0) return -1; | |
232 | + } | |
193 | 233 | // This var name is defined by USEVAR statement. |
194 | 234 | return i+ALLOC_LNV_BLOCK; |
195 | 235 |