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