Branch data Line data Source code
1 : : #include "addr2line.h"
2 : : #include "asar.h"
3 : : #include "libstr.h"
4 : : #include "libsmw.h"
5 : : #include "assocarr.h"
6 : : #include "autoarray.h"
7 : : #include "warnings.h"
8 : : #include "assembleblock.h"
9 : : #include "asar_math.h"
10 : : #include "macro.h"
11 : : #include "platform/file-helpers.h"
12 : : #include <cinttypes>
13 : :
14 : : #include "interface-shared.h"
15 : : #include "arch-shared.h"
16 : :
17 : : int arch=arch_65816;
18 : :
19 : : int snespos;
20 : : int realsnespos;
21 : : int startpos;
22 : : int realstartpos;
23 : :
24 : : bool emulatexkas;
25 : : bool mapper_set = false;
26 : : bool warn_endwhile = true;
27 : : static bool specifiedasarver = false;
28 : :
29 : : static int old_snespos;
30 : : static int old_startpos;
31 : : static int old_optimizeforbank;
32 : : static int struct_base;
33 : : static string struct_name;
34 : : static string struct_parent;
35 : : static bool in_struct = false;
36 : : static bool in_sub_struct = false;
37 : : static bool static_struct = false;
38 : : static bool in_spcblock = false;
39 : :
40 : : assocarr<snes_struct> structs;
41 : :
42 : : static bool movinglabelspossible = false;
43 : :
44 : : static bool disable_bank_cross_errors = false;
45 : : static bool check_half_banks_crossed = false;
46 : :
47 : : int bytes;
48 : :
49 : : static enum {
50 : : ratsmeta_ban,
51 : : ratsmeta_allow,
52 : : ratsmeta_used,
53 : : } ratsmetastate=ratsmeta_ban;
54 : :
55 : : enum spcblock_type{
56 : : spcblock_nspc,
57 : : spcblock_custom
58 : : };
59 : :
60 : : struct spcblock_data{
61 : : unsigned int destination;
62 : : spcblock_type type;
63 : : string macro_name;
64 : :
65 : : unsigned int execute_address;
66 : : unsigned int size_address;
67 : : mapper_t old_mapper;
68 : : }spcblock;
69 : :
70 : 21 : int snestopc_pick(int addr)
71 : : {
72 : 155 : return snestopc(addr);
73 : : }
74 : :
75 : 119045 : inline void verifysnespos()
76 : : {
77 [ + + - + ]: 119045 : if (snespos<0 || realsnespos<0)
78 : : {
79 : 12 : asar_throw_warning(0, warning_id_missing_org);
80 : 12 : snespos=0x008000;
81 : 12 : realsnespos=0x008000;
82 : 12 : startpos=0x008000;
83 : 12 : realstartpos=0x008000;
84 : : }
85 : 119045 : }
86 : :
87 : 480 : static int fixsnespos(int inaddr, int step)
88 : : {
89 : : // randomdude999: turns out it wasn't very reliable at all.
90 : : /* // RPG Hacker: No idea how reliable this is.
91 : : // Might not work with some of the more exotic mappers.
92 : : return pctosnes(snestopc(inaddr) + step); */
93 [ + + ]: 480 : if (mapper == lorom) {
94 [ + + ]: 186 : if ((inaddr&0xFFFF)+step > 0xFFFF) {
95 : : // bank crossed
96 : 12 : return inaddr+step+0x8000;
97 : : }
98 : 174 : return inaddr+step;
99 : : } else if (mapper == hirom) {
100 [ # # ]: 0 : if ((inaddr&0x400000) == 0) {
101 : : // system pages, need to account for low pages and stuff
102 [ # # ]: 0 : if ((inaddr&0xFFFF)+step > 0xFFFF) {
103 : 0 : return inaddr+step+0x8000;
104 : : }
105 : : }
106 : 0 : return inaddr+step;
107 : : } else if (mapper == exlorom) {
108 : : // exlorom has no mirroring so this should work fine
109 : 0 : return pctosnes(snestopc(inaddr)+step);
110 : : } else if (mapper == exhirom) {
111 : : // apparently exhirom is pretty similar to hirom after all
112 [ # # ]: 0 : if ((inaddr&0x400000) == 0) {
113 : : // system pages, need to account for low pages and stuff
114 [ # # ]: 0 : if ((inaddr&0xFFFF)+step > 0xFFFF) {
115 : 0 : return inaddr+step+0x8000;
116 : : }
117 : : }
118 : 0 : return inaddr+step;
119 : : } else if (mapper == sa1rom) {
120 [ # # ]: 0 : if((inaddr&0x400000) == 0) {
121 : : // lorom area
122 [ # # ]: 0 : if ((inaddr&0xFFFF)+step > 0xFFFF) {
123 : 0 : return inaddr+step+0x8000;
124 : : }
125 : 0 : return inaddr+step;
126 : : } else {
127 : : // hirom area
128 : 0 : return inaddr+step;
129 : : }
130 : : } else if (mapper == sfxrom) {
131 [ # # ]: 0 : if ((inaddr&0x400000) == 0) {
132 : : // lorom area
133 [ # # ]: 0 : if ((inaddr&0xFFFF)+step > 0xFFFF) {
134 : 0 : return inaddr+step+0x8000;
135 : : }
136 : : } else {
137 : : // hirom area
138 : 0 : return inaddr+step;
139 : : }
140 : : } else if (mapper == bigsa1rom) {
141 : : // no mirrors here, so this should work
142 : 0 : return pctosnes(snestopc(inaddr)+step);
143 : : } else if (mapper == norom) {
144 : 294 : return inaddr+step;
145 : : }
146 : : return -1;
147 : : }
148 : :
149 : 118721 : inline void step(int num)
150 : : {
151 [ + + ]: 118721 : if (disable_bank_cross_errors)
152 : : {
153 : 240 : snespos = fixsnespos(snespos, num);
154 : 240 : realsnespos = fixsnespos(realsnespos, num);
155 : :
156 : : // RPG Hacker: Not adjusting startpos here will eventually throw
157 : : // an error in checkbankcross() if we set warn bankcross on again.
158 : : // As far as I can tell, those are pretty much just used for
159 : : // checking bank crossing, anyways, so it's hopefully save to just
160 : : // adjust them here.
161 : 240 : startpos = snespos;
162 : 240 : realstartpos = realsnespos;
163 : : }
164 : : else
165 : : {
166 : 118481 : snespos += num;
167 : 118481 : realsnespos += num;
168 : : }
169 : 118721 : bytes+=num;
170 : 118721 : }
171 : :
172 : 118625 : inline void write1_65816(unsigned int num)
173 : : {
174 : 118625 : verifysnespos();
175 [ + + ]: 118625 : if (pass==2)
176 : : {
177 : 39536 : int pcpos=snestopc(realsnespos&0xFFFFFF);
178 [ - + ]: 39536 : if (pcpos<0)
179 : : {
180 : 0 : movinglabelspossible=true;
181 : 0 : asar_throw_error(2, error_type_block, error_id_snes_address_doesnt_map_to_rom, hex6((unsigned int)realsnespos).data());
182 : : }
183 : 39536 : writeromdata_byte(pcpos, (unsigned char)num);
184 [ + + ]: 39536 : if (pcpos>=romlen) romlen=pcpos+1;
185 : : }
186 : 118625 : step(1);
187 : 118625 : ratsmetastate=ratsmeta_ban;
188 : 118625 : }
189 : :
190 : : int recent_opcode_num = 0;
191 : :
192 : 7598 : void write1_pick(unsigned int num)
193 : : {
194 : 114693 : write1_65816(num);
195 : 107614 : }
196 : :
197 : 113788 : static bool asblock_pick(char** word, int numwords)
198 : : {
199 : 113788 : recent_opcode_num = 1;
200 : :
201 [ + + ]: 113788 : if (arch==arch_65816) return asblock_65816(word, numwords);
202 [ + + ]: 3012 : if (arch==arch_spc700) return asblock_spc700(word, numwords);
203 [ + + ]: 1833 : if (arch==arch_spc700_inline) return asblock_spc700(word, numwords);
204 [ + - ]: 1827 : if (arch==arch_superfx) return asblock_superfx(word, numwords);
205 : : return true;
206 : : }
207 : :
208 : : #define write1 write1_pick
209 : : #define snestopc snestopc_pick
210 : :
211 : 754 : const char * safedequote(char * str)
212 : : {
213 : 754 : const char * tmp=dequote(str);
214 [ - + ]: 754 : if (!tmp) asar_throw_error(0, error_type_block, error_id_garbage_near_quoted_string);
215 : 754 : return tmp;
216 : : }
217 : :
218 : : extern char romtitle[30];
219 : : extern bool stdlib;
220 : :
221 : 853 : void write2(unsigned int num)
222 : : {
223 : : write1(num);
224 : 853 : write1(num/256);
225 : 853 : }
226 : :
227 : 509 : void write3(unsigned int num)
228 : : {
229 : : write1(num);
230 : 509 : write1(num/256);
231 : 509 : write1(num/65536);
232 : 509 : }
233 : :
234 : 45 : void write4(unsigned int num)
235 : : {
236 : : write1(num);
237 : 45 : write1(num/256);
238 : 45 : write1(num/65536);
239 : 45 : write1(num/16777216);
240 : 45 : }
241 : :
242 : : //these are NOT used by the math parser - see math.cpp for that
243 : 0 : int read1(int insnespos)
244 : : {
245 : : int addr=snestopc(insnespos);
246 [ # # # # ]: 0 : if (addr<0 || addr+1>romlen_r) return -1;
247 : : return
248 : 0 : romdata_r[addr ] ;
249 : : }
250 : :
251 : 9 : int read2(int insnespos)
252 : : {
253 : : int addr=snestopc(insnespos);
254 [ + - + - ]: 9 : if (addr<0 || addr+2>romlen_r) return -1;
255 : : return
256 : 9 : romdata_r[addr ] |
257 : 9 : (romdata_r[addr+1]<< 8);
258 : : }
259 : :
260 : 27 : int read3(int insnespos)
261 : : {
262 : : int addr=snestopc(insnespos);
263 [ + - + - ]: 27 : if (addr<0 || addr+3>romlen_r) return -1;
264 : : return
265 : 27 : romdata_r[addr ] |
266 : 27 : (romdata_r[addr+1]<< 8)|
267 : 27 : (romdata_r[addr+2]<<16);
268 : : }
269 : :
270 : 708 : int getlenfromchar(char c)
271 : : {
272 : 708 : c=(char)to_lower(c);
273 [ + + ]: 708 : if (c=='b') return 1;
274 [ + + ]: 378 : if (c=='w') return 2;
275 [ - + ]: 48 : if (c=='l') return 3;
276 [ # # ]: 0 : if (c=='d')
277 : : {
278 : 0 : asar_throw_warning(1, warning_id_feature_deprecated, ".d opcode suffix", "this doesn't even make sense");
279 : 0 : return 4;
280 : : }
281 : 0 : asar_throw_error(0, error_type_block, error_id_invalid_opcode_length);
282 : 0 : return -1;
283 : : }
284 : :
285 : : assocarr<snes_label> labels;
286 : : static autoarray<int> poslabels;
287 : : static autoarray<int> neglabels;
288 : :
289 : : autoarray<int>* macroposlabels;
290 : : autoarray<int>* macroneglabels;
291 : :
292 : : autoarray<string> sublabels;
293 : : autoarray<string>* macrosublabels;
294 : :
295 : : // randomdude999: ns is still the string to prefix to all labels, it's calculated whenever namespace_list is changed
296 : : string ns;
297 : : string ns_backup;
298 : : autoarray<string> namespace_list;
299 : :
300 : : //bool fastrom=false;
301 : :
302 : : autoarray<string> includeonce;
303 : :
304 : 442 : bool confirmname(const char * name)
305 : : {
306 [ - + ]: 442 : if (!name[0]) return false;
307 [ + + ]: 442 : if (is_digit(name[0])) return false;
308 [ + + ]: 2950 : for (int i=0;name[i];i++)
309 : : {
310 [ + + + + ]: 2586 : if (!is_alnum(name[i]) && name[i]!='_') return false;
311 : : }
312 : : return true;
313 : : }
314 : :
315 : 1140857 : string posneglabelname(const char ** input, bool define)
316 : : {
317 : 1140857 : const char* label = *input;
318 : :
319 : 1140857 : string output;
320 : :
321 : : int depth = 0;
322 : : bool ismacro = false;
323 : :
324 [ + + ]: 1140857 : if (label[0] == '?')
325 : : {
326 : : ismacro = true;
327 : 25 : label++;
328 : : }
329 [ + + + + ]: 1140857 : if (label[0] == '-' || label[0] == '+')
330 : : {
331 : : char first = label[0];
332 [ + + + + ]: 298 : for (depth = 0; label[0] && label[0] == first; depth++) label++;
333 : :
334 [ + + ]: 149 : if (!ismacro)
335 : : {
336 [ + + ]: 139 : if (first == '+')
337 : : {
338 : 103 : *input = label;
339 : 206 : output = STR":pos_" + dec(depth) + "_" + dec(poslabels[depth]);
340 [ + + ]: 154 : if (define) poslabels[depth]++;
341 : : }
342 : : else
343 : : {
344 : 36 : *input = label;
345 [ + + ]: 39 : if (define) neglabels[depth]++;
346 : 72 : output = STR":neg_" + dec(depth) + "_" + dec(neglabels[depth]);
347 : : }
348 : : }
349 : : else
350 : : {
351 [ + - + - : 10 : if (macrorecursion == 0 || macroposlabels == nullptr || macroneglabels == nullptr)
- + ]
352 : : {
353 [ # # # # ]: 0 : if (!macrorecursion) asar_throw_error(0, error_type_block, error_id_macro_label_outside_of_macro);
354 : : }
355 : : else
356 : : {
357 [ + + ]: 10 : if (first == '+')
358 : : {
359 : 5 : *input = label;
360 : 10 : output = STR":macro_" + dec(calledmacros) + STR"_pos_" + dec(depth) + "_" + dec((*macroposlabels)[depth]);
361 [ + + ]: 5 : if (define) (*macroposlabels)[depth]++;
362 : : }
363 : : else
364 : : {
365 : 5 : *input = label;
366 [ + + ]: 8 : if (define) (*macroneglabels)[depth]++;
367 : 10 : output = STR":macro_" + dec(calledmacros) + STR"_neg_" + dec(depth) + "_" + dec((*macroneglabels)[depth]);
368 : : }
369 : : }
370 : : }
371 : : }
372 : :
373 : 1140857 : return output;
374 : 0 : }
375 : :
376 : 1164 : static string labelname(const char ** rawname, bool define=false)
377 : : {
378 : : #define deref_rawname (*rawname)
379 : 1164 : bool ismacro = (deref_rawname[0] == '?');
380 : :
381 [ + + ]: 1164 : if (ismacro)
382 : : {
383 : 12 : deref_rawname++;
384 : : }
385 : :
386 : : bool issublabel = false;
387 : :
388 : 1164 : string name;
389 : : int i=-1;
390 : :
391 : : autoarray<string>* sublabellist = &sublabels;
392 [ + + ]: 1164 : if (ismacro)
393 : : {
394 : 12 : sublabellist = macrosublabels;
395 : : }
396 : :
397 [ - + - - ]: 1164 : if (is_digit(*deref_rawname)) asar_throw_error(1, error_type_block, error_id_invalid_label_name);
398 [ + + ]: 1164 : if (*deref_rawname ==':')
399 : : {
400 : 48 : deref_rawname++;
401 : : name=":";
402 : : }
403 [ + + + + ]: 1116 : else if (!in_struct && !in_sub_struct)
404 : : {
405 [ + + ]: 1054 : for (i=0;(*deref_rawname =='.');i++) deref_rawname++;
406 [ - + - - ]: 1020 : if (!is_ualnum(*deref_rawname)) asar_throw_error(1, error_type_block, error_id_invalid_label_name);
407 [ + + - + : 1020 : if (emulatexkas && i>1) asar_throw_warning(1, warning_id_convert_to_asar);
- - ]
408 [ + + ]: 1020 : if (i)
409 : : {
410 [ + - - + : 31 : if (!sublabellist || !(*sublabellist)[i - 1]) asar_throw_error(1, error_type_block, error_id_label_missing_parent);
- - ]
411 : 62 : name+=STR(*sublabellist)[i-1]+"_";
412 : : issublabel = true;
413 : : }
414 : : }
415 : :
416 [ + + ]: 1164 : if (ismacro && !issublabel)
417 : : {
418 : : // RPG Hacker: Don't add the prefix for sublabels, because they already inherit it from
419 : : // their parents' names.
420 [ + - - + : 7 : if (!macrorecursion || macrosublabels == nullptr) asar_throw_error(1, error_type_block, error_id_macro_label_outside_of_macro);
- - ]
421 : 14 : name = STR":macro_" + dec(calledmacros) + "_" + name;
422 : : }
423 : :
424 [ + + ]: 1164 : if(in_sub_struct)
425 : : {
426 : 12 : name += struct_parent + ".";
427 : : }
428 : :
429 [ + + + + ]: 1164 : if (in_struct || in_sub_struct)
430 : : {
431 : 96 : name += struct_name;
432 : 96 : name += '.';
433 [ - + - - ]: 96 : if(*deref_rawname != '.') asar_throw_error(1, error_type_block, error_id_invalid_label_name); //probably should be a better error. TODO!!!
434 : 96 : deref_rawname++;
435 : : }
436 : :
437 [ - + - - ]: 1164 : if (!is_ualnum(*deref_rawname)) asar_throw_error(1, error_type_block, error_id_invalid_label_name);
438 : :
439 [ + + + + : 10454 : while (is_ualnum(*deref_rawname) || *deref_rawname == '.' || *deref_rawname == '[')
+ + ]
440 : : {
441 [ + + + + : 9290 : if(!in_struct && !in_sub_struct && *deref_rawname == '[')
+ + ]
442 : : {
443 : : bool invalid = true;
444 [ + - ]: 117 : while (isprint(*deref_rawname))
445 : : {
446 [ + + ]: 117 : if (*(deref_rawname++) == ']')
447 : : {
448 : : invalid = false;
449 : : break;
450 : : }
451 : : }
452 [ - + ]: 39 : if (invalid)
453 : : {
454 : 0 : asar_throw_error(1, error_type_block, error_id_invalid_label_missing_closer);
455 : : }
456 : : }
457 [ - + ]: 9251 : else if (*deref_rawname == '{')
458 : : {
459 : 0 : asar_throw_error(1, error_type_block, error_id_array_invalid_inside_structs);
460 : : }
461 : :
462 : 9290 : name+=*(deref_rawname++);
463 : : }
464 [ + + ]: 1164 : if (define && i>=0)
465 : : {
466 : 255 : (*sublabellist).reset(i);
467 : : (*sublabellist)[i]=name;
468 : : }
469 : 1164 : return name;
470 : : #undef deref_rawname
471 : 0 : }
472 : :
473 : 801 : inline bool labelvalcore(const char ** rawname, snes_label * rval, bool define, bool shouldthrow)
474 : : {
475 : 801 : string name=labelname(rawname, define);
476 : : snes_label rval_;
477 [ + + + + : 873 : if (ns && labels.exists(STR ns+name)) {rval_ = labels.find(STR ns+name);}
+ + + + ]
478 [ + + ]: 774 : else if (labels.exists(name)) {rval_ = labels.find(name);}
479 : : else
480 : : {
481 [ + + - + ]: 63 : if (shouldthrow && pass)
482 : : {
483 : 0 : asar_throw_error(2, error_type_block, error_id_label_not_found, name.data());
484 : : }
485 [ + - ]: 63 : if (rval) { rval->pos = (unsigned int)-1; rval->is_static = false; }
486 : 63 : return false;
487 : : }
488 [ + - ]: 738 : if (rval)
489 : : {
490 : 738 : *rval=rval_;
491 : : //if (fastrom && (rval_&0x700000)!=0x700000) *rval|=0x800000;
492 : : }
493 : : return true;
494 : 801 : }
495 : :
496 : 506 : snes_label labelval(const char ** rawname, bool define)
497 : : {
498 : : snes_label rval;
499 : 506 : labelvalcore(rawname, &rval, define, true);
500 : 506 : return rval;
501 : : }
502 : :
503 : 0 : snes_label labelval(char ** rawname, bool define)
504 : : {
505 : : snes_label rval;
506 : 0 : labelvalcore(const_cast<const char**>(rawname), &rval, define, true);
507 : 0 : return rval;
508 : : }
509 : :
510 : 28 : snes_label labelval(string name, bool define)
511 : : {
512 : 28 : const char * rawname=name;
513 : : snes_label rval;
514 : 28 : labelvalcore(&rawname, &rval, define, true);
515 : 28 : return rval;
516 : : }
517 : :
518 : 239 : bool labelval(const char ** rawname, snes_label * rval, bool define)
519 : : {
520 : 239 : return labelvalcore(rawname, rval, define, false);
521 : : }
522 : :
523 : 0 : bool labelval(char ** rawname, snes_label * rval, bool define)
524 : : {
525 : 0 : return labelvalcore(const_cast<const char**>(rawname), rval, define, false);
526 : : }
527 : :
528 : 28 : bool labelval(string name, snes_label * rval, bool define)
529 : : {
530 : 28 : const char * str=name;
531 : 28 : return labelvalcore(&str, rval, define, false);
532 : : }
533 : :
534 : 454 : static void setlabel(string name, int loc=-1, bool is_static=false)
535 : : {
536 [ + + ]: 454 : if (loc==-1)
537 : : {
538 : 420 : verifysnespos();
539 : 420 : loc=snespos;
540 : : }
541 : :
542 : : snes_label label_data;
543 : 454 : label_data.pos = (unsigned int)loc;
544 : 454 : label_data.is_static = is_static;
545 : :
546 : : unsigned int labelpos;
547 [ + + ]: 454 : if (pass==0)
548 : : {
549 [ + + ]: 152 : if (labels.exists(name))
550 : : {
551 : 1 : movinglabelspossible=true;
552 : 1 : asar_throw_error(0, error_type_block, error_id_label_redefined, name.data());
553 : : }
554 : 151 : labels.create(name) = label_data;
555 : : }
556 [ + + ]: 302 : else if (pass==1)
557 : : {
558 : 151 : labels.create(name) = label_data;
559 : : }
560 [ + - ]: 151 : else if (pass==2)
561 : : {
562 : : //all label locations are known at this point, add a sanity check
563 [ - + ]: 151 : if (!labels.exists(name)) asar_throw_error(2, error_type_block, error_id_label_on_third_pass);
564 : 151 : labelpos = labels.find(name).pos;
565 [ - + - - ]: 151 : if ((int)labelpos != loc && !movinglabelspossible)
566 : : {
567 [ # # # # ]: 0 : if((unsigned int)loc < labelpos && (unsigned int)loc>>16 != labelpos>>16) asar_throw_error(2, error_type_block, error_id_label_ambiguous, name.raw());
568 [ # # # # ]: 0 : else if((unsigned int)loc < labelpos && labelpos == (dp_base + 0xFFu)) asar_throw_error(2, error_type_block, error_id_label_ambiguous, name.raw());
569 [ # # ]: 0 : else if(errored) return;
570 : 0 : else asar_throw_error(2, error_type_block, error_id_label_moving);
571 : : }
572 : : }
573 : : }
574 : :
575 : :
576 : : chartabledata table;
577 : : static autoarray<chartabledata> tablestack;
578 : :
579 : : static int freespacepos[256];
580 : : static int freespacelen[256];
581 : : static int freespaceidnext;
582 : : static int freespaceid;
583 : : static int freespacestart;
584 : : int freespaceextra;
585 : :
586 : : static bool freespaceleak[256];
587 : : static string freespacefile[256];
588 : :
589 : : static int freespaceorgpos[256];
590 : : static int freespaceorglen[256];
591 : : static bool freespacestatic[256];
592 : : static unsigned char freespacebyte[256];
593 : :
594 : 281 : static void cleartable()
595 : : {
596 [ + + ]: 72217 : for (unsigned int i=0;i<256;i++) table.table[i]=i;
597 : 281 : }
598 : :
599 : : struct pushable {
600 : : int arch;
601 : : int snespos;
602 : : int snesstart;
603 : : int snesposreal;
604 : : int snesstartreal;
605 : : int freeid;
606 : : int freeex;
607 : : int freest;
608 : : int arch1;
609 : : int arch2;
610 : : int arch3;
611 : : int arch4;
612 : : };
613 : : static autoarray<pushable> pushpc;
614 : : static int pushpcnum;
615 : :
616 : : static autoarray<int> basestack;
617 : : static int basestacknum;
618 : :
619 : : struct ns_pushable {
620 : : string ns;
621 : : autoarray<string> namespace_list;
622 : : bool nested_namespaces;
623 : : };
624 : :
625 : : static autoarray<ns_pushable> pushns;
626 : : static int pushnsnum;
627 : :
628 : :
629 : : static unsigned char fillbyte[12];
630 : : static unsigned char padbyte[12];
631 : :
632 : : static bool nested_namespaces = false;
633 : :
634 : 441 : static int getfreespaceid()
635 : : {
636 : : static const int max_num_freespaces = 125;
637 [ - + ]: 441 : if (freespaceidnext > max_num_freespaces) asar_throw_error(pass, error_type_fatal, error_id_freespace_limit_reached, max_num_freespaces);
638 : 441 : return freespaceidnext++;
639 : : }
640 : :
641 : 436663 : void checkbankcross()
642 : : {
643 [ + + + - : 436663 : if (snespos<0 && realsnespos<0 && startpos<0 && realstartpos<0) return;
+ - - + ]
644 [ + + ]: 433342 : if (disable_bank_cross_errors) return;
645 [ + + ]: 433009 : unsigned int mask = 0x7FFF0000 | (check_half_banks_crossed ? 0x8000 : 0);
646 [ + + + + ]: 433009 : if (((snespos^ startpos) & mask) && (((snespos - 1) ^ startpos) & mask))
647 : : {
648 : 1 : asar_throw_error(pass, error_type_fatal, error_id_bank_border_crossed, snespos);
649 : : }
650 [ + + - + ]: 433008 : else if (((realsnespos^realstartpos) & mask) && (((realsnespos - 1) ^ realstartpos) & mask))
651 : : {
652 : 0 : asar_throw_error(pass, error_type_fatal, error_id_bank_border_crossed, realsnespos);
653 : : }
654 : : }
655 : :
656 : 1066 : static void freespaceend()
657 : : {
658 [ + + + + ]: 1066 : if ((snespos&0x7F000000) && ((unsigned int)snespos&0x80000000)==0)
659 : : {
660 : 438 : freespacelen[freespaceid]=snespos-freespacestart+freespaceextra;
661 : 438 : snespos=(int)0xFFFFFFFF;
662 : : }
663 : 1066 : freespaceextra=0;
664 : 1066 : }
665 : :
666 : : int numopcodes;
667 : :
668 : : bool warnxkas;
669 : :
670 : 2810 : static void adddefine(const string & key, string & value)
671 : : {
672 [ + - ]: 2810 : if (!defines.exists(key)) defines.create(key) = value;
673 : 2810 : }
674 : :
675 : 281 : void initstuff()
676 : : {
677 [ + + ]: 281 : if (pass==0)
678 : : {
679 [ + + ]: 24415 : for (int i=0;i<256;i++)
680 : : {
681 : 24320 : freespaceleak[i]=true;
682 : 24320 : freespaceorgpos[i]=-2;
683 : 24320 : freespaceorglen[i]=-1;
684 : 24320 : freespacebyte[i] = 0x00;
685 : : }
686 : : }
687 : 281 : arch=arch_65816;
688 : 281 : mapper=lorom;
689 : 281 : mapper_set = false;
690 : 281 : reallycalledmacros=0;
691 : 281 : calledmacros=0;
692 : 281 : macrorecursion=0;
693 : 281 : repeatnext=1;
694 : 281 : defines.reset();
695 : 281 : builtindefines.each(adddefine);
696 : 281 : clidefines.each(adddefine);
697 : : ns="";
698 : 281 : namespace_list.reset();
699 : 281 : sublabels.reset();
700 : 281 : poslabels.reset();
701 : 281 : neglabels.reset();
702 : 281 : macroposlabels = nullptr;
703 : 281 : macroneglabels = nullptr;
704 : 281 : macrosublabels = nullptr;
705 : 281 : cleartable();
706 : 281 : pushpc.reset();
707 : 281 : pushpcnum=0;
708 : 281 : pushns.reset();
709 : 281 : pushnsnum = 0;
710 : 281 : bytes=0;
711 : 281 : memset(fillbyte, 0, sizeof(fillbyte));
712 : 281 : memset(padbyte, 0, sizeof(padbyte));
713 : 281 : snespos=(int)0xFFFFFFFF;
714 : 281 : realsnespos= (int)0xFFFFFFFF;
715 : 281 : startpos= (int)0xFFFFFFFF;
716 : 281 : realstartpos= (int)0xFFFFFFFF;
717 : : //fastrom=false;
718 : 281 : freespaceidnext=1;
719 : 281 : freespaceid=1;
720 : 281 : freespaceextra=0;
721 : 281 : numopcodes=0;
722 : 281 : specifiedasarver = false;
723 : 281 : incsrcdepth = 0;
724 : :
725 : 281 : optimizeforbank = -1;
726 : 281 : optimize_dp = optimize_dp_flag::NONE;
727 : 281 : dp_base = 0;
728 : 281 : optimize_address = optimize_address_flag::DEFAULT;
729 : :
730 : 281 : in_struct = false;
731 : 281 : in_sub_struct = false;
732 : 281 : in_spcblock = false;
733 : :
734 : 281 : math_pri=false;
735 : 281 : math_round=true;
736 : :
737 [ + - ]: 281 : if (arch==arch_65816) asinit_65816();
738 [ - + ]: 281 : if (arch==arch_spc700) asinit_spc700();
739 [ - + ]: 281 : if (arch==arch_spc700_inline) asinit_spc700();
740 [ - + ]: 281 : if (arch==arch_superfx) asinit_superfx();
741 : :
742 : 281 : warnxkas=false;
743 : 281 : emulatexkas=false;
744 : 281 : disable_bank_cross_errors = false;
745 : 281 : check_half_banks_crossed = false;
746 : 281 : nested_namespaces = false;
747 : :
748 : : thisfilename = "";
749 : :
750 : 281 : includeonce.reset();
751 : :
752 : : extern AddressToLineMapping addressToLineMapping;
753 : 281 : addressToLineMapping.reset();
754 : :
755 : 281 : push_warnings(false);
756 : :
757 : 281 : initmathcore();
758 : 281 : }
759 : :
760 : :
761 : : //void nerf(const string& left, string& right){puts(S left+" = "+right);}
762 : :
763 : 279 : void finishpass()
764 : : {
765 : 279 : verify_warnings();
766 : 279 : pull_warnings(false);
767 : :
768 : : //defines.traverse(nerf);
769 [ - + ]: 279 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_missing_endspcblock);
770 [ + - - + ]: 279 : if (in_struct || in_sub_struct) asar_throw_error(pass, error_type_null, error_id_struct_without_endstruct);
771 [ - + - - ]: 279 : else if (pushpcnum && pass == 0) asar_throw_error(pass, error_type_null, error_id_pushpc_without_pullpc);
772 [ - + - - ]: 279 : else if (pushnsnum && pass == 0) asar_throw_error(pass, error_type_null, error_id_pushns_without_pullns);
773 : 279 : freespaceend();
774 [ + + ]: 279 : if (arch==arch_65816) asend_65816();
775 [ + + ]: 279 : if (arch==arch_spc700) asend_spc700();
776 [ + + ]: 279 : if (arch==arch_spc700_inline) asend_spc700();
777 [ + + ]: 279 : if (arch==arch_superfx) asend_superfx();
778 : :
779 : 279 : deinitmathcore();
780 : 279 : }
781 : :
782 : 436203 : static bool addlabel(const char * label, int pos=-1, bool global_label = false)
783 : : {
784 [ + + + - ]: 436203 : if (!label[0] || label[0]==':') return false;//colons are reserved for special labels
785 : :
786 : 325720 : const char* posneglabel = label;
787 : 325720 : string posnegname = posneglabelname(&posneglabel, true);
788 : :
789 [ + + ]: 325720 : if (posnegname.length() > 0)
790 : : {
791 [ + - ]: 60 : if (global_label) return false;
792 [ + + - + : 60 : if (*posneglabel != '\0' && *posneglabel != ':') asar_throw_error(0, error_type_block, error_id_broken_label_definition);
- - ]
793 : 60 : setlabel(posnegname, pos);
794 : 60 : return true;
795 : : }
796 [ + + + + : 325660 : if (label[strlen(label)-1]==':' || label[0]=='.' || label[0]=='?' || label[0] == '#')
+ + - + ]
797 : : {
798 [ + + ]: 372 : if (!label[1]) return false;
799 [ + + + - : 366 : if(global_label && (in_struct || in_sub_struct || label[0]=='?')) return false;
+ - + + ]
800 : :
801 : : bool define = true;
802 : :
803 [ + + ]: 363 : if (label[0] == '#')
804 : : {
805 : : define = false;
806 : 12 : label++;
807 : : }
808 : :
809 : : // RPG Hacker: Also checking label[1] now, since it might be a macro sublabel.
810 : : // Also, apparently this here doesn't account for main labels. I guess because
811 : : // we don't even get here in the first place if they don't include a colon?
812 [ + + + + : 363 : bool requirecolon = (label[0] != '.' && label[1] != '.') && (in_struct || in_sub_struct);
+ - ]
813 : 363 : string name=labelname(&label, define);
814 [ + + ]: 363 : if (label[0]==':') label++;
815 [ - + - - ]: 21 : else if (requirecolon) asar_throw_error(0, error_type_block, error_id_broken_label_definition);
816 [ + + ]: 21 : else if (global_label) return false;
817 [ - + - - ]: 360 : if (label[0]) asar_throw_error(0, error_type_block, error_id_broken_label_definition);
818 [ + + + + ]: 408 : if (ns && !global_label) name=STR ns+name;
819 [ + + + + : 360 : setlabel(name, pos, ((in_struct || in_sub_struct) && static_struct));
+ + ]
820 : 359 : return true;
821 : 363 : }
822 : : return false;
823 : 325720 : }
824 : :
825 : 111916 : static void add_addr_to_line(int pos)
826 : : {
827 [ + + ]: 111916 : if (pass == 2)
828 : 37405 : addressToLineMapping.includeMapping(thisfilename.data(), thisline + 1, pos);
829 : 111916 : }
830 : :
831 : : static autoarray<bool> elsestatus;
832 : : int numtrue=0;//if 1 -> increase both
833 : : int numif = 0; //if 0 or inside if 0 -> increase only numif
834 : :
835 : : autoarray<whiletracker> whilestatus;
836 : : int single_line_for_tracker;
837 : :
838 : : static int freespaceuse=0;
839 : :
840 : :
841 : 36 : static void push_pc()
842 : : {
843 : 36 : pushpc[pushpcnum].arch=arch;
844 : 36 : pushpc[pushpcnum].snespos=snespos;
845 : 36 : pushpc[pushpcnum].snesstart=startpos;
846 : 36 : pushpc[pushpcnum].snesposreal=realsnespos;
847 : 36 : pushpc[pushpcnum].snesstartreal=realstartpos;
848 : 36 : pushpc[pushpcnum].freeid=freespaceid;
849 : 36 : pushpc[pushpcnum].freeex=freespaceextra;
850 : 36 : pushpc[pushpcnum].freest=freespacestart;
851 : 36 : pushpcnum++;
852 : 36 : }
853 : :
854 : 36 : static void pop_pc()
855 : : {
856 : 36 : pushpcnum--;
857 : 36 : snespos=pushpc[pushpcnum].snespos;
858 : 36 : startpos=pushpc[pushpcnum].snesstart;
859 : 36 : realsnespos=pushpc[pushpcnum].snesposreal;
860 : 36 : realstartpos=pushpc[pushpcnum].snesstartreal;
861 : 36 : freespaceid=pushpc[pushpcnum].freeid;
862 : 36 : freespaceextra=pushpc[pushpcnum].freeex;
863 : 36 : freespacestart=pushpc[pushpcnum].freest;
864 : 36 : }
865 : :
866 : :
867 : 66 : string handle_print(char* input)
868 : : {
869 [ - + ]: 66 : if (!confirmqpar(input)) asar_throw_error(0, error_type_block, error_id_mismatched_parentheses);
870 : 66 : string out;
871 [ + - ]: 66 : autoptr<char**> pars = qpsplit(input, ",");
872 [ + + ]: 228 : for (int i = 0; pars[i]; i++)
873 : : {
874 : : if (0);
875 [ + + + - ]: 162 : else if (pars[i][0] == '"') out += safedequote(pars[i]);
876 [ - + ]: 57 : else if (!stricmp(pars[i], "bytes")) out += dec(bytes);
877 [ - + ]: 57 : else if (!stricmp(pars[i], "freespaceuse")) out += dec(freespaceuse);
878 [ - + ]: 57 : else if (!stricmp(pars[i], "pc")) out += hex6((unsigned int)(snespos & 0xFFFFFF));
879 : 102 : else if (!strncasecmp(pars[i], "bin(", strlen("bin(")) ||
880 [ + + ]: 45 : !strncasecmp(pars[i], "dec(", strlen("dec(")) ||
881 [ + + + + ]: 90 : !strncasecmp(pars[i], "hex(", strlen("hex(")) ||
882 [ + - ]: 21 : !strncasecmp(pars[i], "double(", strlen("double(")))
883 : : {
884 : 57 : char * arg1pos = strchr(pars[i], '(') + 1;
885 : : char * endpos = strchr(arg1pos, '\0');
886 [ - + + + ]: 114 : while (*endpos == ' ' || *endpos == '\0') endpos--;
887 [ - + - - ]: 57 : if (*endpos != ')') asar_throw_error(0, error_type_block, error_id_invalid_print_function_syntax);
888 : 57 : string paramstr = string(arg1pos, (int)(endpos - arg1pos));
889 : :
890 : : int numargs;
891 [ + - ]: 57 : autoptr<char**> params = qpsplit(paramstr.temp_raw(), ",", &numargs);
892 [ - + - - ]: 57 : if (numargs > 2) asar_throw_error(0, error_type_block, error_id_wrong_num_parameters);
893 : : int precision = 0;
894 : 57 : bool hasprec = numargs == 2;
895 [ + + ]: 57 : if (hasprec)
896 : : {
897 : 39 : precision = getnum64(params[1]);
898 [ - + ]: 39 : if (precision < 0) precision = 0;
899 : 39 : if (precision > 64) precision = 64;
900 : : }
901 : 57 : *(arg1pos - 1) = '\0'; // allows more convenient comparsion functions
902 [ + + ]: 57 : if (!stricmp(pars[i], "bin"))
903 : : {
904 : : // sadly printf doesn't have binary, so let's roll our own
905 : 12 : int64_t value = getnum64(params[0]);
906 : : char buffer[65];
907 [ - + ]: 12 : if (value < 0) {
908 : 0 : out += '-';
909 : 0 : value = -value;
910 : : // decrement precision because we've output one char already
911 : 0 : precision -= 1;
912 [ # # ]: 0 : if (precision<0) precision = 0;
913 : : }
914 [ + + ]: 780 : for (int j = 0; j < 64; j++) {
915 : 768 : buffer[63 - j] = '0' + ((value & (1ull << j)) >> j);
916 : : }
917 : 12 : buffer[64] = 0;
918 : : int startidx = 0;
919 [ + + + - ]: 684 : while (startidx < 64 - precision && buffer[startidx] == '0') startidx++;
920 [ - + ]: 12 : if (startidx == 64) startidx--; // always want to print at least one digit
921 : 12 : out += buffer + startidx;
922 : : }
923 [ + + ]: 45 : else if (!stricmp(pars[i], "dec"))
924 : : {
925 : 12 : int64_t value = getnum64(params[0]);
926 : : char buffer[65];
927 : 12 : snprintf(buffer, 65, "%0*" PRId64, precision, value);
928 : 12 : out += buffer;
929 : : }
930 [ + + ]: 33 : else if (!stricmp(pars[i], "hex"))
931 : : {
932 : 12 : int64_t value = getnum64(params[0]);
933 : : char buffer[65];
934 : 12 : snprintf(buffer, 65, "%0*" PRIX64, precision, value);
935 : 12 : out += buffer;
936 : : }
937 [ + - ]: 21 : else if (!stricmp(pars[i], "double"))
938 : : {
939 [ + + ]: 21 : if (!hasprec) precision = 5;
940 : 21 : out += ftostrvar(getnumdouble(params[0]), precision);
941 : : }
942 : 57 : }
943 : 0 : else asar_throw_error(2, error_type_block, error_id_unknown_variable);
944 : : }
945 : 66 : return out;
946 : 66 : }
947 : :
948 : :
949 : 436992 : void assembleblock(const char * block, bool isspecialline)
950 : : {
951 : 436992 : string tmp=block;
952 : : int numwords;
953 : 436992 : char ** word = qsplit(tmp.temp_raw(), " ", &numwords);
954 : 436992 : string resolved;
955 : : // when writing out the data for the addrToLine mapping,
956 : : // we want to write out the snespos we had before writing opcodes
957 : 436992 : int addrToLinePos = realsnespos & 0xFFFFFF;
958 : :
959 : : #define is(test) (!stricmpwithlower(word[0], test))
960 : : #define is0(test) (numwords==1 && !stricmpwithlower(word[0], test))
961 : : #define is1(test) (numwords==2 && !stricmpwithlower(word[0], test))
962 : : #define is2(test) (numwords==3 && !stricmpwithlower(word[0], test))
963 : : #define is3(test) (numwords==4 && !stricmpwithlower(word[0], test))
964 : : #define par word[1]
965 : :
966 [ - + - - : 436992 : if(!moreonlinecond && !(is("elseif") || is("else"))){
- - ]
967 : : return;
968 : : }
969 : :
970 : : // RPG Hacker: Hack to fix the bug where defines in elseifs would never get resolved
971 : : // This really seems like the only possible place for the fix
972 [ + + + + ]: 436992 : if (is("elseif") && numtrue+1==numif)
973 : : {
974 : 36 : resolvedefines(resolved, block);
975 : 36 : free(word);
976 : 36 : word = qsplit(resolved.temp_raw(), " ", &numwords);
977 : : }
978 : :
979 : : autoptr<char**> wordcopy=word;
980 [ + + + + : 436992 : if (numif==numtrue && is1("global")) {
+ + ]
981 [ + - + + ]: 21 : if (!addlabel(word[1], -1, true)) {
982 : 6 : asar_throw_error(1, error_type_block, error_id_invalid_global_label, word[1]);
983 : : }
984 : 15 : return;
985 : : }
986 [ + + + + : 437375 : while (numif==numtrue && word[0] && (!word[1] || strcmp(word[1], "=")) && addlabel(word[0]))
+ + + + +
+ + + ]
987 : : {
988 : 404 : word++;
989 : 404 : numwords--;
990 : : }
991 [ + + + + ]: 436970 : if (!word[0] || !word[0][0]) return;
992 [ + + + + ]: 326146 : if (numif==numtrue && word[0][0]=='%')
993 : : {
994 [ + + ]: 108 : if (!macrorecursion)
995 : : {
996 : : callerfilename=thisfilename;
997 : 105 : callerline=thisline;
998 : : }
999 : 108 : int fakeendif_prev = fakeendif;
1000 : 108 : int moreonlinecond_prev = moreonlinecond;
1001 : 108 : int calledmacros_prev = calledmacros;
1002 : 108 : int single_line_for_tracker_prev = single_line_for_tracker;
1003 : 108 : callmacro(strchr(block, '%')+1);
1004 : 102 : fakeendif = fakeendif_prev;
1005 : 102 : moreonlinecond = moreonlinecond_prev;
1006 : 102 : calledmacros = calledmacros_prev;
1007 : 102 : single_line_for_tracker = single_line_for_tracker_prev;
1008 [ + + ]: 102 : if (!macrorecursion)
1009 : : {
1010 : : callerfilename="";
1011 : 99 : callerline=-1;
1012 : : }
1013 : 102 : return;
1014 : : }
1015 [ + + + + : 326038 : if (is("if") || is("elseif") || is("assert") || is("while") || is("for"))
+ + + + +
+ ]
1016 : : {
1017 [ + + + + ]: 105912 : if(is("if") && moreonline) fakeendif++;
1018 [ - + - - ]: 105912 : if (emulatexkas) asar_throw_warning(0, warning_id_convert_to_asar);
1019 : 105912 : string errmsg;
1020 : 105912 : whiletracker wstatus;
1021 : 105912 : wstatus.startline = thisline;
1022 : 105912 : wstatus.iswhile = false;
1023 : 105912 : wstatus.cond = false;
1024 : 105912 : wstatus.is_for = false;
1025 : 105912 : wstatus.for_start = wstatus.for_end = wstatus.for_cur = 0;
1026 : 105912 : wstatus.for_has_var_backup = false;
1027 [ + + ]: 105912 : if (is("while")) wstatus.iswhile = true;
1028 [ + + ]: 105912 : if (is("for")) wstatus.is_for = true;
1029 : : // if we are a for loop and:
1030 : : // 1) whilestatus has an entry at this level already
1031 : : // 2) said entry represents an incomplete for loop
1032 : : // then this loop must be meant "for us".
1033 : : // check number 2 is necessary because otherwise, 2 for loops back-to-back (not nested) would try to use the same whilestatus entry
1034 : : bool is_for_cont = false;
1035 [ + + + + : 106085 : if (is("for") && whilestatus.count > numif && whilestatus[numif].is_for && whilestatus[numif].for_cur < whilestatus[numif].for_end)
+ + + + ]
1036 : : {
1037 : : // continuation of a for loop
1038 : : is_for_cont = true;
1039 : : }
1040 : 105912 : whiletracker& addedwstatus = is_for_cont ? whilestatus[numif] : (whilestatus[numif] = wstatus);
1041 [ + + ]: 105912 : if (is("assert"))
1042 : : {
1043 [ + - ]: 15 : autoptr<char**> tokens = qpsplit(word[numwords - 1], ",");
1044 [ + - + + ]: 15 : if (tokens[0] != NULL && tokens[1] != NULL)
1045 : : {
1046 : 6 : string rawerrmsg;
1047 : : size_t pos = 1;
1048 [ + + ]: 27 : while (tokens[pos])
1049 : : {
1050 : 21 : rawerrmsg += tokens[pos];
1051 [ + + ]: 21 : if (tokens[pos + 1] != NULL)
1052 : : {
1053 : 15 : rawerrmsg += ",";
1054 : : }
1055 : : pos++;
1056 : : }
1057 : :
1058 : 6 : errmsg = handle_print(rawerrmsg.raw());
1059 : 6 : }
1060 : 15 : }
1061 [ + + + + : 105912 : if (numtrue!=numif && !(is("elseif") && numtrue+1==numif))
+ - ]
1062 : : {
1063 [ + - + + : 18 : if ((is("if") || is("while") || is("for"))) numif++;
+ - ]
1064 : : return;
1065 : : }
1066 [ + + + + : 105894 : if ((is("if") || is("while") || is("for"))) numif++;
+ + ]
1067 : : bool cond;
1068 : :
1069 : 105894 : bool isassert = is("assert");
1070 : :
1071 : 105894 : char ** nextword=word+1;
1072 : : char * condstr= nullptr;
1073 [ + + ]: 105894 : if(!is("for")) {
1074 : : while (true)
1075 : : {
1076 [ - + - - ]: 105732 : if (!nextword[0]) asar_throw_error(0, error_type_block, error_id_broken_conditional, word[0]);
1077 : : bool thiscond = false;
1078 [ + + + - : 105732 : if (!nextword[1] || !strcmp(nextword[1], "&&") || !strcmp(nextword[1], "||"))
- + ]
1079 : : {
1080 [ - + ]: 177 : if (nextword[0][0] == '!')
1081 : : {
1082 : 0 : asar_throw_warning(0, warning_id_feature_deprecated, "old style conditional negation (if !condition) ", "the not function");
1083 : 0 : double val = getnumdouble(nextword[0]+1);
1084 [ # # # # : 0 : if (foundlabel && !foundlabel_static && !isassert) asar_throw_error(0, error_type_block, error_id_label_in_conditional, word[0]);
# # # # ]
1085 : 0 : thiscond = !(val > 0);
1086 : : }
1087 : : else
1088 : : {
1089 : 177 : double val = getnumdouble(nextword[0]);
1090 [ - + - - : 177 : if (foundlabel && !foundlabel_static && !isassert) asar_throw_error(0, error_type_block, error_id_label_in_conditional, word[0]);
- - - - ]
1091 : 177 : thiscond = (val > 0);
1092 : : }
1093 : :
1094 [ - + - - ]: 177 : if (condstr && nextword[1])
1095 : : {
1096 [ # # # # ]: 0 : if (strcmp(condstr, nextword[1])) asar_throw_error(1, error_type_block, error_id_invalid_condition);
1097 : : }
1098 : 177 : else condstr=nextword[1];
1099 : 177 : nextword+=2;
1100 : 177 : }
1101 : : else
1102 : : {
1103 [ - + - - ]: 105555 : if (!nextword[2]) asar_throw_error(0, error_type_block, error_id_broken_conditional, word[0]);
1104 : 105555 : double par1=getnumdouble(nextword[0]);
1105 [ + + + + : 105555 : if (foundlabel && !foundlabel_static && !isassert) asar_throw_error(0, error_type_block, error_id_label_in_conditional, word[0]);
+ - - + ]
1106 : 105540 : double par2=getnumdouble(nextword[2]);
1107 [ - + - - : 105540 : if (foundlabel && !foundlabel_static && !isassert) asar_throw_error(0, error_type_block, error_id_label_in_conditional, word[0]);
- - - - ]
1108 : : if(0);
1109 [ + + ]: 105540 : else if (!strcmp(nextword[1], ">")) thiscond=(par1>par2);
1110 [ + + ]: 105480 : else if (!strcmp(nextword[1], "<")) thiscond=(par1<par2);
1111 [ + + ]: 51 : else if (!strcmp(nextword[1], ">=")) thiscond=(par1>=par2);
1112 [ - + ]: 48 : else if (!strcmp(nextword[1], "<=")) thiscond=(par1<=par2);
1113 [ - + ]: 48 : else if (!strcmp(nextword[1], "=")) thiscond=(par1==par2);
1114 [ + - ]: 48 : else if (!strcmp(nextword[1], "==")) thiscond=(par1==par2);
1115 [ # # ]: 0 : else if (!strcmp(nextword[1], "!=")) thiscond=(par1!=par2);
1116 : : //else if (!strcmp(nextword[1], "<>")) thiscond=(par1!=par2);
1117 : 0 : else asar_throw_error(0, error_type_block, error_id_broken_conditional, word[0]);
1118 : :
1119 [ + + - + ]: 105540 : if (condstr && nextword[3])
1120 : : {
1121 [ # # # # ]: 0 : if (strcmp(condstr, nextword[3])) asar_throw_error(1, error_type_block, error_id_invalid_condition);
1122 : : }
1123 : 105540 : else condstr=nextword[3];
1124 : 105540 : nextword+=4;
1125 : : }
1126 [ + + ]: 105717 : if (condstr)
1127 : : {
1128 [ + - + + ]: 9 : if (!strcmp(condstr, "&&")) { if(thiscond) continue; }
1129 [ # # # # ]: 0 : else if (!strcmp(condstr, "||")) { if(!thiscond) continue; }
1130 : 0 : else asar_throw_error(0, error_type_block, error_id_broken_conditional, word[0]);
1131 : : }
1132 : : cond=thiscond;
1133 : : break;
1134 : : }
1135 : : }
1136 : :
1137 [ + + ]: 105879 : if (is("for"))
1138 : : {
1139 : : // for loops as anything except the first block cause weirdness
1140 : : // (while loops do too, but let's not talk about it)
1141 [ - + ]: 165 : if(single_line_for_tracker != 1) {
1142 : 0 : numif--;
1143 : 0 : asar_throw_error(0, error_type_line, error_id_bad_single_line_for);
1144 : : }
1145 : : // TODO: these errors could probably be a bit more descriptive
1146 [ + + ]: 165 : if(!is_for_cont)
1147 : : {
1148 : : // "for i = 0..16"
1149 [ - + - - ]: 42 : if(numwords != 4) asar_throw_error(0, error_type_block, error_id_broken_for_loop);
1150 [ - + - - ]: 42 : if(strcmp(word[2], "=") != 0) asar_throw_error(0, error_type_block, error_id_broken_for_loop);
1151 : :
1152 : 42 : char* range_sep = strqpstr(word[3], "..");
1153 [ - + ]: 42 : if(!range_sep)
1154 : 0 : asar_throw_error(0, error_type_block, error_id_broken_for_loop, "invalid loop range");
1155 : :
1156 : 42 : string for_start(word[3], range_sep - word[3]);
1157 : 42 : string for_end(range_sep+2);
1158 : 42 : addedwstatus.for_start = getnum(for_start);
1159 [ - + - - : 42 : if(foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_label_in_conditional, "for");
- - ]
1160 : 42 : addedwstatus.for_end = getnum(for_end);
1161 [ - + - - : 42 : if(foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_label_in_conditional, "for");
- - ]
1162 : 42 : string varname = word[1];
1163 [ + - - + : 42 : if(!validatedefinename(varname)) asar_throw_error(0, error_type_block, error_id_broken_for_loop);
- - ]
1164 : 42 : addedwstatus.for_variable = varname;
1165 : 42 : addedwstatus.for_cur = addedwstatus.for_start;
1166 : 42 : }
1167 : : else
1168 : : {
1169 : 123 : addedwstatus.for_cur++;
1170 : : }
1171 : : // this cond is actually also used to tell assemblefile whether to jump back to the beginning of the loop, so keep it updated
1172 : 165 : addedwstatus.cond = addedwstatus.for_cur < addedwstatus.for_end;
1173 : 165 : single_line_for_tracker = 2;
1174 [ + + ]: 165 : if(addedwstatus.cond)
1175 : : {
1176 : 123 : numtrue++;
1177 [ + + ]: 123 : if(defines.exists(addedwstatus.for_variable)) {
1178 : 96 : addedwstatus.for_has_var_backup = true;
1179 : 96 : addedwstatus.for_var_backup = defines.find(addedwstatus.for_variable);
1180 : : }
1181 : 123 : defines.create(addedwstatus.for_variable) = ftostr(addedwstatus.for_cur);
1182 : : }
1183 : : }
1184 [ + + + + ]: 105714 : else if (is("if") || is("while"))
1185 : : {
1186 : : if(0);
1187 [ + + ]: 105630 : else if (cond)
1188 : : {
1189 : 105522 : numtrue++;
1190 : 105522 : elsestatus[numif]=true;
1191 : : }
1192 : : else if (!cond)
1193 : : {
1194 [ - + ]: 108 : if(moreonline) moreonlinecond=false;
1195 : 108 : elsestatus[numif]=false;
1196 : : }
1197 : 105630 : addedwstatus.cond = cond;
1198 : : }
1199 [ + + ]: 84 : else if (is("elseif"))
1200 : : {
1201 [ - + - - ]: 69 : if (!numif) asar_throw_error(1, error_type_block, error_id_misplaced_elseif);
1202 [ - + - - ]: 69 : if (whilestatus[numif - 1].iswhile) asar_throw_error(1, error_type_block, error_id_elseif_in_while);
1203 [ + + ]: 69 : if (numif==numtrue) numtrue--;
1204 [ + + + + ]: 102 : if (cond && !elsestatus[numif])
1205 : : {
1206 [ - + ]: 18 : if(moreonline) moreonlinecond = true;
1207 : 18 : numtrue++;
1208 : 18 : elsestatus[numif]=true;
1209 : : }
1210 : : }
1211 : : // otherwise, must be assert command
1212 [ + + + + ]: 15 : else if (pass == 2 && !cond)
1213 : : {
1214 [ + + - + ]: 8 : if (errmsg) asar_throw_error(2, error_type_block, error_id_assertion_failed, (string(": ") + errmsg).data());
1215 : 2 : else asar_throw_error(2, error_type_block, error_id_assertion_failed, ".");
1216 : : }
1217 : 105931 : }
1218 [ + + + + : 220126 : else if (is("endif") || is("endwhile") || is("endfor"))
+ + ]
1219 : : {
1220 [ + + ]: 105828 : if(fakeendif) fakeendif--;
1221 [ - + - - ]: 105828 : if (numwords != 1) asar_throw_error(1, error_type_block, error_id_unknown_command);
1222 [ - + - - ]: 105828 : if (!numif) asar_throw_error(1, error_type_block, error_id_misplaced_endif);
1223 [ + + ]: 105828 : if (numif==numtrue) numtrue--;
1224 : 105828 : numif--;
1225 [ + + ]: 105828 : if(whilestatus[numif].is_for) {
1226 [ + + ]: 174 : if(single_line_for_tracker == 2) single_line_for_tracker = 3;
1227 [ - + ]: 174 : if(moreonline) {
1228 : : // sabotage the whilestatus to prevent the loop running again
1229 : : // and spamming more of the same error
1230 : 0 : whilestatus[numif].for_cur = whilestatus[numif].for_end;
1231 : 0 : whilestatus[numif].cond = false;
1232 : 0 : asar_throw_error(0, error_type_block, error_id_bad_single_line_for);
1233 : : }
1234 [ + + ]: 174 : if(whilestatus[numif].cond) {
1235 [ + + ]: 123 : if(whilestatus[numif].for_has_var_backup)
1236 : 96 : defines.create(whilestatus[numif].for_variable) = whilestatus[numif].for_var_backup;
1237 : 27 : else defines.remove(whilestatus[numif].for_variable);
1238 : : }
1239 : : }
1240 [ + + ]: 105828 : if(warn_endwhile) {
1241 [ + + ]: 105403 : if(whilestatus[numif].iswhile) {
1242 [ + + ]: 105070 : if(!is("endwhile")) {
1243 : 1 : warn_endwhile = false;
1244 : 1 : asar_throw_warning(0, warning_id_feature_deprecated, "mismatched terminators", "use endwhile to terminate a while statement");
1245 : : }
1246 : : }
1247 [ + + ]: 333 : else if(whilestatus[numif].is_for) {
1248 [ - + ]: 174 : if(!is("endfor")) {
1249 : 0 : warn_endwhile = false;
1250 : 0 : asar_throw_warning(0, warning_id_feature_deprecated, "mismatched terminators", "use endfor to terminate a for statement");
1251 : : }
1252 : : }
1253 [ - + ]: 159 : else if(!is("endif")) {
1254 : 0 : warn_endwhile = false;
1255 : 0 : asar_throw_warning(0, warning_id_feature_deprecated, "mismatched terminators", "use endif to terminate an if statement");
1256 : : }
1257 : : }
1258 : : }
1259 [ + + ]: 114298 : else if (is("else"))
1260 : : {
1261 [ - + ]: 108 : if(!moreonlinecond) moreonlinecond = true;
1262 [ - + - - ]: 108 : if (numwords != 1) asar_throw_error(1, error_type_block, error_id_unknown_command);
1263 [ - + - - ]: 108 : if (!numif) asar_throw_error(1, error_type_block, error_id_misplaced_else);
1264 [ + - + - : 108 : if (whilestatus[numif - 1].iswhile || whilestatus[numif - 1].is_for) asar_throw_error(1, error_type_block, error_id_else_in_while_loop);
- - ]
1265 [ + + ]: 108 : else if (numif==numtrue) numtrue--;
1266 [ + - + + ]: 108 : else if (numif==numtrue+1 && !elsestatus[numif])
1267 : : {
1268 : 21 : numtrue++;
1269 : 21 : elsestatus[numif]=true;
1270 : : }
1271 : : }
1272 [ + + ]: 114190 : else if (numif!=numtrue) return;
1273 [ + + + + ]: 113788 : else if (asblock_pick(word, numwords))
1274 : : {
1275 : 4775 : add_addr_to_line(addrToLinePos);
1276 : 4775 : numopcodes += recent_opcode_num;
1277 : : }
1278 [ + + + + ]: 109012 : else if (is1("undef"))
1279 : : {
1280 : 3 : string def;
1281 : : // RPG Hacker: Not sure if we should allow this?
1282 : : // Currently, the manual states that we should not include the
1283 : : // exclamation mark, and I believe that this is for the better
1284 : : // because I can see this leading to ambiguities or causing
1285 : : // problems. If we add this back in, we should definitely
1286 : : // also added it to the defined() function for consistency, though.
1287 : : // Well, actually I just check and we can't support this in
1288 : : // defined() (the defined is already replaced at that point), so
1289 : : // I think we should not support it here, either.
1290 : : /*if (*par == '!') def = S safedequote(par) + 1;
1291 : 3 : else*/ def = STR safedequote(par);
1292 : :
1293 [ + - ]: 3 : if (defines.exists(def))
1294 : : {
1295 : 3 : defines.remove(def);
1296 : : }
1297 : : else
1298 : : {
1299 : 0 : asar_throw_error(0, error_type_block, error_id_define_not_found, def.data());
1300 : : }
1301 : 3 : }
1302 [ + + + + ]: 109009 : else if (is0("error"))
1303 : : {
1304 : 3 : asar_throw_error(0, error_type_block, error_id_error_command, ".");
1305 : : }
1306 [ + + + + ]: 109006 : else if (is0("warn"))
1307 : : {
1308 : 3 : asar_throw_warning(2, warning_id_warn_command, ".");
1309 : : }
1310 [ + + + + ]: 109003 : else if (is1("error"))
1311 : : {
1312 : 6 : string out = handle_print(par);
1313 : : // RPG Hacker: This used to be on pass 0, which had its merits (you don't want to miss a potentially critical
1314 : : // user-generated error, just because a bazillion other errors are thrown in passes before it). However, I
1315 : : // don't see how to support print functions with this without moving it to pass 2. Suggestions are welcome.
1316 : 18 : asar_throw_error(2, error_type_block, error_id_error_command, (string(": ") + out).data());
1317 : 6 : }
1318 [ + + + + ]: 108997 : else if (is1("warn"))
1319 : : {
1320 : 6 : string out = handle_print(par);
1321 : 12 : asar_throw_warning(2, warning_id_warn_command, (string(": ") + out).data());
1322 : 6 : }
1323 [ + + + + ]: 108991 : else if (is1("warnings"))
1324 : : {
1325 [ + + ]: 18 : if (stricmp(word[1], "push") == 0)
1326 : : {
1327 : 9 : push_warnings();
1328 : : }
1329 [ + - ]: 9 : else if (stricmp(word[1], "pull") == 0)
1330 : : {
1331 : 9 : pull_warnings();
1332 : : }
1333 : : }
1334 [ + + + + ]: 108973 : else if (is2("warnings"))
1335 : : {
1336 [ + + ]: 36 : if (stricmp(word[1], "enable") == 0)
1337 : : {
1338 : 6 : asar_warning_id warnid = parse_warning_id_from_string(word[2]);
1339 : :
1340 [ + - ]: 6 : if (warnid != warning_id_end)
1341 : : {
1342 : 6 : set_warning_enabled(warnid, true);
1343 : : }
1344 : : else
1345 : : {
1346 : 0 : asar_throw_error(0, error_type_null, error_id_invalid_warning_id, "warnings enable", (int)(warning_id_start + 1), (int)(warning_id_end - 1));
1347 : : }
1348 : : }
1349 [ + - ]: 30 : else if (stricmp(word[1], "disable") == 0)
1350 : : {
1351 : 30 : asar_warning_id warnid = parse_warning_id_from_string(word[2]);
1352 : :
1353 [ + - ]: 30 : if (warnid != warning_id_end)
1354 : : {
1355 : 30 : set_warning_enabled(warnid, false);
1356 : : }
1357 : : else
1358 : : {
1359 : 0 : asar_throw_error(0, error_type_null, error_id_invalid_warning_id, "warnings disable", (int)(warning_id_start + 1), (int)(warning_id_end - 1));
1360 : : }
1361 : : }
1362 : : }
1363 [ + + + + ]: 108937 : else if (is2("check"))
1364 : : {
1365 [ + + ]: 34 : if (stricmp(word[1], "title") == 0)
1366 : : {
1367 : : // RPG Hacker: Removed trimming for now - I think requiring an exact match is probably
1368 : : // better here (not sure, though, it's worth discussing)
1369 : 3 : string expected_title = safedequote(word[2]);
1370 : : // randomdude999: this also removes leading spaces because itrim gets stuck in an endless
1371 : : // loop when multi is true and one argument is empty
1372 : : //expected_title = itrim(expected_title.data(), " ", " ", true); // remove trailing spaces
1373 : : // in hirom the rom needs to be an entire bank for it to have a title, other modes only need 0x8000 bytes
1374 [ + - - + : 3 : if (romlen < ((mapper == hirom || mapper == exhirom) ? 0x10000 : 0x8000)) // too short
- + ]
1375 : : {
1376 [ # # ]: 0 : if (!ignoretitleerrors) // title errors shouldn't be ignored
1377 : 0 : asar_throw_error(0, error_type_block, error_id_rom_too_short, expected_title.data());
1378 : : else // title errors should be ignored, throw a warning anyways
1379 : 0 : asar_throw_warning(0, warning_id_rom_too_short, expected_title.data());
1380 : : }
1381 : : else {
1382 : 3 : string actual_title;
1383 : 3 : string actual_display_title;
1384 [ + + ]: 66 : for (int i = 0;i < 21;i++)
1385 : : {
1386 : 63 : unsigned char c = romdata[snestopc(0x00FFC0 + i)];
1387 : 63 : actual_title += (char)c;
1388 : : // the replacements are from interface-cli.cpp
1389 [ + - ]: 63 : if (c == 7) c = 14;
1390 [ + - ]: 63 : if (c == 8) c = 27;
1391 [ + - ]: 63 : if (c == 9) c = 26;
1392 [ + - ]: 63 : if (c == '\r') c = 17;
1393 [ + - ]: 63 : if (c == '\n') c = 25;
1394 [ - + ]: 63 : if (c == '\0') c = 155;
1395 : 63 : actual_display_title += (char)c;
1396 : : }
1397 : : //actual_display_title = itrim(actual_display_title.data(), " ", " ", true); // remove trailing spaces
1398 : : //actual_title = itrim(actual_title.data(), " ", " ", true); // remove trailing spaces
1399 [ - + ]: 3 : if (strncmp(expected_title, actual_title, 21) != 0)
1400 : : {
1401 [ # # ]: 0 : if (!ignoretitleerrors) // title errors shouldn't be ignored
1402 : 0 : asar_throw_error(0, error_type_block, error_id_rom_title_incorrect, expected_title.data(), actual_display_title.data());
1403 : : else // title errors should be ignored, throw a warning anyways
1404 : 0 : asar_throw_warning(0, warning_id_rom_title_incorrect, expected_title.data(), actual_display_title.data());
1405 : : }
1406 : 3 : }
1407 : 3 : }
1408 [ + - ]: 31 : else if (stricmp(word[1], "bankcross") == 0)
1409 : : {
1410 : : if (0);
1411 [ + + ]: 31 : else if (!stricmp(word[2], "on"))
1412 : : {
1413 : 15 : asar_throw_warning(0, warning_id_feature_deprecated, "bankcheck on", "bankcheck full or bankcheck half");
1414 : : }
1415 [ + + ]: 16 : else if (!stricmp(word[2], "off"))
1416 : : {
1417 : 15 : disable_bank_cross_errors = true;
1418 : : }
1419 [ + - ]: 1 : else if (!stricmp(word[2], "half"))
1420 : : {
1421 : 1 : disable_bank_cross_errors = false;
1422 : 1 : check_half_banks_crossed = true;
1423 : : }
1424 [ # # ]: 0 : else if (!stricmp(word[2], "full"))
1425 : : {
1426 : 0 : disable_bank_cross_errors = false;
1427 : 0 : check_half_banks_crossed = false;
1428 : : }
1429 : 0 : else asar_throw_error(0, error_type_block, error_id_invalid_check);
1430 : :
1431 : : }
1432 : : else
1433 : : {
1434 : 0 : asar_throw_error(0, error_type_block, error_id_invalid_check);
1435 : : }
1436 : : }
1437 [ + + + - : 108903 : else if (is0("asar") || is1("asar"))
+ + + + ]
1438 : : {
1439 [ - + - - ]: 15 : if (!asarverallowed) asar_throw_error(0, error_type_block, error_id_start_of_file);
1440 [ + - ]: 15 : if (!par) return;
1441 [ - + - - ]: 15 : if (emulatexkas) asar_throw_error(0, error_type_block, error_id_xkas_asar_conflict);
1442 : : int dots=0;
1443 : : int dig=0;
1444 [ + + ]: 75 : for (int i=0;par[i];i++)
1445 : : {
1446 [ + + ]: 60 : if (par[i]=='.')
1447 : : {
1448 [ - + - - ]: 15 : if (!dig) asar_throw_error(0, error_type_block, error_id_invalid_version_number);
1449 : : dig=0;
1450 : 15 : dots++;
1451 : : }
1452 [ + - ]: 45 : else if (is_digit(par[i])) dig++;
1453 : 0 : else asar_throw_error(0, error_type_block, error_id_invalid_version_number);
1454 : : }
1455 [ + - - + : 15 : if (!dig || !dots || dots>2) asar_throw_error(0, error_type_block, error_id_invalid_version_number);
- - ]
1456 [ + - ]: 15 : autoptr<char**> vers=split(par, ".");
1457 : 15 : int vermaj=atoi(vers[0]);
1458 [ - + - - ]: 15 : if (vermaj > asarver_maj) asar_throw_error(pass, error_type_fatal, error_id_asar_too_old);
1459 [ - + ]: 15 : if (vermaj<asarver_maj) return;
1460 [ + - ]: 15 : if (dots==1)
1461 : : {
1462 [ - + - - ]: 15 : if (strlen(vers[1])!=2) asar_throw_error(0, error_type_block, error_id_invalid_version_number);
1463 : : //if (asarver_min<10 && asarver_bug<10 && strlen(vers[1])>2) error(0, "This version of Asar is too old for this patch.");
1464 : 15 : int verminbug=atoi(vers[1]);
1465 : 15 : int tmpver=asarver_bug;
1466 : 15 : if (tmpver>9) tmpver=9;
1467 [ - + - - ]: 15 : if (asarver_min*10+tmpver<verminbug) asar_throw_error(pass, error_type_fatal, error_id_asar_too_old);
1468 [ + + ]: 15 : if(vermaj == 1 && verminbug >= 90) { default_math_pri = true; default_math_round_off = true; }
1469 : : }
1470 : : else
1471 : : {
1472 : 0 : int vermin=atoi(vers[1]);
1473 [ # # # # ]: 0 : if (vermin>asarver_min) asar_throw_error(pass, error_type_fatal, error_id_asar_too_old);
1474 : 0 : int verbug=atoi(vers[2]);
1475 [ # # # # : 0 : if (vermin==asarver_min && verbug>asarver_bug) asar_throw_error(pass, error_type_fatal, error_id_asar_too_old);
# # ]
1476 [ # # ]: 0 : if(vermaj == 1 && vermin >= 9) { default_math_pri = true; default_math_round_off = true; }
1477 : : }
1478 : 15 : specifiedasarver = true;
1479 : 15 : }
1480 [ + + + + ]: 108888 : else if (is0("xkas"))
1481 : : {
1482 : 6 : asar_throw_warning(0, warning_id_feature_deprecated, "xkas compatibility mode", "UPGRADE YOUR PATCH ITS 2021!!!");
1483 [ - + - - ]: 6 : if (!asarverallowed) asar_throw_error(0, error_type_block, error_id_start_of_file);
1484 [ + + + - : 6 : if (incsrcdepth != 1 && !emulatexkas) asar_throw_error(0, error_type_block, error_id_command_in_non_root_file);
- + ]
1485 [ - + - - ]: 3 : if (specifiedasarver) asar_throw_error(0, error_type_block, error_id_xkas_asar_conflict);
1486 : 3 : emulatexkas=true;
1487 : 3 : optimizeforbank=0x100;
1488 [ + - ]: 3 : if(!force_checksum_fix)
1489 : 3 : checksum_fix_enabled = false;
1490 : : sublabels[0]=":xkasdefault:";
1491 : : }
1492 [ + + + - : 108882 : else if (is0("include") || is1("includefrom"))
+ + - + ]
1493 : : {
1494 [ # # # # ]: 0 : if (!asarverallowed) asar_throw_error(0, error_type_block, error_id_start_of_file);
1495 [ # # ]: 0 : if (istoplevel)
1496 : : {
1497 [ # # # # ]: 0 : if (par) asar_throw_error(pass, error_type_fatal, error_id_cant_be_main_file, (string(" The main file is '") + STR par + STR "'.").data());
1498 : 0 : else asar_throw_error(pass, error_type_fatal, error_id_cant_be_main_file, "");
1499 : : }
1500 : : }
1501 [ + + + + ]: 108882 : else if (is0("includeonce"))
1502 : : {
1503 [ + - + - ]: 15 : if (!file_included_once(thisfilename))
1504 : : {
1505 : 15 : includeonce.append(thisfilename);
1506 : : }
1507 : : }
1508 [ + + + + : 108867 : else if (is1("db") || is1("dw") || is1("dl") || is1("dd"))
+ + + + +
+ + + + +
+ + ]
1509 : : {
1510 : : int len = 0;
1511 [ + - - + : 106918 : if (!confirmqpar(par)) asar_throw_error(0, error_type_block, error_id_mismatched_parentheses);
- - ]
1512 [ + - + + ]: 106918 : if (is1("db")) len=1;
1513 [ + - + + ]: 106918 : if (is1("dw")) len=2;
1514 [ + - + + ]: 106918 : if (is1("dl")) len=3;
1515 [ + - + + ]: 106918 : if (is1("dd")) len=4;
1516 [ + - ]: 106918 : autoptr<char**> pars=qpsplit(par, ",");
1517 [ + + ]: 214188 : for (int i=0;pars[i];i++)
1518 : : {
1519 [ + + ]: 107275 : if (pars[i][0]=='"')
1520 : : {
1521 [ + + - + ]: 84 : if (!strcmp(pars[i],"\"STAR\"") && !emulatexkas)
1522 : 0 : asar_throw_warning(0, warning_id_xkas_patch);
1523 [ + - + + ]: 393 : for (char * str=const_cast<char*>(safedequote(pars[i]));*str;str++)
1524 : : {
1525 [ + + + - ]: 309 : if (len==1) write1(table.table[(size_t)(unsigned char) *str]);
1526 [ + + + - ]: 309 : if (len==2) write2(table.table[(size_t)(unsigned char) *str]);
1527 [ + + + - ]: 309 : if (len==3) write3(table.table[(size_t)(unsigned char) *str]);
1528 [ + + + - ]: 309 : if (len==4) write4(table.table[(size_t)(unsigned char) *str]);
1529 : : }
1530 : : }
1531 : : else
1532 : : {
1533 : : const char * math=pars[i];
1534 [ - + ]: 107191 : if (math[0]=='#') math++;
1535 [ + + + + ]: 107191 : unsigned int num=(pass==2)?getnum(math):0;
1536 [ + + ]: 107186 : if (len == 1) write1(num);
1537 [ + + + - ]: 107186 : if (len == 2) write2(num);
1538 [ + + + - ]: 107186 : if (len == 3) write3(num);
1539 [ + + + - ]: 107186 : if (len == 4) write4(num);
1540 : : }
1541 : : }
1542 : 106913 : add_addr_to_line(addrToLinePos);
1543 : 106918 : }
1544 [ + + + + ]: 1949 : else if (numwords==3 && !stricmp(word[1], "="))
1545 : : {
1546 [ + + + - : 111 : if (word[0][0]=='\'' && word[0][1] && word[0][2]=='\'' && word[0][3]=='\0')
+ - + - ]
1547 : : {
1548 : 75 : table.table[(unsigned char)word[0][1]]=getnum(word[2]);
1549 [ + + - + : 75 : if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_no_labels_here);
- - ]
1550 : 75 : return;
1551 : : }
1552 : : // randomdude999: int cast b/c i'm too lazy to also mess with making setlabel()
1553 : : // unsigned, besides it wouldn't matter anyways.
1554 : 36 : int num=(int)getnum(word[2]);
1555 [ + + + + : 36 : if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_label_cross_assignment);
- + ]
1556 : :
1557 : 33 : const char* newlabelname = word[0];
1558 : : bool ismacro = false;
1559 : :
1560 [ + + ]: 33 : if (newlabelname[0] == '?')
1561 : : {
1562 : : ismacro = true;
1563 : 3 : newlabelname++;
1564 : : }
1565 : :
1566 [ + - ]: 3 : if (ismacro && macrorecursion == 0)
1567 : : {
1568 : 0 : asar_throw_error(0, error_type_block, error_id_macro_label_outside_of_macro);
1569 : : }
1570 : :
1571 [ - + - - ]: 33 : if (!confirmname(newlabelname)) asar_throw_error(0, error_type_block, error_id_invalid_label_name);
1572 : :
1573 : 33 : string completename;
1574 : :
1575 [ + + ]: 33 : if (ismacro)
1576 : : {
1577 : 6 : completename += STR":macro_" + dec(calledmacros) + "_";
1578 : : }
1579 : :
1580 : 33 : completename += newlabelname;
1581 : :
1582 : 33 : setlabel(ns + completename, num, true);
1583 : 33 : }
1584 [ + - + + ]: 1838 : else if (assemblemapper(word, numwords)) {}
1585 [ + + + + ]: 1759 : else if (is1("org"))
1586 : : {
1587 [ - + - - ]: 346 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_feature_unavaliable_in_spcblock);
1588 : 346 : freespaceend();
1589 : 346 : unsigned int num=getnum(par);
1590 [ - + - - ]: 346 : if (forwardlabel) asar_throw_error(0, error_type_block, error_id_org_label_forward);
1591 [ - + - - ]: 346 : if (num&~0xFFFFFF) asar_throw_error(1, error_type_block, error_id_snes_address_out_of_bounds, hex6(num).data());
1592 [ + + + + : 346 : if ((mapper==lorom || mapper==exlorom) && (num&0x408000)==0x400000 && (num&0x700000)!=0x700000) asar_throw_warning(0, warning_id_set_middle_byte);
- + - - -
- ]
1593 : : //if (fastrom) num|=0x800000;
1594 : 346 : snespos=(int)num;
1595 : 346 : realsnespos=(int)num;
1596 : 346 : startpos=(int)num;
1597 : 346 : realstartpos=(int)num;
1598 : : }
1599 : : #define ret_error(errid) { asar_throw_error(0, error_type_block, errid); return; }
1600 : : #define ret_error_params(errid, ...) { asar_throw_error(0, error_type_block, errid, __VA_ARGS__); return; }
1601 [ + + ]: 1413 : else if (is("struct"))
1602 : : {
1603 : : //verifysnespos();
1604 [ + - - + : 36 : if (in_struct || in_sub_struct) ret_error(error_id_nested_struct);
- - ]
1605 [ - + - - ]: 36 : if (numwords < 2) ret_error(error_id_missing_struct_params);
1606 [ - + - - ]: 36 : if (numwords > 4) ret_error(error_id_too_many_struct_params);
1607 [ - + - - ]: 36 : if (!confirmname(word[1])) ret_error(error_id_invalid_struct_name);
1608 : :
1609 [ + + + - : 36 : if (structs.exists(word[1]) && pass == 0) ret_error_params(error_id_struct_redefined, word[1]);
- - ]
1610 : :
1611 : 36 : static_struct = false;
1612 : 36 : old_snespos = snespos;
1613 : 36 : old_startpos = startpos;
1614 : 36 : old_optimizeforbank = optimizeforbank;
1615 : : unsigned int base = 0;
1616 [ + + ]: 36 : if (numwords == 3)
1617 : : {
1618 : 12 : static_struct = true;
1619 : 12 : base = getnum(word[2]);
1620 : :
1621 [ - + - - ]: 12 : if (foundlabel && !foundlabel_static) static_struct = false;
1622 : : }
1623 : :
1624 : 36 : bool old_in_struct = in_struct;
1625 : 36 : bool old_in_sub_struct = in_sub_struct;
1626 : 36 : in_struct = numwords == 2 || numwords == 3;
1627 : 36 : in_sub_struct = numwords == 4;
1628 : :
1629 : : #define ret_error_cleanup(errid) { in_struct = old_in_struct; in_sub_struct = old_in_sub_struct; asar_throw_error(0, error_type_block, errid); return; }
1630 : : #define ret_error_params_cleanup(errid, ...) { in_struct = old_in_struct; in_sub_struct = old_in_sub_struct; asar_throw_error(0, error_type_block, errid, __VA_ARGS__); return; }
1631 : :
1632 [ + + ]: 36 : if (numwords == 3)
1633 : : {
1634 [ - + - - ]: 12 : if (base&~0xFFFFFF) ret_error_params_cleanup(error_id_snes_address_out_of_bounds, hex6((unsigned int)base).data());
1635 : 12 : snespos = (int)base;
1636 : 12 : startpos = (int)base;
1637 : : }
1638 [ + + ]: 24 : else if (numwords == 4)
1639 : : {
1640 [ - + - - ]: 12 : if (strcasecmp(word[2], "extends")) ret_error_cleanup(error_id_missing_extends);
1641 [ - + - - ]: 12 : if (!confirmname(word[3])) ret_error_cleanup(error_id_struct_invalid_parent_name);
1642 : 12 : string tmp_struct_parent = word[3];
1643 : :
1644 [ - + - - ]: 12 : if (!structs.exists(tmp_struct_parent)) ret_error_params_cleanup(error_id_struct_not_found, tmp_struct_parent.data());
1645 : 12 : snes_struct structure = structs.find(tmp_struct_parent);
1646 : :
1647 : 12 : static_struct = structure.is_static;
1648 : : struct_parent = tmp_struct_parent;
1649 : 12 : snespos = structure.base_end;
1650 : 12 : startpos = structure.base_end;
1651 : 12 : }
1652 : :
1653 : 36 : push_pc();
1654 : :
1655 : 36 : optimizeforbank = -1;
1656 : :
1657 : 36 : struct_name = word[1];
1658 : 36 : struct_base = snespos;
1659 : 36 : realsnespos = 0;
1660 : 36 : realstartpos = 0;
1661 : : #undef ret_error_cleanup
1662 : : #undef ret_error_params_cleanup
1663 : : }
1664 [ + + ]: 1377 : else if (is("endstruct"))
1665 : : {
1666 [ + + - + : 36 : if (numwords != 1 && numwords != 3) ret_error(error_id_invalid_endstruct_count);
- - ]
1667 [ + + - + : 36 : if (numwords == 3 && strcasecmp(word[1], "align")) ret_error(error_id_expected_align);
- - ]
1668 [ + + - + : 36 : if (!in_struct && !in_sub_struct) ret_error(error_id_endstruct_without_struct);
- - ]
1669 : :
1670 [ + + + - ]: 36 : int alignment = numwords == 3 ? (int)getnum(word[2]) : 1;
1671 [ - + - - ]: 3 : if (alignment < 1) ret_error(error_id_alignment_too_small);
1672 : :
1673 : : snes_struct structure;
1674 : 36 : structure.base_end = snespos;
1675 : 36 : structure.struct_size = alignment * ((snespos - struct_base + alignment - 1) / alignment);
1676 : 36 : structure.object_size = structure.struct_size;
1677 : 36 : structure.is_static = static_struct;
1678 : :
1679 [ + + ]: 36 : if (in_struct)
1680 : : {
1681 : 24 : structs.create(struct_name) = structure;
1682 : : }
1683 [ + - ]: 12 : else if (in_sub_struct)
1684 : : {
1685 : : snes_struct parent;
1686 : 12 : parent = structs.find(struct_parent);
1687 : :
1688 [ + - ]: 12 : if (parent.object_size < parent.struct_size + structure.struct_size) {
1689 : 12 : parent.object_size = parent.struct_size + structure.struct_size;
1690 : : }
1691 : :
1692 : 12 : structs.create(struct_parent + "." + struct_name) = structure;
1693 : 12 : structs.create(struct_parent) = parent;
1694 : : }
1695 : :
1696 : 36 : pop_pc();
1697 : 36 : in_struct = false;
1698 : 36 : in_sub_struct = false;
1699 : 36 : snespos = old_snespos;
1700 : 36 : startpos = old_startpos;
1701 : 36 : optimizeforbank = old_optimizeforbank;
1702 : 36 : static_struct = false;
1703 : : }
1704 : : #undef ret_error
1705 [ + + ]: 1341 : else if(is("spcblock"))
1706 : : {
1707 : : //banned features when active: org, freespace(and variants), arch, mapper,namespace,pushns
1708 [ - + - - ]: 3 : if(arch != arch_spc700) asar_throw_error(0, error_type_block, error_id_spcblock_bad_arch);
1709 [ + - - + : 3 : if(in_struct || in_sub_struct) asar_throw_error(0, error_type_block, error_id_spcblock_inside_struct);
- - ]
1710 [ - + - - ]: 3 : if(numwords < 2) asar_throw_error(0, error_type_block, error_id_spcblock_too_few_args);
1711 [ - + - - ]: 3 : if(numwords > 4) asar_throw_error(0, error_type_block, error_id_spcblock_too_many_args);
1712 : :
1713 : 3 : spcblock.destination = getnum(par);
1714 : 3 : spcblock.type = spcblock_nspc;
1715 : : spcblock.macro_name = "";
1716 : :
1717 [ - + - - ]: 3 : if (spcblock.destination&~0xFFFF) asar_throw_error(0, error_type_block, error_id_snes_address_out_of_bounds, hex6(spcblock.destination).data());
1718 : :
1719 [ - + ]: 3 : if(numwords == 3)
1720 : : {
1721 [ # # ]: 0 : if(!stricmp(word[2], "nspc")) spcblock.type = spcblock_nspc;
1722 [ # # # # ]: 0 : else if(!stricmp(word[2], "custom")) asar_throw_error(0, error_type_block, error_id_custom_spcblock_missing_macro);
1723 : 0 : else asar_throw_error(0, error_type_block, error_id_unknown_spcblock_type);
1724 : : }
1725 [ - + ]: 3 : else if(numwords == 4)
1726 : : {
1727 [ # # ]: 0 : if(!stricmp(word[2], "custom")) spcblock.type = spcblock_custom;
1728 : 0 : else asar_throw_error(0, error_type_block, error_id_extra_spcblock_arg_for_type);
1729 : :
1730 [ # # ]: 0 : if(macros.exists(word[3]))
1731 : : {
1732 : 0 : macrodata *macro = macros.find(word[3]);
1733 [ # # # # ]: 0 : if(!macro->variadic) asar_throw_error(0, error_type_block, error_id_spcblock_macro_must_be_varadic);
1734 [ # # # # ]: 0 : if(macro->numargs != 3) asar_throw_error(0, error_type_block, error_id_spcblock_macro_invalid_static_args);
1735 : 0 : spcblock.macro_name = word[3];
1736 : : }
1737 : 0 : else asar_throw_error(0, error_type_block, error_id_spcblock_macro_doesnt_exist);
1738 : : }
1739 : :
1740 [ + - - ]: 3 : switch(spcblock.type)
1741 : : {
1742 : 3 : case spcblock_nspc:
1743 : 3 : spcblock.size_address=realsnespos;
1744 : 3 : write2(0x0000);
1745 : 3 : write2(spcblock.destination);
1746 : 3 : snespos=(int)spcblock.destination;
1747 : 3 : startpos=(int)spcblock.destination;
1748 : 3 : spcblock.execute_address = -1u;
1749 : 3 : add_addr_to_line(addrToLinePos);
1750 : : break;
1751 : 0 : case spcblock_custom:
1752 : : //this is a todo that probably won't be ready for 1.9
1753 : : //mostly so we can leverage some cleanups we make in 2.0 for practicality
1754 : 0 : asar_throw_error(0, error_type_block, error_id_spcblock_custom_types_incomplete);
1755 : 0 : push_pc();
1756 : 0 : spcblock.old_mapper = mapper;
1757 : 0 : mapper = norom;
1758 : 0 : break;
1759 : 0 : default:
1760 : 0 : asar_throw_error(0, error_type_fatal, error_id_internal_error, "invalid spcblock type");
1761 : : }
1762 : :
1763 : : ns_backup = ns;
1764 : 6 : ns = STR":SPCBLOCK:_" + ns_backup;
1765 : 3 : in_spcblock = true;
1766 : : }
1767 [ + + + + ]: 1338 : else if(is0("endspcblock"))
1768 : : {
1769 [ - + - - ]: 3 : if(!in_spcblock) asar_throw_error(0, error_type_block, error_id_endspcblock_without_spcblock);
1770 : :
1771 [ + - - ]: 3 : switch(spcblock.type)
1772 : : {
1773 : 3 : case spcblock_nspc:
1774 [ + + ]: 3 : if (pass==2)
1775 : : {
1776 : 1 : int pcpos=snestopc(spcblock.size_address&0xFFFFFF);
1777 [ - + - - ]: 1 : if (pcpos<0) asar_throw_error(2, error_type_block, error_id_snes_address_doesnt_map_to_rom, hex6((unsigned int)realsnespos).data());
1778 : 1 : int num=snespos-startpos;
1779 : 1 : writeromdata_byte(pcpos, (unsigned char)num);
1780 : 1 : writeromdata_byte(pcpos+1, (unsigned char)(num >> 8));
1781 : : }
1782 [ + - ]: 3 : if(spcblock.execute_address != -1u)
1783 : : {
1784 : 3 : write2(0x0000);
1785 : 3 : write2((unsigned int)spcblock.execute_address);
1786 : : }
1787 : : break;
1788 : 0 : case spcblock_custom:
1789 : 0 : mapper = spcblock.old_mapper;
1790 : 0 : pop_pc();
1791 : : break;
1792 : 0 : default:
1793 : 0 : asar_throw_error(0, error_type_fatal, error_id_internal_error, "invalid spcblock type");
1794 : : }
1795 : : ns = ns_backup;
1796 : 3 : in_spcblock = false;
1797 : : }
1798 [ + + + + ]: 1335 : else if (is1("startpos"))
1799 : : {
1800 [ - + - - ]: 3 : if(!in_spcblock) asar_throw_error(0, error_type_block, error_id_startpos_without_spcblock);
1801 : 3 : spcblock.execute_address=getnum64(par);
1802 : : }
1803 [ + + + + ]: 1332 : else if (is1("base"))
1804 : : {
1805 [ + + ]: 42 : if (!stricmp(par, "off"))
1806 : : {
1807 : 15 : snespos=realsnespos;
1808 : 15 : startpos=realstartpos;
1809 : 15 : return;
1810 : : }
1811 : 27 : unsigned int num=getnum(par);
1812 [ - + - - ]: 27 : if (forwardlabel) asar_throw_error(0, error_type_block, error_id_base_label_invalid);
1813 [ - + - - ]: 27 : if (num&~0xFFFFFF) asar_throw_error(1, error_type_block, error_id_snes_address_out_of_bounds, hex6((unsigned int)num).data());
1814 : 27 : snespos=(int)num;
1815 : 27 : startpos=(int)num;
1816 : 27 : optimizeforbank=-1;
1817 : : }
1818 [ + + + + ]: 1290 : else if (is1("dpbase"))
1819 : : {
1820 : 6 : unsigned int num=(int)getnum(par);
1821 [ - + - - ]: 6 : if (forwardlabel) asar_throw_error(0, error_type_block, error_id_base_label_invalid);
1822 [ - + - - ]: 6 : if (num&~0xFF00) asar_throw_error(1, error_type_block, error_id_bad_dp_base, hex6((unsigned int)num).data());
1823 : 6 : dp_base = (int)num;
1824 : : }
1825 [ + + + + ]: 1284 : else if (is2("optimize"))
1826 : : {
1827 [ + + ]: 15 : if (!stricmp(par, "dp"))
1828 : : {
1829 [ + + ]: 9 : if (!stricmp(word[2], "none"))
1830 : : {
1831 : 3 : optimize_dp = optimize_dp_flag::NONE;
1832 : 3 : return;
1833 : : }
1834 [ + + ]: 6 : if (!stricmp(word[2], "ram"))
1835 : : {
1836 : 3 : optimize_dp = optimize_dp_flag::RAM;
1837 : 3 : return;
1838 : : }
1839 [ + - ]: 3 : if (!stricmp(word[2], "always"))
1840 : : {
1841 : 3 : optimize_dp = optimize_dp_flag::ALWAYS;
1842 : 3 : return;
1843 : : }
1844 : 0 : asar_throw_error(1, error_type_block, error_id_bad_dp_optimize, word[2]);
1845 : : }
1846 [ + - ]: 6 : if (!stricmp(par, "address"))
1847 : : {
1848 [ - + ]: 6 : if (!stricmp(word[2], "default"))
1849 : : {
1850 : 0 : optimize_address = optimize_address_flag::DEFAULT;
1851 : 0 : return;
1852 : : }
1853 [ + + ]: 6 : if (!stricmp(word[2], "ram"))
1854 : : {
1855 : 3 : optimize_address = optimize_address_flag::RAM;
1856 : 3 : return;
1857 : : }
1858 [ + - ]: 3 : if (!stricmp(word[2], "mirrors"))
1859 : : {
1860 : 3 : optimize_address = optimize_address_flag::MIRRORS;
1861 : 3 : return;
1862 : : }
1863 : 0 : asar_throw_error(1, error_type_block, error_id_bad_address_optimize, word[2]);
1864 : : }
1865 : 0 : asar_throw_error(1, error_type_block, error_id_bad_optimize, par);
1866 : : }
1867 [ + + + - ]: 1269 : else if (is1("bank"))
1868 : : {
1869 [ # # ]: 0 : if (!stricmp(par, "auto"))
1870 : : {
1871 : 0 : optimizeforbank=-1;
1872 : 0 : return;
1873 : : }
1874 [ # # ]: 0 : if (!stricmp(par, "noassume"))
1875 : : {
1876 : 0 : optimizeforbank=0x100;
1877 : 0 : return;
1878 : : }
1879 : 0 : unsigned int num=getnum(par);
1880 : : //if (forwardlabel) error(0, "bank Label is not valid");
1881 : : //if (foundlabel) num>>=16;
1882 [ # # # # ]: 0 : if (num&~0x0000FF) asar_throw_error(1, error_type_block, error_id_snes_address_out_of_bounds, hex6((unsigned int)num).data());
1883 : 0 : optimizeforbank=(int)num;
1884 : : }
1885 [ + - + + : 1269 : else if (is("freespace") || is("freecode") || is("freedata"))
+ + ]
1886 : : {
1887 [ - + - - ]: 438 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_feature_unavaliable_in_spcblock);
1888 [ - + - - ]: 438 : if (emulatexkas) asar_throw_warning(0, warning_id_convert_to_asar);
1889 : 438 : string parstr;
1890 [ + + ]: 438 : if (numwords==1) parstr="\n";//crappy hack: impossible character to cut out extra commas
1891 [ + - ]: 390 : else if (numwords==2) parstr=word[1];
1892 : 0 : else asar_throw_error(0, error_type_block, error_id_invalid_freespace_request);
1893 [ + + ]: 837 : if (is("freecode")) parstr=STR"ram,"+parstr;
1894 [ + + ]: 477 : if (is("freedata")) parstr=STR"noram,"+parstr;
1895 [ + - ]: 438 : autoptr<char**> pars=split(parstr.temp_raw(), ",");
1896 : : unsigned char fsbyte = 0x00;
1897 : : int useram=-1;
1898 : : bool fixedpos=false;
1899 : : bool align=false;
1900 : : bool leakwarn=true;
1901 [ + + ]: 1314 : for (int i=0;pars[i];i++)
1902 : : {
1903 [ + + ]: 876 : if (pars[i][0]=='\n') {}
1904 [ + + ]: 828 : else if (!stricmp(pars[i], "ram"))
1905 : : {
1906 [ - + - - ]: 399 : if (useram!=-1) asar_throw_error(0, error_type_block, error_id_invalid_freespace_request);
1907 : : useram=1;
1908 : : }
1909 [ + + ]: 429 : else if (!stricmp(pars[i], "noram"))
1910 : : {
1911 [ - + - - ]: 39 : if (useram!=-1) asar_throw_error(0, error_type_block, error_id_invalid_freespace_request);
1912 : : useram=0;
1913 : : }
1914 [ + - + - ]: 390 : else if (!stricmp(pars[i], "static") || !stricmp(pars[i], "fixed"))
1915 : : {
1916 [ # # # # ]: 0 : if (!stricmp(pars[i], "fixed")) asar_throw_warning(0, warning_id_feature_deprecated, "freespace/code/data fixed", "freespace/code/data static");
1917 [ # # # # ]: 0 : if (fixedpos) asar_throw_error(0, error_type_block, error_id_invalid_freespace_request);
1918 : : fixedpos=true;
1919 : : }
1920 [ + + ]: 390 : else if (!stricmp(pars[i], "align"))
1921 : : {
1922 [ - + - - ]: 3 : if (align) asar_throw_error(0, error_type_block, error_id_invalid_freespace_request);
1923 : : align=true;
1924 : : }
1925 [ + - ]: 387 : else if (!stricmp(pars[i], "cleaned"))
1926 : : {
1927 [ - + - - ]: 387 : if (!leakwarn) asar_throw_error(0, error_type_block, error_id_invalid_freespace_request);
1928 : : leakwarn=false;
1929 : : }
1930 : : else
1931 : : {
1932 : 0 : fsbyte = (unsigned char)getnum(pars[i]);
1933 : : }
1934 : : }
1935 [ - + - - ]: 438 : if (useram==-1) asar_throw_error(0, error_type_block, error_id_invalid_freespace_request);
1936 [ - + - - ]: 438 : if (mapper == norom) asar_throw_error(0, error_type_block, error_id_no_freespace_norom);
1937 : 438 : freespaceend();
1938 : 438 : freespaceid=getfreespaceid();
1939 : 438 : freespacebyte[freespaceid] = fsbyte;
1940 [ + + ]: 438 : if (pass==0) snespos=(freespaceid<<24)|0x8000;
1941 [ + + ]: 438 : if (pass==1)
1942 : : {
1943 [ - + - - ]: 146 : if (fixedpos && freespaceorgpos[freespaceid]<0)
1944 : : {
1945 : 0 : freespacepos[freespaceid]=0x008000;
1946 : 0 : freespaceleak[freespaceid]=false;//mute some other errors
1947 : 0 : asar_throw_error(1, error_type_block, error_id_static_freespace_autoclean);
1948 : : }
1949 [ # # ]: 0 : if (fixedpos && freespaceorgpos[freespaceid]) freespacepos[freespaceid]=snespos=(freespaceid<<24)|freespaceorgpos[freespaceid];
1950 [ + - ]: 146 : else freespacepos[freespaceid]=snespos=(freespaceid<<24)|getsnesfreespace(freespacelen[freespaceid], (useram != 0), true, true, align, freespacebyte[freespaceid]);
1951 : : }
1952 [ + + ]: 438 : if (pass==2)
1953 : : {
1954 [ - + - - ]: 146 : if (fixedpos && freespaceorgpos[freespaceid]==-1) return;//to kill some errors
1955 : 146 : snespos=(freespaceid<<24)|freespacepos[freespaceid];
1956 : 146 : resizerats(snespos&0xFFFFFF, freespacelen[freespaceid]);
1957 [ + + - + : 146 : if (freespaceleak[freespaceid] && leakwarn) asar_throw_warning(2, warning_id_freespace_leaked);
- - ]
1958 [ - + - - : 146 : if (fixedpos && freespaceorgpos[freespaceid]>0 && freespacelen[freespaceid]>freespaceorglen[freespaceid])
- - ]
1959 : 0 : asar_throw_error(2, error_type_block, error_id_static_freespace_growing);
1960 : 146 : freespaceuse+=8+freespacelen[freespaceid];
1961 : :
1962 : : // add a mapping for the start of the rats tag
1963 : 146 : add_addr_to_line(snespos-8);
1964 : : }
1965 : 438 : freespacestatic[freespaceid]=fixedpos;
1966 [ - + - - : 438 : if (snespos < 0 && mapper == sa1rom) asar_throw_error(pass, error_type_fatal, error_id_no_freespace_in_mapped_banks, dec(freespacelen[freespaceid]).data());
- - ]
1967 [ - + - - ]: 438 : if (snespos < 0) asar_throw_error(pass, error_type_fatal, error_id_no_freespace, dec(freespacelen[freespaceid]).data());
1968 : 438 : bytes+=8;
1969 : 438 : freespacestart=snespos;
1970 : 438 : startpos=snespos;
1971 : 438 : realstartpos=snespos;
1972 : 438 : realsnespos=snespos;
1973 : 438 : optimizeforbank=-1;
1974 : 438 : ratsmetastate=ratsmeta_allow;
1975 : 438 : }
1976 [ + + + + ]: 831 : else if (is1("prot"))
1977 : : {
1978 [ - + - - ]: 27 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_feature_unavaliable_in_spcblock);
1979 [ + - - + : 27 : if (!confirmqpar(par)) asar_throw_error(0, error_type_block, error_id_mismatched_parentheses);
- - ]
1980 [ - + - - ]: 27 : if (!ratsmetastate) asar_throw_error(2, error_type_block, error_id_prot_not_at_freespace_start);
1981 [ + + ]: 27 : if (ratsmetastate==ratsmeta_used) step(-5);
1982 : : int num;
1983 [ + - ]: 27 : autoptr<char**> pars=qpsplit(par, ",", &num);
1984 : : write1('P');
1985 : : write1('R');
1986 : : write1('O');
1987 : : write1('T');
1988 [ - + - - ]: 27 : if (num * 3 > 255) asar_throw_error(0, error_type_block, error_id_prot_too_many_entries);
1989 : 27 : write1((unsigned int)(num*3));
1990 [ + + ]: 60 : for (int i=0;i<num;i++)
1991 : : {
1992 : : //int num=getnum(pars[i]);
1993 : 33 : const char * labeltest=pars[i];
1994 : 33 : string testlabel = labeltest;
1995 : 33 : int labelnum=(int)labelval(&labeltest).pos;
1996 [ - + - - ]: 33 : if (*labeltest) asar_throw_error(0, error_type_block, error_id_label_not_found, testlabel.data());
1997 : 33 : write3((unsigned int)labelnum);
1998 [ + + ]: 33 : if (pass==1) freespaceleak[labelnum >>24]=false;
1999 : 33 : }
2000 : : write1('S');
2001 : : write1('T');
2002 : : write1('O');
2003 : : write1('P');
2004 : : write1(0);
2005 : 27 : ratsmetastate=ratsmeta_used;
2006 : :
2007 : 27 : add_addr_to_line(addrToLinePos);
2008 : 27 : }
2009 [ + + + - : 804 : else if (is1("autoclean") || is2("autoclean") || is1("autoclear") || is2("autoclear"))
+ + + + +
+ + - + +
- + ]
2010 : : {
2011 [ - + - - ]: 27 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_feature_unavaliable_in_spcblock);
2012 [ - + - - : 27 : if (is1("autoclear") || is2("autoclear")) asar_throw_warning(0, warning_id_autoclear_deprecated);
+ - - + -
- ]
2013 [ + - ]: 27 : if (numwords==3)
2014 : : {
2015 [ - + - - ]: 27 : if ((unsigned int)snespos & 0xFF000000) asar_throw_error(0, error_type_block, error_id_autoclean_in_freespace);
2016 : 27 : const char * labeltest = word[2];
2017 : 27 : string testlabel = labeltest;
2018 : 27 : int num=(int)labelval(&labeltest).pos;
2019 [ - + - - ]: 27 : if (*labeltest) asar_throw_error(0, error_type_block, error_id_label_not_found, testlabel.data());
2020 : : unsigned char targetid=(unsigned char)(num>>24);
2021 [ + + ]: 27 : if (pass==1) freespaceleak[targetid]=false;
2022 : 27 : num&=0xFFFFFF;
2023 [ - + - - ]: 27 : if (strlen(par)>3 && !stricmp(par+3, ".l")) par[3]=0;
2024 [ + + + - ]: 27 : if (!stricmp(par, "JSL") || !stricmp(par, "JML"))
2025 : : {
2026 : 27 : int orgpos=read3(snespos+1);
2027 : 27 : int ratsloc=freespaceorgpos[targetid];
2028 [ + + ]: 27 : int firstbyte = ((!stricmp(par, "JSL")) ? 0x22 : 0x5C);
2029 : : int pcpos=snestopc(snespos);
2030 [ + - + - : 27 : if (/*pass==1 && */pcpos>=0 && pcpos<romlen_r && romdata_r[pcpos]==firstbyte)
+ + ]
2031 : : {
2032 : 9 : ratsloc=ratsstart(orgpos)+8;
2033 : 9 : freespaceorglen[targetid]=read2(ratsloc-4)+1;
2034 [ + - + + : 9 : if (!freespacestatic[targetid] && pass==1) removerats(orgpos, freespacebyte[targetid]);
+ - ]
2035 : : }
2036 : 18 : else if (ratsloc<0) ratsloc=0;
2037 : 27 : write1((unsigned int)firstbyte);
2038 : 27 : write3((unsigned int)num);
2039 [ + + ]: 27 : if (pass==2)
2040 : : {
2041 : 9 : int start=ratsstart(num);
2042 [ - + ]: 9 : if (start>=num || start<0)
2043 : : {
2044 : 0 : asar_throw_error(2, error_type_block, error_id_autoclean_label_at_freespace_end);
2045 : : }
2046 : :
2047 : 9 : add_addr_to_line(addrToLinePos);
2048 : : }
2049 : : //freespaceorglen[targetid]=read2(ratsloc-4)+1;
2050 : 27 : freespaceorgpos[targetid]=ratsloc;
2051 : 27 : }
2052 [ # # ]: 0 : else if (!stricmp(par, "dl"))
2053 : : {
2054 : 0 : int orgpos=read3(snespos);
2055 : 0 : int ratsloc=freespaceorgpos[targetid];
2056 : 0 : int start=ratsstart(num);
2057 [ # # ]: 0 : if (pass==1 && num>=0)
2058 : : {
2059 : 0 : ratsloc=ratsstart(orgpos)+8;
2060 [ # # # # ]: 0 : if (!freespacestatic[targetid]) removerats(orgpos, freespacebyte[targetid]);
2061 : : }
2062 : : else if (!ratsloc) ratsloc=0;
2063 [ # # # # ]: 0 : if ((start==num || start<0) && pass==2)
2064 : 0 : asar_throw_error(2, error_type_block, error_id_autoclean_label_at_freespace_end);
2065 : 0 : write3((unsigned int)num);
2066 : 0 : freespaceorgpos[targetid]=ratsloc;
2067 : 0 : freespaceorglen[targetid]=read2(ratsloc-4)+1;
2068 : :
2069 : 0 : add_addr_to_line(addrToLinePos);
2070 : : }
2071 : 0 : else asar_throw_error(0, error_type_block, error_id_broken_autoclean);
2072 : 27 : }
2073 [ # # # # : 0 : else if (pass==0) removerats((int)getnum(word[1]), 0x00);
# # ]
2074 : : }
2075 [ + + + + ]: 777 : else if (is0("pushpc"))
2076 : : {
2077 [ - + - - ]: 3 : if (emulatexkas) asar_throw_warning(0, warning_id_convert_to_asar);
2078 : 3 : pushpc[pushpcnum].arch=arch;
2079 : 3 : pushpc[pushpcnum].snespos=snespos;
2080 : 3 : pushpc[pushpcnum].snesstart=startpos;
2081 : 3 : pushpc[pushpcnum].snesposreal=realsnespos;
2082 : 3 : pushpc[pushpcnum].snesstartreal=realstartpos;
2083 : 3 : pushpc[pushpcnum].freeid=freespaceid;
2084 : 3 : pushpc[pushpcnum].freeex=freespaceextra;
2085 : 3 : pushpc[pushpcnum].freest=freespacestart;
2086 : 3 : pushpcnum++;
2087 : 3 : snespos=(int)0xFFFFFFFF;
2088 : 3 : startpos= (int)0xFFFFFFFF;
2089 : 3 : realsnespos= (int)0xFFFFFFFF;
2090 : 3 : realstartpos= (int)0xFFFFFFFF;
2091 : : }
2092 [ + + + + ]: 774 : else if (is0("pullpc"))
2093 : : {
2094 [ - + - - ]: 3 : if (!pushpcnum) asar_throw_error(0, error_type_block, error_id_pullpc_without_pushpc);
2095 : 3 : pushpcnum--;
2096 : 3 : freespaceend();
2097 [ - + - - ]: 3 : if (arch != pushpc[pushpcnum].arch) asar_throw_error(0, error_type_block, error_id_pullpc_different_arch);
2098 : 3 : snespos=pushpc[pushpcnum].snespos;
2099 : 3 : startpos=pushpc[pushpcnum].snesstart;
2100 : 3 : realsnespos=pushpc[pushpcnum].snesposreal;
2101 : 3 : realstartpos=pushpc[pushpcnum].snesstartreal;
2102 : 3 : freespaceid=pushpc[pushpcnum].freeid;
2103 : 3 : freespaceextra=pushpc[pushpcnum].freeex;
2104 : 3 : freespacestart=pushpc[pushpcnum].freest;
2105 : : }
2106 [ + + + + ]: 771 : else if (is0("pushbase"))
2107 : : {
2108 [ - + - - ]: 3 : if (emulatexkas) asar_throw_warning(0, warning_id_convert_to_asar);
2109 : 3 : basestack[basestacknum] = snespos;
2110 : 3 : basestacknum++;
2111 : : }
2112 [ + + + + ]: 768 : else if (is0("pullbase"))
2113 : : {
2114 [ - + - - ]: 3 : if (!basestacknum) asar_throw_error(0, error_type_block, error_id_pullbase_without_pushbase);
2115 : 3 : basestacknum--;
2116 : 3 : snespos = basestack[basestacknum];
2117 : 3 : startpos = basestack[basestacknum];
2118 : :
2119 [ + - ]: 3 : if (snespos != realstartpos)
2120 : : {
2121 : 3 : optimizeforbank = -1;
2122 : : }
2123 : : }
2124 [ + + + + ]: 765 : else if (is0("pushns"))
2125 : : {
2126 [ - + - - ]: 6 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_feature_unavaliable_in_spcblock);
2127 : 6 : pushns[pushnsnum].ns = ns;
2128 [ + + ]: 12 : for(int i = 0; i < namespace_list.count; i++)
2129 : : {
2130 : 6 : pushns[pushnsnum].namespace_list.append(namespace_list[i]);
2131 : : }
2132 : 6 : pushns[pushnsnum].nested_namespaces = nested_namespaces;
2133 : 6 : pushnsnum++;
2134 : :
2135 : 6 : namespace_list.reset();
2136 : : ns = "";
2137 : 6 : nested_namespaces = false;
2138 : : }
2139 [ + + + + ]: 759 : else if (is0("pullns"))
2140 : : {
2141 [ - + - - ]: 6 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_feature_unavaliable_in_spcblock);
2142 [ - + - - ]: 6 : if (!pushnsnum) asar_throw_error(0, error_type_block, error_id_pullns_without_pushns);
2143 : 6 : pushnsnum--;
2144 : 6 : ns = pushns[pushnsnum].ns;
2145 : 6 : nested_namespaces = pushns[pushnsnum].nested_namespaces;
2146 : 6 : namespace_list.reset();
2147 [ + + ]: 18 : for(int i = 0; i < pushns[pushnsnum].namespace_list.count; i++)
2148 : : {
2149 : 12 : namespace_list.append(pushns[pushnsnum].namespace_list[i]);
2150 : : }
2151 : : }
2152 [ + + + + : 753 : else if (is1("namespace") || is2("namespace"))
+ + + - ]
2153 : : {
2154 [ - + - - ]: 81 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_feature_unavaliable_in_spcblock);
2155 : : bool leave = false;
2156 [ + - ]: 81 : if (par)
2157 : : {
2158 [ + + ]: 81 : if (!stricmp(par, "off"))
2159 : : {
2160 [ - + - - ]: 24 : if (word[2]) asar_throw_error(0, error_type_block, error_id_invalid_namespace_use);
2161 : : leave = true;
2162 : : }
2163 [ + + ]: 57 : else if (!stricmp(par, "nested"))
2164 : : {
2165 [ - + - - ]: 18 : if (!word[2]) asar_throw_error(0, error_type_block, error_id_invalid_namespace_use);
2166 [ + + ]: 18 : else if (!stricmp(word[2], "on")) nested_namespaces = true;
2167 [ + - ]: 9 : else if (!stricmp(word[2], "off")) nested_namespaces = false;
2168 : : }
2169 : : else
2170 : : {
2171 [ - + - - ]: 39 : if (word[2]) asar_throw_error(0, error_type_block, error_id_invalid_namespace_use);
2172 : 39 : const char * tmpstr= safedequote(par);
2173 [ - + - - ]: 39 : if (!confirmname(tmpstr)) asar_throw_error(0, error_type_block, error_id_invalid_namespace_name);
2174 [ + + ]: 39 : if (!nested_namespaces)
2175 : : {
2176 : 15 : namespace_list.reset();
2177 : : }
2178 : 39 : namespace_list.append(STR tmpstr);
2179 : : }
2180 : : }
2181 : : else
2182 : : {
2183 : : leave = true;
2184 : : }
2185 : :
2186 : : if (leave)
2187 : : {
2188 [ + + ]: 24 : if (nested_namespaces)
2189 : : {
2190 : 18 : namespace_list.remove(namespace_list.count - 1);
2191 : : }
2192 : : else
2193 : : {
2194 : 6 : namespace_list.reset();
2195 : : }
2196 : : }
2197 : :
2198 : : // recompute ns
2199 : : ns = "";
2200 [ + + ]: 177 : for (int i = 0; i < namespace_list.count; i++)
2201 : : {
2202 : 96 : ns += namespace_list[i];
2203 : 96 : ns += STR"_";
2204 : : }
2205 : : }
2206 [ + + + + ]: 672 : else if (is1("warnpc"))
2207 : : {
2208 : 3 : unsigned int maxpos=getnum(par);
2209 [ - + - - ]: 3 : if ((unsigned int)snespos & 0xFF000000) asar_throw_error(0, error_type_block, error_id_warnpc_in_freespace);
2210 [ - + - - ]: 3 : if ((unsigned int)maxpos & 0xFF000000) asar_throw_error(0, error_type_block, error_id_warnpc_broken_param);
2211 [ - + - - ]: 3 : if ((unsigned int)snespos > maxpos) asar_throw_error(0, error_type_block, error_id_warnpc_failed, hex6((unsigned int)snespos).data(), hex6((unsigned int)maxpos).data());
2212 [ - + - - : 3 : if (warnxkas && (unsigned int)snespos == maxpos) asar_throw_warning(0, warning_id_xkas_warnpc_relaxed);
- - ]
2213 [ - + - - : 3 : if (emulatexkas && (unsigned int)snespos==maxpos) asar_throw_error(0, error_type_block, error_id_warnpc_failed_equal, hex6((unsigned int)snespos).data(), hex6((unsigned int)maxpos).data());
- - ]
2214 : : }
2215 [ + + + + ]: 669 : else if (is1("rep"))
2216 : : {
2217 : 15 : int rep = (int)getnum64(par);
2218 [ - + - - ]: 12 : if (foundlabel) asar_throw_error(0, error_type_block, error_id_rep_label);
2219 [ + + ]: 12 : if (rep<=1)
2220 : : {
2221 [ + + ]: 9 : if(rep < 0){
2222 : 3 : asar_throw_warning(0, warning_id_feature_deprecated, "rep condition < 0", "You probably want conditionals");
2223 : : }
2224 [ + - ]: 9 : if (emulatexkas)
2225 : : {
2226 : 9 : asar_throw_warning(0, warning_id_feature_deprecated, "rep <= 1 xkas behaviour", "You probably want conditionals");
2227 [ + + ]: 9 : if (rep==0) rep=1;
2228 [ + + ]: 6 : if (rep<0) rep=0;
2229 : 9 : repeatnext=rep;
2230 : 9 : return;
2231 : : }
2232 : : }
2233 : 3 : asar_throw_warning(0, warning_id_feature_deprecated, "rep X : {command}", "Use while loops, unrolled loops, pseudo opcodes or for loops");
2234 : 3 : repeatnext=rep;
2235 : : }
2236 : : #ifdef SANDBOX
2237 : : else if (is("incsrc") || is("incbin") || is("table"))
2238 : : {
2239 : : asar_throw_error(0, error_type_block, error_id_command_disabled);
2240 : : }
2241 : : #endif
2242 [ + + + + ]: 654 : else if (is1("incsrc"))
2243 : : {
2244 : 309 : string name;
2245 [ - + - - : 309 : if (warnxkas && (strchr(thisfilename, '/') || strchr(thisfilename, '\\')))
- - ]
2246 : 0 : asar_throw_warning(0, warning_id_xkas_incsrc_relative);
2247 [ - + ]: 309 : if (strchr(par, '\\'))
2248 : : {
2249 [ # # ]: 0 : if (emulatexkas)
2250 : : {
2251 : 0 : asar_throw_warning(0, warning_id_feature_deprecated, "xkas style paths", "convert paths to crossplatform style");
2252 [ # # ]: 0 : for (int i=0;par[i];i++)
2253 : : {
2254 [ # # ]: 0 : if (par[i]=='\\') par[i]='/';//let's just hope nobody finds I could just enable this for everything.
2255 : : }
2256 : : }
2257 : : #ifdef _WIN32
2258 : : else asar_throw_warning(0, warning_id_feature_deprecated, "windows specific paths", "convert paths to crossplatform style");
2259 : : #endif
2260 : : }
2261 [ - + - - ]: 309 : if (emulatexkas) name= safedequote(par);
2262 : 309 : else name=STR safedequote(par);
2263 : 309 : assemblefile(name, false);
2264 : 309 : }
2265 [ + + + + : 345 : else if (is1("incbin") || is3("incbin"))
+ + + + ]
2266 : : {
2267 [ + + - + : 36 : if (numwords == 4 && strcmp(word[2], "->")) asar_throw_error(0, error_type_block, error_id_broken_incbin);
- - ]
2268 : : int len;
2269 : : int start=0;
2270 : : int end=0;
2271 [ + + ]: 36 : if (strqchr(par, ':'))
2272 : : {
2273 : 21 : char * lengths=strqchr(par, ':');
2274 : 21 : *lengths=0;
2275 : 21 : lengths++;
2276 [ + - + + ]: 21 : if(strqpstr(lengths, ".."))
2277 : : {
2278 : : // new style ranges
2279 : 18 : char* split = strqpstr(lengths, "..");
2280 : 18 : string start_str(lengths, split-lengths);
2281 : 18 : start = getnum(start_str);
2282 [ + + + + : 18 : if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_no_labels_here);
- + ]
2283 : 15 : string end_str(split+2);
2284 : 15 : end = getnum(end_str);
2285 [ + + + + : 15 : if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_no_labels_here);
- + ]
2286 : 21 : }
2287 : : else
2288 : : {
2289 : 3 : asar_throw_warning(0, warning_id_feature_deprecated, "old style incbin ranges", "use the :start..end syntax instead");
2290 [ - + - - ]: 3 : if (strchr(lengths, '"')) asar_throw_error(0, error_type_block, error_id_broken_incbin);
2291 [ + - ]: 3 : if(*lengths=='(') {
2292 : 3 : char* tmp = strqpchr(lengths, '-');
2293 [ + - - + : 3 : if(!tmp || (*(tmp-1)!=')')) asar_throw_error(0, error_type_block, error_id_broken_incbin);
- - ]
2294 : 3 : start = (int)getnum64(string(lengths+1, tmp-1-lengths-1));
2295 [ # # # # : 0 : if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_no_labels_here);
# # ]
2296 : 0 : lengths = tmp;
2297 : : } else {
2298 : 0 : start=(int)strtoul(lengths, &lengths, 16);
2299 : : }
2300 [ # # # # ]: 0 : if (*lengths!='-') asar_throw_error(0, error_type_block, error_id_broken_incbin);
2301 : 0 : lengths++;
2302 [ # # ]: 0 : if(*lengths=='(') {
2303 : : char* tmp = strchr(lengths, '\0');
2304 [ # # # # ]: 0 : if(*(tmp-1)!=')') asar_throw_error(0, error_type_block, error_id_broken_incbin);
2305 : 0 : end = (int)getnum64(string(lengths+1, tmp-1-lengths-1));
2306 [ # # # # : 0 : if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_no_labels_here);
# # ]
2307 : : // no need to check end-of-string here
2308 : : } else {
2309 : 0 : end=(int)strtoul(lengths, &lengths, 16);
2310 [ # # # # ]: 0 : if (*lengths) asar_throw_error(0, error_type_block, error_id_broken_incbin);
2311 : : }
2312 : : }
2313 : : }
2314 : 27 : string name;
2315 [ - + - - : 27 : if (warnxkas && (strchr(thisfilename, '/') || strchr(thisfilename, '\\')))
- - ]
2316 : 0 : asar_throw_warning(0, warning_id_xkas_incsrc_relative);
2317 [ + + ]: 27 : if (strchr(par, '\\'))
2318 : : {
2319 [ + - ]: 3 : if (emulatexkas)
2320 : : {
2321 : 3 : asar_throw_warning(0, warning_id_feature_deprecated, "xkas style paths", "convert paths to crossplatform style");
2322 [ + + ]: 60 : for (int i=0;par[i];i++)
2323 : : {
2324 [ + + ]: 57 : if (par[i]=='\\') par[i]='/';//let's just hope nobody finds I could just enable this for everything.
2325 : : }
2326 : : }
2327 : : #ifdef _WIN32
2328 : : else asar_throw_warning(0, warning_id_feature_deprecated, "windows specific paths", "convert paths to crossplatform style");
2329 : : #endif
2330 : : }
2331 [ + + + - ]: 27 : if (emulatexkas) name= safedequote(par);
2332 : 24 : else name=STR safedequote(par);
2333 : : char * data;//I couldn't find a way to get this into an autoptr
2334 [ + - + + : 27 : if (!readfile(name, thisfilename, &data, &len)) asar_throw_error(0, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), name.data());
+ - + - -
+ ]
2335 : 24 : autoptr<char*> datacopy=data;
2336 [ + + ]: 24 : if (!end) end=len;
2337 [ - + - - ]: 24 : if(start < 0) asar_throw_error(0, error_type_block, error_id_file_offset_out_of_bounds, dec(start).data(), name.data());
2338 [ + - + - : 24 : if (end < start || end > len || end < 0) asar_throw_error(0, error_type_block, error_id_file_offset_out_of_bounds, dec(end).data(), name.data());
- + - - ]
2339 [ + + ]: 24 : if (numwords==4)
2340 : : {
2341 : 3 : asar_throw_warning(0, warning_id_feature_deprecated, "incbin with target location", "put an org before the incbin");
2342 [ - + ]: 3 : if (!confirmname(word[3]))
2343 : : {
2344 : 0 : int pos=(int)getnum(word[3]);
2345 [ # # # # : 0 : if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_no_labels_here);
# # ]
2346 : : int offset=snestopc(pos);
2347 [ # # # # ]: 0 : if (offset + end - start > 0xFFFFFF) asar_throw_error(0, error_type_block, error_id_16mb_rom_limit);
2348 [ # # ]: 0 : if (offset+end-start>romlen) romlen=offset+end-start;
2349 [ # # ]: 0 : if (pass==2)
2350 : : {
2351 : 0 : writeromdata(offset, data+start, end-start);
2352 : 0 : add_addr_to_line(pos);
2353 : : }
2354 : : }
2355 : : else
2356 : : {
2357 : : int pos;
2358 [ + + ]: 3 : if (pass==0)
2359 : : {
2360 [ - + - - ]: 1 : if (end - start > 65536) asar_throw_error(0, error_type_block, error_id_incbin_64kb_limit);
2361 : 1 : pos=getpcfreespace(end-start, false, true, false);
2362 [ - + - - ]: 1 : if (pos < 0) asar_throw_error(0, error_type_block, error_id_no_freespace, dec(end - start).data());
2363 : 1 : int foundfreespaceid=getfreespaceid();
2364 : 1 : freespacepos[foundfreespaceid]=pctosnes(pos)|(/*fastrom?0x800000:*/0x000000)|(foundfreespaceid <<24);
2365 : 1 : setlabel(word[3], freespacepos[foundfreespaceid]);
2366 : 1 : writeromdata_bytes(pos, 0xFF, end-start);
2367 : : }
2368 [ + + ]: 3 : if (pass==1)
2369 : : {
2370 : 1 : getfreespaceid();//nothing to do here, but we want to tick the counter
2371 : : }
2372 [ + + ]: 3 : if (pass==2)
2373 : : {
2374 : 1 : int foundfreespaceid =getfreespaceid();
2375 [ - + - - ]: 1 : if (freespaceleak[foundfreespaceid]) asar_throw_warning(2, warning_id_freespace_leaked);
2376 : 1 : writeromdata(snestopc(freespacepos[foundfreespaceid]&0xFFFFFF), data+start, end-start);
2377 : 1 : add_addr_to_line((freespacepos[foundfreespaceid]&0xFFFFFF) - 8);
2378 : 1 : freespaceuse+=8+end-start;
2379 : : }
2380 : : }
2381 : : }
2382 : : else
2383 : : {
2384 [ + - + + ]: 54 : for (int i=start;i<end;i++) write1((unsigned int)data[i]);
2385 : 21 : add_addr_to_line(addrToLinePos);
2386 : : }
2387 : 27 : }
2388 [ + + + + ]: 309 : else if (is("skip") || is("fill"))
2389 : : {
2390 [ - + - - : 108 : if(numwords != 2 && numwords != 3 && numwords != 5) asar_throw_error(0, error_type_block, error_id_unknown_command);
- - ]
2391 [ - + - - : 108 : if(numwords > 2 && stricmp(word[1], "align")) asar_throw_error(0, error_type_block, error_id_unknown_command);
- - ]
2392 [ - + - - : 108 : if(numwords == 5 && stricmp(word[3], "offset")) asar_throw_error(0, error_type_block, error_id_unknown_command);
- - ]
2393 : : int amount;
2394 [ - + ]: 108 : if(numwords > 2)
2395 : : {
2396 : 0 : int alignment = getnum64(word[2]);
2397 [ # # # # : 0 : if(foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_no_labels_here);
# # ]
2398 : : int offset = 0;
2399 [ # # ]: 0 : if(numwords==5)
2400 : : {
2401 : 0 : offset = getnum64(word[4]);
2402 [ # # # # : 0 : if(foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_no_labels_here);
# # ]
2403 : : }
2404 [ # # # # ]: 0 : if(alignment > 0x800000) asar_throw_error(0, error_type_block, error_id_alignment_too_big);
2405 [ # # # # ]: 0 : if(alignment < 1) asar_throw_error(0, error_type_block, error_id_alignment_too_small);
2406 [ # # # # ]: 0 : if(alignment & (alignment-1)) asar_throw_error(0, error_type_block, error_id_invalid_alignment);
2407 : : // i just guessed this formula but it seems to work
2408 : 0 : amount = (alignment - ((snespos - offset) & (alignment-1))) & (alignment-1);
2409 : : }
2410 : : else
2411 : : {
2412 : 108 : amount = (int)getnum64(par);
2413 [ + + + + : 108 : if (foundlabel && !foundlabel_static) asar_throw_error(0, error_type_block, error_id_no_labels_here);
- + ]
2414 : : }
2415 [ + + ]: 105 : if(is("skip")) step(amount);
2416 : : else
2417 : : {
2418 [ + - + + ]: 144 : for(int i=0; i < amount; i++) write1(fillbyte[i%12]);
2419 : 15 : add_addr_to_line(addrToLinePos);
2420 : : }
2421 : :
2422 : : }
2423 [ + + + - ]: 201 : else if (is0("cleartable"))
2424 : : {
2425 : 0 : cleartable();
2426 : : }
2427 [ + + + + ]: 201 : else if (is0("pushtable"))
2428 : : {
2429 : 3 : tablestack.append(table);
2430 : : }
2431 [ + + + + ]: 198 : else if (is0("pulltable"))
2432 : : {
2433 [ - + - - ]: 3 : if (tablestack.count <= 0) asar_throw_error(0, error_type_block, error_id_pulltable_without_table);
2434 : 3 : table=tablestack[tablestack.count-1];
2435 : 3 : tablestack.remove(tablestack.count-1);
2436 : : }
2437 [ + + + - ]: 195 : else if (is1("table"))
2438 : : {
2439 : 0 : asar_throw_warning(0, warning_id_feature_deprecated, "table command", "Use direct character assignments. For example: 'a' = $61");
2440 : : bool fliporder=false;
2441 : : if(0);
2442 [ # # # # ]: 0 : else if (striend(par, ",ltr")) { itrim(par, "", ",ltr"); }
2443 [ # # # # ]: 0 : else if (striend(par, ",rtl")) { itrim(par, "", ",rtl"); fliporder=true; }
2444 : 0 : string name=STR safedequote(par);
2445 : 0 : autoptr<char*> tablecontents=readfile(name, thisfilename);
2446 [ # # # # : 0 : if (!tablecontents) asar_throw_error(0, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), name.data());
# # # # ]
2447 [ # # ]: 0 : autoptr<char**> tablelines=split(tablecontents, "\n");
2448 [ # # ]: 0 : for (int i=0;i<256;i++) table.table[i]=(unsigned int)(((numopcodes+read2(0x00FFDE)+i)*0x26594131)|0x40028020);
2449 : : //garbage value so people will notice they're doing it wrong (for bonus points: figure out what 0x26594131 is)
2450 [ # # ]: 0 : for (int i=0;tablelines[i];i++)
2451 : : {
2452 : 0 : string tableline=tablelines[i];
2453 [ # # ]: 0 : if (!*tableline) continue;
2454 [ # # # # : 0 : if (strlen(tableline) < 4 || strlen(tableline) & 1 || strlen(tableline) > 10) asar_throw_error(0, error_type_block, error_id_invalid_table_file, i+1);
# # # # ]
2455 [ # # ]: 0 : if (!fliporder)
2456 : : {
2457 [ # # # # : 0 : if (tableline[3]=='x' || tableline[3]=='X') asar_throw_error(0, error_type_block, error_id_invalid_table_file, i+1);
# # ]
2458 : : char * end;
2459 : 0 : table.table[(unsigned char)tableline[0]]=(unsigned int)strtol(tableline.data()+2, &end, 16);
2460 [ # # # # ]: 0 : if (*end) asar_throw_error(0, error_type_block, error_id_invalid_table_file, i+1);
2461 : : }
2462 : : else
2463 : : {
2464 [ # # # # : 0 : if (tableline[1]=='x' || tableline[1]=='X') asar_throw_error(0, error_type_block, error_id_invalid_table_file, i+1);
# # ]
2465 : : char * eq;
2466 : 0 : unsigned int val=(unsigned int)strtol(tableline, &eq, 16);
2467 [ # # # # : 0 : if (eq[0]!='=' || eq[2]) asar_throw_error(0, error_type_block, error_id_invalid_table_file, i+1);
# # ]
2468 : 0 : table.table[(unsigned char)eq[1]]=val;
2469 : : }
2470 : 0 : }
2471 : 0 : }
2472 [ + + - + ]: 195 : else if (is3("function"))
2473 : : {
2474 : : //if (!pass)
2475 : : //{
2476 [ - + - - ]: 15 : if (stricmp(word[2], "=")) asar_throw_error(0, error_type_block, error_id_broken_function_declaration);
2477 [ + - - + : 15 : if (!confirmqpar(word[1])) asar_throw_error(0, error_type_block, error_id_broken_function_declaration);
- - ]
2478 : 15 : string line=word[1];
2479 : 15 : clean(line);
2480 : 15 : char * startpar=strqchr(line.data(), '(');
2481 [ - + - - ]: 15 : if (!startpar) asar_throw_error(0, error_type_block, error_id_broken_function_declaration);
2482 : 15 : *startpar=0;
2483 : 15 : startpar++;
2484 [ - + - - ]: 15 : if (!confirmname(line)) asar_throw_error(0, error_type_block, error_id_invalid_function_name);
2485 : 15 : char * endpar=strqchr(startpar, ')');
2486 : : //confirmqpar requires that all parentheses are matched, and a starting one exists, therefore it is harmless to not check for nulls
2487 [ - + - - ]: 15 : if (endpar[1]) asar_throw_error(0, error_type_block, error_id_broken_function_declaration);
2488 : 15 : *endpar=0;
2489 : 15 : createuserfunc(line, startpar, word[3]);
2490 : : //}
2491 : 15 : }
2492 [ + + + + ]: 180 : else if (is1("print"))
2493 : : {
2494 : 48 : string out = handle_print(par);
2495 [ + + ]: 48 : if (pass!=2) return;
2496 : 16 : print(out);
2497 : 48 : }
2498 [ + + + - ]: 132 : else if (is1("reset"))
2499 : : {
2500 : : if(0);
2501 [ # # ]: 0 : else if (!stricmp(par, "bytes")) bytes=0;
2502 [ # # ]: 0 : else if (!stricmp(par, "freespaceuse")) freespaceuse=0;
2503 : 0 : else asar_throw_error(2, error_type_block, error_id_unknown_variable);
2504 : : }
2505 [ + + + + : 132 : else if (is1("padbyte") || is1("padword") || is1("padlong") || is1("paddword"))
+ + + - +
+ + - + +
- + ]
2506 : : {
2507 : : int len = 0;
2508 [ + - ]: 9 : if (is("padbyte")) len=1;
2509 [ - + ]: 9 : if (is("padword")) len=2;
2510 [ - + ]: 9 : if (is("padlong")) len=3;
2511 [ - + ]: 9 : if (is("paddword")) len=4;
2512 : 9 : unsigned int val=getnum(par);
2513 [ + + + + : 9 : if(foundlabel && !foundlabel_static) asar_throw_warning(1, warning_id_feature_deprecated, "labels in padbyte", "just... don't.");
+ - ]
2514 [ + + ]: 117 : for (int i=0;i<12;i+=len)
2515 : : {
2516 : : unsigned int tmpval=val;
2517 [ + + ]: 216 : for (int j=0;j<len;j++)
2518 : : {
2519 : 108 : padbyte[i+j]=(unsigned char)tmpval;
2520 : 108 : tmpval>>=8;
2521 : : }
2522 : : }
2523 : : }
2524 [ + + + + ]: 123 : else if (is1("pad"))
2525 : : {
2526 [ - + - - ]: 9 : if ((unsigned int)realsnespos & 0xFF000000) asar_throw_error(0, error_type_block, error_id_pad_in_freespace);
2527 : 9 : int num=(int)getnum(par);
2528 [ - + - - ]: 9 : if ((unsigned int)num & 0xFF000000) asar_throw_error(0, error_type_block, error_id_snes_address_doesnt_map_to_rom, hex6((unsigned int)num).data());
2529 [ + + ]: 9 : if (num>realsnespos)
2530 : : {
2531 : : int end=snestopc(num);
2532 : : int start=snestopc(realsnespos);
2533 : 6 : int len=end-start;
2534 [ + - + + ]: 36 : for (int i=0;i<len;i++) write1(padbyte[i%12]);
2535 : 6 : add_addr_to_line(addrToLinePos);
2536 : : }
2537 : : }
2538 [ + + + + : 114 : else if (is1("fillbyte") || is1("fillword") || is1("filllong") || is1("filldword"))
+ + + + +
+ + + + +
+ + ]
2539 : : {
2540 : : int len = 0;
2541 [ + + ]: 18 : if (is("fillbyte")) len=1;
2542 [ + + ]: 18 : if (is("fillword")) len=2;
2543 [ + + ]: 18 : if (is("filllong")) len=3;
2544 [ + + ]: 18 : if (is("filldword")) len=4;
2545 : 18 : unsigned int val= getnum(par);
2546 [ + + + + : 18 : if(foundlabel && !foundlabel_static) asar_throw_warning(1, warning_id_feature_deprecated, "labels in fillbyte", "just... don't");
+ - ]
2547 [ + + ]: 165 : for (int i=0;i<12;i+=len)
2548 : : {
2549 : : unsigned int tmpval=val;
2550 [ + + ]: 363 : for (int j=0;j<len;j++)
2551 : : {
2552 : 216 : fillbyte[i+j]=(unsigned char)tmpval;
2553 : 216 : tmpval>>=8;
2554 : : }
2555 : : }
2556 : : }
2557 [ + + - + ]: 96 : else if (is1("arch"))
2558 : : {
2559 [ - + - - ]: 51 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_feature_unavaliable_in_spcblock);
2560 [ - + - - ]: 51 : if (emulatexkas) asar_throw_warning(0, warning_id_convert_to_asar);
2561 [ + + ]: 51 : if (!stricmp(par, "65816")) { arch=arch_65816; return; }
2562 [ + + ]: 39 : if (!stricmp(par, "spc700")) { arch=arch_spc700; return; }
2563 [ + + + - ]: 21 : if (!stricmp(par, "spc700-inline")) { asar_throw_warning(1, warning_id_feature_deprecated, "spc700-inline", " Use spcblock and endspcblock"); arch=arch_spc700_inline; return; }
2564 [ + + ]: 18 : if (!stricmp(par, "spc700-raw")) {
2565 : 6 : asar_throw_warning(1, warning_id_feature_deprecated, "spc700-raw", " Use arch spc700 with norom");
2566 : 6 : arch=arch_spc700;
2567 : 6 : mapper=norom;
2568 : 6 : mapper_set = false;
2569 [ + - ]: 6 : if(!force_checksum_fix)
2570 : 6 : checksum_fix_enabled = false;
2571 : 6 : return;
2572 : : }
2573 [ + - ]: 12 : if (!stricmp(par, "superfx")) { arch=arch_superfx; return; }
2574 : : }
2575 [ - + - - ]: 45 : else if (is2("math"))
2576 : : {
2577 : : bool val = false;
2578 : : if(0);
2579 [ # # ]: 0 : else if (!stricmp(word[2], "on")) val=true;
2580 [ # # ]: 0 : else if (!stricmp(word[2], "off")) val=false;
2581 : 0 : else asar_throw_error(0, error_type_block, error_id_invalid_math);
2582 : : if(0);
2583 [ # # # # ]: 0 : else if (!stricmp(word[1], "pri")){ math_pri=val; asar_throw_warning(2, warning_id_feature_deprecated, "math pri", "Rewrite your math statements using parentheses where needed and put \"asar 1.9\" in your patch to enable the future behavior of always enforcing math prioritization rules"); }
2584 [ # # # # ]: 0 : else if (!stricmp(word[1], "round")){ math_round=val; asar_throw_warning(2, warning_id_feature_deprecated, "math round", "Put \"asar 1.9\" in your patch to enable the future behavior of never rounding intermediate results. Call the round(), floor() or ceil() functions in places where intermediate rounding is required"); }
2585 : 0 : else asar_throw_error(0, error_type_block, error_id_invalid_math);
2586 : : }
2587 [ - + - - ]: 45 : else if (is2("warn"))
2588 : : {
2589 : : bool val = false;
2590 : : if(0);
2591 [ # # ]: 0 : else if (!stricmp(word[2], "on")) val=true;
2592 [ # # ]: 0 : else if (!stricmp(word[2], "off")) val=false;
2593 : 0 : else asar_throw_error(0, error_type_block, error_id_invalid_warn);
2594 : : if(0);
2595 [ # # ]: 0 : else if (!stricmp(word[1], "xkas")) {
2596 : 0 : asar_throw_warning(0, warning_id_feature_deprecated, "xkas compatibility warning", "If you worry about xkas I worry about you. Just stop.");
2597 : 0 : warnxkas=val;
2598 : : }
2599 : 0 : else asar_throw_error(0, error_type_block, error_id_invalid_warn);
2600 : : }
2601 [ + - + + ]: 45 : else if (is0("fastrom"))
2602 : : {
2603 : 3 : asar_throw_warning(0, warning_id_feature_deprecated, "fastrom", "This feature has been disabled for years and is a lie. Sorry.");
2604 : : //removed due to causing more trouble than it's worth.
2605 : : //if (emulatexkas) warn0("Convert the patch to native Asar format instead of making an Asar-only xkas patch.");
2606 : : //if (mapper==lorom || mapper==hirom) fastrom=true;
2607 : : //else error(0, "Can't use fastrom in this mapper.");
2608 : : }
2609 [ + - + + : 42 : else if (is0("{") || is0("}")) {}
+ - + + ]
2610 : : else
2611 : : {
2612 [ - + ]: 6 : if (isspecialline)
2613 : : {
2614 : 0 : asar_throw_warning(0, warning_id_unrecognized_special_command);
2615 : : }
2616 : : else
2617 : : {
2618 : 6 : asar_throw_error(1, error_type_block, error_id_unknown_command);
2619 : : }
2620 : : }
2621 : :
2622 : 437650 : }
2623 : :
2624 : 3665 : bool assemblemapper(char** word, int numwords)
2625 : : {
2626 : 3665 : auto previous_mapper = mapper;
2627 : : if(0);
2628 [ + + + + ]: 3665 : else if (is0("lorom"))
2629 : : {
2630 : : //this also makes xkas set snespos to $008000 for some reason
2631 : 36 : mapper=lorom;
2632 : : }
2633 [ + + + + ]: 3629 : else if (is0("hirom"))
2634 : : {
2635 : : //xkas makes this point to $C00000
2636 : 7 : mapper=hirom;
2637 : : }
2638 [ + + + + ]: 3622 : else if (is0("exlorom"))
2639 : : {
2640 : 3 : mapper = exlorom;
2641 : : }
2642 [ + + + + ]: 3619 : else if (is0("exhirom"))
2643 : : {
2644 : 3 : mapper=exhirom;
2645 : : }
2646 [ + + + + ]: 3616 : else if (is0("sfxrom"))
2647 : : {
2648 : 6 : mapper=sfxrom;
2649 : : //fastrom=false;
2650 : : }
2651 [ + + + + ]: 3610 : else if (is0("norom"))
2652 : : {
2653 : : //$000000 would be the best snespos for this, but I don't care
2654 : 9 : mapper=norom;
2655 : : //fastrom=false;
2656 [ + - ]: 9 : if(!force_checksum_fix)
2657 : 9 : checksum_fix_enabled = false;//we don't know where the header is, so don't set the checksum
2658 : : }
2659 [ + + + + ]: 3601 : else if (is0("fullsa1rom"))
2660 : : {
2661 : 3 : mapper=bigsa1rom;
2662 : : //fastrom=false;
2663 : : }
2664 [ + + ]: 3598 : else if (is("sa1rom"))
2665 : : {
2666 : : //fastrom=false;
2667 [ + + ]: 12 : if (par)
2668 : : {
2669 [ - + ]: 9 : if (word[2]) asar_throw_error(0, error_type_block, error_id_invalid_mapper);
2670 [ + - ]: 9 : if (!is_digit(par[0]) || par[1]!=',' ||
2671 [ + - + - ]: 9 : !is_digit(par[2]) || par[3]!=',' ||
2672 [ + - + - ]: 9 : !is_digit(par[4]) || par[5]!=',' ||
2673 [ + - + - : 18 : !is_digit(par[6]) || par[7]) asar_throw_error(0, error_type_block, error_id_invalid_mapper);
- + ]
2674 : : int len;
2675 : 9 : autoptr<char**> pars=qpsplit(par, ",", &len);
2676 [ - + - - ]: 9 : if (len!=4) asar_throw_error(0, error_type_block, error_id_invalid_mapper);
2677 : 9 : sa1banks[0]=(par[0]-'0')<<20;
2678 : 9 : sa1banks[1]=(par[2]-'0')<<20;
2679 : 9 : sa1banks[4]=(par[4]-'0')<<20;
2680 : 9 : sa1banks[5]=(par[6]-'0')<<20;
2681 : 9 : }
2682 : : else
2683 : : {
2684 : 3 : sa1banks[0]=0<<20;
2685 : 3 : sa1banks[1]=1<<20;
2686 : 3 : sa1banks[4]=2<<20;
2687 : 3 : sa1banks[5]=3<<20;
2688 : : }
2689 : 12 : mapper=sa1rom;
2690 : : }
2691 [ + + - + ]: 3586 : else if (is0("header"))
2692 : : {
2693 : : //headers are detected elsewhere; ignoring for familiarity
2694 : 0 : asar_throw_warning(0, warning_id_feature_deprecated, "header", "Remove command, unnecessary.");
2695 : : }
2696 : : else return false;
2697 : :
2698 [ - + ]: 79 : if(in_spcblock) asar_throw_error(0, error_type_block, error_id_feature_unavaliable_in_spcblock);
2699 [ + + ]: 79 : if(!mapper_set){
2700 : 46 : mapper_set = true;
2701 [ + + ]: 33 : }else if(previous_mapper != mapper){
2702 : 27 : asar_throw_warning(1, warning_id_mapper_already_set);
2703 : : }
2704 : : return true;
2705 : : }
|