LCOV - code coverage report
Current view: top level - asar - assembleblock.cpp (source / functions) Coverage Total Hit
Test: asar build #66 Lines: 90.4 % 1474 1332
Test Date: 2024-01-16 02:45:19 Functions: 97.6 % 41 40
Branches: 67.0 % 2454 1645

             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                 :             : }
        

Generated by: LCOV version 2.0-1