LCOV - code coverage report
Current view: top level - asar - assembleblock.cpp (source / functions) Coverage Total Hit
Test: asar.info Lines: 84.1 % 1464 1231
Test Date: 2024-01-15 16:23:49 Functions: 92.5 % 40 37
Branches: 56.1 % 2278 1278

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

Generated by: LCOV version 2.0-1