| 49 | | class Flags { |
| 50 | | /* flag: |
| 51 | | ** type 0-5 : ¥í¡Œ¥«¥ëÀ°¿ô¡¢³Æ2000žÄ |
| 52 | | ** type 6, 25 : ¥°¥í¡Œ¥Ð¥ëÀ°¿ô¡¢2000žÄ |
| 53 | | ** type 12 : ¥°¥í¡Œ¥Ð¥ëÊž»úÎó¡¢2000žÄ (º£€Ï̵»ë€·€Æ€âÎÉ€€€¬) |
| 54 | | ** type 18 : ¥í¡Œ¥«¥ëÊž»úÎó¡¢2000žÄ |
| 55 | | ** type 25: ¥·¥¹¥Æ¥àÊÑ¿ô¡Ê¥Þ¥Š¥¹ºÂÉž€Ê€É¡©¡Ë 1000 žÄ¡© |
| 56 | | ** type 26-32, 51 : 1-bit access to 0-6, 25 |
| 57 | | ** type 52-58, 77 : 2-bit access to 0-6, 25 |
| 58 | | ** type 78-84, 103 : 4-bit access to 0-6, 25 |
| 59 | | ** type 104-110, 129 : 8-bit access to 0-6, 25 |
| 60 | | */ |
| 61 | | typedef unsigned int uint; |
| 62 | | int sys; |
| 63 | | int var[8][2000]; |
| 64 | | string str[2000]; |
| 65 | | public: |
| 66 | | int operator () () const; |
| 67 | | int operator () (VarInfo info) const; |
| 68 | | void Str(unsigned int number, char* buf, int sz) const; |
| 69 | | |
| 70 | | bool IsInt(int type) const; |
| 71 | | int MaxIndex(int type) const; |
| 72 | | |
| 73 | | void Set(VarInfo info, int value); |
| 74 | | int Get(int type, int number) const; |
| 75 | | void SetSys(int value); |
| 76 | | void SetStr(unsigned int number, string val); |
| 77 | | }; |
| 78 | | |
| 79 | | bool Flags::IsInt(int type) const { |
| 80 | | int v = type % 26; |
| 81 | | return v >= 0 && v < 7 || v == 25; |
| 82 | | } |
| 83 | | |
| 84 | | int Flags::MaxIndex(int type) const { |
| 85 | | switch (type / 26) { |
| 86 | | case 1: |
| 87 | | return 63999; |
| 88 | | case 2: |
| 89 | | return 31999; |
| 90 | | case 3: |
| 91 | | return 15999; |
| 92 | | case 4: |
| 93 | | return 7999; |
| 94 | | default: |
| 95 | | return 1999; |
| 96 | | } |
| 97 | | } |
| 98 | | |
| 99 | | int Flags::operator()() const { |
| 100 | | return rand() % 10000; |
| 101 | | } |
| 102 | | int Flags::operator() (VarInfo info) const { |
| 103 | | return Get(info.type, info.number); |
| 104 | | } |
| 105 | | int Flags::Get(int type, int number) const { |
| 106 | | int index = type % 26; |
| 107 | | type /= 26; |
| 108 | | if (index == 25) index = 7; |
| 109 | | if (index > 7 || uint(type) > 4) return 0; |
| 110 | | if (type == 0) { |
| 111 | | // A[]..G[], Z[] €òÄŸ€ËÆÉ€à |
| 112 | | if (uint(number) >= 2000) return 0; |
| 113 | | return var[index][number]; |
| 114 | | } else { |
| 115 | | // Ab[]..G4b[], Z8b[] €Ê€É€òÆÉ€à |
| 116 | | int factor = 1 << (type - 1); |
| 117 | | int eltsize = 32 / factor; |
| 118 | | if (uint(number) >= (64000 / factor)) return 0; |
| 119 | | return (var[index][number / eltsize] >> ((number % eltsize) * factor)) & ((1 << factor) - 1); |
| 120 | | } |
| 121 | | } |
| 122 | | |
| 123 | | void Flags::Set(VarInfo info, int value) { |
| 124 | | int type = info.type / 26; |
| 125 | | int index = info.type % 26; |
| 126 | | if (index == 25) index = 7; |
| 127 | | if (type == 0) { |
| 128 | | // A[]..G[], Z[] €òÄŸ€Ëœñ€¯ |
| 129 | | if (uint(info.number) >= 2000) return; |
| 130 | | var[index][info.number] = value; |
| 131 | | } else { |
| 132 | | // Ab[]..G4b[], Z8b[] €Ê€É€òœñ€¯ |
| 133 | | int factor = 1 << (type - 1); |
| 134 | | int eltsize = 32 / factor; |
| 135 | | int eltmask = (1 << factor) - 1; |
| 136 | | int shift = (info.number % eltsize) * factor; |
| 137 | | if (uint(info.number) >= (64000 / factor)) return; |
| 138 | | var[index][info.number / eltsize] = |
| 139 | | (var[index][info.number / eltsize] & ~(eltmask << shift)) |
| 140 | | | (value & eltmask) << shift; |
| 141 | | } |
| 142 | | } |
| 143 | | |
| 144 | | void Flags::SetSys(int value) { |
| 145 | | sys = value; |
| 146 | | } |
| 147 | | void Flags::SetStr(unsigned int number, string val) { |
| 148 | | if (number >= 2000) return; |
| 149 | | str[number] = val; |
| 150 | | } |
| 151 | | void Flags::Str(unsigned int number, char* buf, int sz) const { |
| 152 | | if (number >= 2000) {if(sz>0) buf[0] = 0; return;} |
| 153 | | const string& s = str[number]; |
| 154 | | int len = s.length(); |
| 155 | | if (sz-1 > len) sz = len; |
| 156 | | s.copy(buf, sz, 0); |
| 157 | | buf[sz] = 0; |
| 158 | | return; |
| 159 | | } |
| 160 | | |
| 161 | | /* commands */ |
| 162 | | enum Cmdtype { CMD_FLAGS, CMD_JMP, CMD_TEXT, CMD_OTHER}; |
| 163 | | class Cmd { |
| 164 | | Cmdtype cmd_type; |
| 165 | | int cmd1, cmd2, cmd3, cmd4; |
| 166 | | int argc; |
| 167 | | bool errorflag; |
| 168 | | char cmdstr[1024]; |
| 169 | | const Flags& flags; |
| 170 | | vector<VarInfo> args; |
| 171 | | |
| 172 | | int GetArgs(const char*& d); |
| 173 | | int GetArgsSpecial(int normal_args,const char*& d); |
| 174 | | void GetSelection(const char*& d); |
| 175 | | int GetSwitch(const char*& d); |
| 176 | | int GetSimpleSwitch(const char*& d); |
| 177 | | int GetExpression(const char*& d, struct VarInfo* info = 0); |
| 178 | | int GetExpressionCond(const char*& d); |
| 179 | | int GetLeftToken(const char*& d, struct VarInfo& info); |
| 180 | | static int GetString(const char*& d); |
| 181 | | int StrVar(int number); |
| 182 | | static char strtype[256]; |
| 183 | | static int StrType(const char* d) { return strtype[*(unsigned const char*)d];} |
| 184 | | int AddStr(char* s) { |
| 185 | | // 1-0a-0064 €Ï€³€Š€€€Š€â€Î€¬É¬Í׀逷€€ |
| 186 | | int start = strend; |
| 187 | | while (*s) strheap[strend++] = *s++; |
| 188 | | strheap[strend++] = 0; |
| 189 | | return start; |
| 190 | | } |
| 191 | | #define STRHEAP_SIZE 10000 |
| 192 | | static char strheap[STRHEAP_SIZE]; |
| 193 | | static int strend; |
| 194 | | void SetError(void) { errorflag = true;} |
| 195 | | static void ResetString(void) { |
| 196 | | strend = 0; |
| 197 | | } |
| 198 | | static map<int, struct CmdDescrItem*> cmd_descr; |
| 199 | | const char* CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4); |
| 200 | | public: |
| 201 | | void GetCmd(Flags& f, const char*& d); |
| 202 | | bool IsError() { return errorflag;} |
| 203 | | bool ClearError() { errorflag = false;} |
| 204 | | Cmd(const Flags& f) : flags(f) { argc = 0; errorflag = false; cmdstr[0] = 0;} |
| 205 | | |
| 206 | | }; |
| 207 | | |
| 208 | | bool debug_flag = false; |
| 209 | | void dprintf(const char* fmt, ...) { |
| 210 | | if (debug_flag) { |
| 211 | | va_list ap; va_start(ap, fmt); |
| 212 | | vprintf(fmt, ap); |
| 213 | | va_end(ap); |
| 214 | | } |
| 215 | | } |
| 216 | | |
| 217 | | |
| 218 | | #define SCN_DUMP |
| 332 | | /* ±é»»»Ò op := 0x5c <uchar op> */ |
| 333 | | /* ¿ôŒ° exp: [op] <token> [op <token> [...]] */ |
| 334 | | int Cmd::GetExpression(const char*& d, VarInfo* info_ptr) { |
| 335 | | #define STACK_DEPTH 1024 |
| 336 | | #define OP_LB 11 |
| 337 | | char op_stack[STACK_DEPTH]; |
| 338 | | int val_stack[STACK_DEPTH]; |
| 339 | | int stack_count = 0; |
| 340 | | |
| 341 | | // Âè°ì¹à€ÎÆÉ€ß¹þ€ß |
| 342 | | while(*d == 0x28) { |
| 343 | | d++; |
| 344 | | dprintf("("); |
| 345 | | op_stack[stack_count++] = OP_LB; |
| 346 | | } |
| 347 | | VarInfo info; |
| 348 | | int value = GetLeftToken(d, info); |
| 349 | | |
| 350 | | while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) { |
| 351 | | d++; |
| 352 | | dprintf(")"); |
| 353 | | stack_count--; |
| 354 | | } |
| 355 | | |
| 356 | | if (*d != 0x5c && stack_count == 0) { |
| 357 | | if (info_ptr) *info_ptr = info; |
| 358 | | return value; // ñœã€Êleft-term€Ï€³€³€ÇœªÎ»¡£Ížú€Êinfo_ptr€òµ¢€¹¡Ê²ÄÇœÀ€¬€¢€ë¡Ë |
| 359 | | } |
| 360 | | |
| 361 | | while(*d == 0x5c) { |
| 362 | | int op_type = *(unsigned char*)(d+1); |
| 363 | | d += 2; |
| 364 | | if (op_type < 70) dprintf("%s",op_str[op_type]); |
| 365 | | else dprintf("err."); |
| 366 | | if (op_type >= 10) SetError(); |
| 367 | | int cur_pri = op_pri(op_type); |
| 368 | | while(stack_count != 0 && op_pri(op_stack[stack_count-1]) <= cur_pri) { |
| 369 | | // Í¥Àèœç°Ì€Î¹â€€¡¢Àè¹Ô€¹€ë±é»»€ò¹Ô€Š |
| 370 | | value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); |
| 371 | | stack_count--; |
| 372 | | } |
| 373 | | val_stack[stack_count] = value; |
| 374 | | op_stack[stack_count++] = op_type; |
| 375 | | while(*d == 0x28) { |
| 376 | | d++; |
| 377 | | dprintf("("); |
| 378 | | op_stack[stack_count++] = OP_LB; |
| 379 | | } |
| 380 | | if (stack_count >= STACK_DEPTH) SetError(); |
| 381 | | value = GetLeftToken(d, info); |
| 382 | | |
| 383 | | while (*d != 0x5c && stack_count > 0) { |
| 384 | | // Ì€ŒÂ¹Ô€Î±é»»€òœª€ï€é€»€ë |
| 385 | | if (op_stack[stack_count-1] != OP_LB) { |
| 386 | | value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); |
| 387 | | stack_count--; |
| 388 | | } else if (*d == 0x29) { /* op_stack == OP_LB */ |
| 389 | | // bracket œªÃŒ€¬€¢€ì€Ð¡¢ÊÄ€ž€Æ€ª€¯ |
| 390 | | d++; |
| 391 | | dprintf(")"); |
| 392 | | stack_count--; |
| 393 | | } else break; // error |
| 394 | | } |
| 395 | | } |
| 396 | | if (stack_count) SetError(); // unbalanced bracket |
| 397 | | dprintf("(=%d)",value); |
| 398 | | if (info_ptr) { |
| 399 | | info_ptr->type = TYPE_VAL; |
| 400 | | info_ptr->value = value; |
| 401 | | } |
| 402 | | return value; |
| 403 | | } |
| 404 | | |
| 405 | | // Ÿò·ïʬŽôÀìÍрˡ¢Ÿò·ï±é»»€È»»œÑ±é»»€Îº®¹ç€òž¡Ã΀ǀ€ëÀìÍѥ롌¥Á¥ó¡ÊËÜÍè€ÏGetExpression€Çº¹€·»Ù€š€Ê€€) |
| 406 | | int Cmd::GetExpressionCond(const char*& d) { |
| 407 | | char op_stack[STACK_DEPTH]; |
| 408 | | int val_stack[STACK_DEPTH]; |
| 409 | | int valattr_stack[STACK_DEPTH]; |
| 410 | | #define ATTR_VAL 0 |
| 411 | | #define ATTR_FLAG 1 |
| 412 | | int stack_count = 0; |
| 413 | | |
| 414 | | // Âè°ì¹à€ÎÆÉ€ß¹þ€ß |
| 415 | | while(*d == 0x28) { |
| 416 | | d++; |
| 417 | | dprintf("("); |
| 418 | | op_stack[stack_count++] = OP_LB; |
| 419 | | } |
| 420 | | VarInfo info; |
| 421 | | int value = GetLeftToken(d, info); |
| 422 | | bool valattr = ATTR_VAL; |
| 423 | | |
| 424 | | while(*d == 0x5c) { |
| 425 | | int op_type = *(unsigned char*)(d+1); |
| 426 | | d += 2; |
| 427 | | if (op_type < 70) dprintf("%s",op_str[op_type]); |
| 428 | | else dprintf("err."); |
| 429 | | int cur_pri = op_pri_cond(op_type); |
| 430 | | while(stack_count != 0 && op_pri_cond(op_stack[stack_count-1]) <= cur_pri) { |
| 431 | | // Í¥Àèœç°Ì€Î¹â€€¡¢Àè¹Ô€¹€ë±é»»€ò¹Ô€Š |
| 432 | | if (op_stack[stack_count-1] >= 60) { |
| 433 | | if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError(); |
| 434 | | } else { |
| 435 | | if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError(); |
| 436 | | } |
| 437 | | value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); |
| 438 | | if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG; |
| 439 | | stack_count--; |
| 440 | | } |
| 441 | | val_stack[stack_count] = value; |
| 442 | | valattr_stack[stack_count] = valattr; |
| 443 | | op_stack[stack_count++] = op_type; |
| 444 | | while(*d == 0x28) { |
| 445 | | d++; |
| 446 | | dprintf("("); |
| 447 | | op_stack[stack_count++] = OP_LB; |
| 448 | | } |
| 449 | | if (stack_count >= STACK_DEPTH) SetError(); |
| 450 | | value = GetLeftToken(d, info); |
| 451 | | valattr = ATTR_VAL; |
| 452 | | |
| 453 | | while (*d != 0x5c && stack_count > 0) { |
| 454 | | // Ì€ŒÂ¹Ô€Î±é»»€òœª€ï€é€»€ë |
| 455 | | if (op_stack[stack_count-1] != OP_LB) { |
| 456 | | if (op_stack[stack_count-1] >= 60) { |
| 457 | | if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError(); |
| 458 | | } else { |
| 459 | | if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError(); |
| 460 | | } |
| 461 | | value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value); |
| 462 | | if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG; |
| 463 | | stack_count--; |
| 464 | | // bracket œªÃŒ€¬€¢€ì€Ð¡¢ÊÄ€ž€Æ€ª€¯ |
| 465 | | } else if (*d == 0x29) { /* op_stack == OP_LB */ |
| 466 | | d++; |
| 467 | | dprintf(")"); |
| 468 | | stack_count--; |
| 469 | | } else break; // error |
| 470 | | } |
| 471 | | } |
| 472 | | if (stack_count) SetError(); // unbalanced bracket |
| 473 | | if (value) dprintf("(=true)"); |
| 474 | | else dprintf("(=false)"); |
| 475 | | return value; |
| 476 | | } |
| 477 | | |
| 478 | | |
| 479 | | /* |
| 480 | | str = |
| 481 | | arg = |
| 482 | | args = 0x28 <exp> [[0x2c] <exp> [[0x2c] <exp> [...] ]] |
| 483 | | */ |
| 484 | | |
| 485 | | int Cmd::GetArgs(const char*& d) { |
| 486 | | if (*d != 0x28) return 0; /* °ú¿ô€Ê€· */ |
| 487 | | d++; |
| 488 | | dprintf("args:"); |
| 489 | | VarInfo var; |
| 490 | | int i; for (i=0; i<100 ; i++) { |
| 491 | | /* number, variable, string €ÎŒïỀʀ¯ÃÍ€òÆÀ€ë */ |
| 492 | | if (*d == 0x61) { // €è€¯€ï€«€é€Ê€€(ÃÒÂ奢¥Õ¥¿¡Œ) |
| 493 | | dprintf("@%d",d[1]); |
| 494 | | d += 2; |
| 495 | | if (*d == 0x28) { |
| 496 | | dprintf("{"); |
| 497 | | GetArgs(d); // (A,B,C)ÀာŽÞ€Þ€ì€ë€³€È€¬€¢€ë |
| 498 | | dprintf("}"); |
| 499 | | } else { |
| 500 | | dprintf("{}"); |
| 501 | | } |
| 502 | | } else if (d[0] == 0x0a || d[0] == 0x40) { // €è€¯€ï€«€é€Ê€€ (Little Busters!) |
| 503 | | int var; |
| 504 | | if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;} |
| 505 | | else { var = read_little_endian_short(d+1); d += 3;} |
| 506 | | dprintf("line %d; ",var); |
| 507 | | } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) { |
| 508 | | GetExpression(d, &var); |
| 509 | | args.push_back(var); |
| 510 | | } else if (StrType(d)) { |
| 511 | | var.type = TYPE_STR; |
| 512 | | var.value = GetString(d); |
| 513 | | args.push_back(var); |
| 514 | | } else SetError(); |
| 515 | | if (*d == 0x29) break; |
| 516 | | if (*d == 0x2c) {d++;} // Œ¡€Î arg €¬±é»»»Ò€Ç»Ï€Þ€ë¡¢€Ê€É€¬€Ê€±€ì€Ðžºß€·€Ê€€ |
| 517 | | dprintf(","); |
| 518 | | } |
| 519 | | if (*d == 0x29) d++; |
| 520 | | else SetError(); |
| 521 | | return i; |
| 522 | | } |
| 523 | | |
| 524 | | int Cmd::GetArgsSpecial(int normal_args,const char*& d) { |
| 525 | | if (*d != 0x28) return 0; /* °ú¿ô€Ê€· */ |
| 526 | | d++; |
| 527 | | dprintf("args:"); |
| 528 | | int i; for (i=0; i<normal_args; i++) { |
| 529 | | /* number, variable, string €ÎŒïỀʀ¯ÃÍ€òÆÀ€ë */ |
| 530 | | if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) { |
| 531 | | GetExpression(d); |
| 532 | | } else if (StrType(d)) { |
| 533 | | GetString(d); |
| 534 | | } else SetError(); |
| 535 | | if (*d == 0x29) break; |
| 536 | | if (*d == 0x2c) {d++;} // Œ¡€Î arg €¬±é»»»Ò€Ç»Ï€Þ€ë¡¢€Ê€É€¬€Ê€±€ì€Ðžºß€·€Ê€€ |
| 537 | | dprintf(","); |
| 538 | | } |
| 539 | | for (i=0; i<argc ; i++) { |
| 540 | | if (*d == 0x28) { |
| 541 | | /* |
| 542 | | ** cmd 01-22:0c1c, 01-22:0835 |
| 543 | | ** Princess Bride €Î¥«¡Œ¥É€¬Íî€Á€ë¥¢¥Ë¥á€ÎŸìÌÌ |
| 544 | | ** €Ê€ª¡¢_PBCARDANM* €Î²èÁü€Ï€³€Î¥³¥Þ¥ó¥É€Ç€Î€ß»È€ï€ì€Æ€€€ë€Î€Ç¡¢ÆÃŒìœèÍý€È€·€ÆÌµ»ë€¹€ë€³€È€â²ÄÇœ |
| 545 | | ** |
| 546 | | ** cmd 01-04:0276, 026c, 0270 |
| 547 | | ** Ê£¿ô€Î enum €¬ args €Î¿ô€À€±Â³€¯œèÍý¡£ÆÃŒìœèÍý€È€·€ÆÊ¬Î¥€¹€ë |
| 548 | | */ |
| 549 | | dprintf("enum.<"); |
| 550 | | /* (...) €ÏÎóµó·¿ or ¹œÂ€Â΀βÄÇœÀ€¬€¢€ë */ |
| 551 | | const char* d_orig = d; |
| 552 | | int pt = args.size(); args.push_back(VarInfo(0)); |
| 553 | | int count = GetArgs(d); |
| 554 | | args[pt] = VarInfo(count); |
| 555 | | dprintf(">"); |
| 556 | | } else if (*d == 0x61 && (d[1] >= 0x00 && d[1] <= 0x04) && d[2] == 0x28 ) { |
| 557 | | /* »È€ï€ì€ë¥³¥Þ¥ó¥É€Ï 01-21:004b, 01-28:0064 €Î€€€º€ì€«¡ÊR,C,PB,LO) |
| 558 | | ** €œ€ì€é€Î¥³¥Þ¥ó¥É€Ï |
| 559 | | ** arg1: ²èÁü¥Õ¥¡¥€¥ëÌŸ |
| 560 | | ** arg2 : Sel ÈÖ¹æ |
| 561 | | ** €é€·€¯¡¢arg3 °Ê¹ß€¬ 0x61 <00-04> (a,b,c,...) €È€Ê€ë¡Ê¥À¥ó¥×Ÿå€Ï enum €ÈÉœµ€µ€ì€ë) |
| 562 | | ** () Æâ€Î°ú¿ô€Ï€µ€Þ€¶€Þ€Ç¡¢a €Î€ß¡Ê²èÁü¥Õ¥¡¥€¥ëÌŸ¡Ë¡¢ |
| 563 | | ** a,b b=SEL? |
| 564 | | ** a,b,c (b,c)=ºÂÉž¡© |
| 565 | | ** a,(b,c,d,e,f,g) b-g = src / dest? |
| 566 | | ** €é€·€€ |
| 567 | | */ |
| 568 | | dprintf("kasane. #%d <",d[1]); |
| 569 | | d += 2; |
| 570 | | int pt = args.size(); args.push_back(VarInfo(0)); |
| 571 | | int count = GetArgs(d); |
| 572 | | args[pt] = VarInfo(count); |
| 573 | | dprintf(">"); |
| 574 | | } else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0))) { |
| 575 | | /* cmd 01-15:0028 ; »Ï€á€Ë 0x24 Àာ€¢€ê¡¢Â³€€€Æ 0x28 Àá€Ë€Ê€ë */ |
| 576 | | VarInfo var; |
| 577 | | GetExpression(d, &var); |
| 578 | | args.push_back(var); |
| 579 | | i--; // €³€Î°ú¿ô€Ïargc €Î¿ô€Ë€ÏÆþ€é€Ê€€ |
| 580 | | } else SetError(); |
| 581 | | if (d[0] == 0x0a || d[0] == 0x40) { |
| 582 | | /* cmd 01-15:0028 ; 0x28 Àá€Îžå€ËËè²ó 0x0a ÀာÍè€ë */ |
| 583 | | int var; |
| 584 | | if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;} |
| 585 | | else { var = read_little_endian_short(d+1); d += 3;} |
| 586 | | dprintf("line %d; ",var); |
| 587 | | } |
| 588 | | if (*d == 0x29) break; |
| 589 | | if (*d == 0x2c) {d++;} // Œ¡€Î arg €¬±é»»»Ò€Ç»Ï€Þ€ë¡¢€Ê€É€¬€Ê€±€ì€Ðžºß€·€Ê€€ |
| 590 | | dprintf(","); |
| 591 | | } |
| 592 | | if (*d == 0x29) d++; |
| 593 | | else SetError(); |
| 594 | | return 0; |
| 595 | | } |
| 596 | | |
| 597 | | /* switch |
| 598 | | <exp> |
| 599 | | 0x7b |
| 600 | | <exp> <int> |
| 601 | | ... |
| 602 | | 0x7d |
| 603 | | */ |
| 604 | | |
| 605 | | int Cmd::GetSwitch(const char*& d) { |
| 606 | | if (*d != 0x28) {SetError(); return -1;} |
| 607 | | d++; |
| 608 | | dprintf("switch. "); |
| 609 | | int var = GetExpression(d); |
| 610 | | if (*d != 0x29) {SetError(); return -1;} |
| 611 | | d++; |
| 612 | | dprintf("->\n"); |
| 613 | | if (*d == 0x7b) { |
| 614 | | d++; |
| 615 | | } else SetError(); |
| 616 | | |
| 617 | | int default_jmp = -1; int jmpto = -1; |
| 618 | | int i; for (i=0; i<argc; i++) { |
| 619 | | dprintf("\t"); |
| 620 | | if (*d++ != 0x28) {SetError(); return -1;} |
| 621 | | int item = -1; // default |
| 622 | | if (*d != 0x29) { |
| 623 | | int item = GetExpression(d); |
| 624 | | if (*d++ != 0x29) {SetError(); return -1;} |
| 625 | | int jmp = read_little_endian_int(d); |
| 626 | | if (var == item) { |
| 627 | | dprintf("(selected)"); |
| 628 | | jmpto = jmp; |
| 629 | | } |
| 630 | | dprintf(" -> %d\n", jmp); |
| 631 | | } else { |
| 632 | | d++; |
| 633 | | default_jmp = read_little_endian_int(d); |
| 634 | | } |
| 635 | | d += 4; |
| 636 | | } |
| 637 | | if (default_jmp != -1) { |
| 638 | | dprintf("default -> %d\n",default_jmp); |
| 639 | | if (jmpto == -1) jmpto = default_jmp; |
| 640 | | } |
| 641 | | if (*d == 0x7d) { |
| 642 | | d++; |
| 643 | | } else SetError(); |
| 644 | | return jmpto; |
| 645 | | } |
| 646 | | /* simple switch |
| 647 | | <exp> |
| 648 | | 0x7b |
| 649 | | <int> |
| 650 | | ... |
| 651 | | 0x7d |
| 652 | | */ |
| 653 | | int Cmd::GetSimpleSwitch(const char*& d) { |
| 654 | | if (*d != 0x28) {SetError(); return -1;} |
| 655 | | d++; |
| 656 | | dprintf("simple switch. "); |
| 657 | | int var = GetExpression(d); |
| 658 | | if (*d != 0x29) {SetError(); return -1;} |
| 659 | | d++; |
| 660 | | dprintf(" ->\n"); |
| 661 | | int jumpto = -1; |
| 662 | | if (*d == 0x7b) { |
| 663 | | d++; |
| 664 | | } else SetError(); |
| 665 | | int i; for (i=0; i<argc; i++) { |
| 666 | | int j = read_little_endian_int(d); |
| 667 | | d += 4; |
| 668 | | dprintf("\t%d -> %d\n", i+1, j); |
| 669 | | if (var == i+1) jumpto = j; |
| 670 | | } |
| 671 | | if (*d == 0x7d) { |
| 672 | | d++; |
| 673 | | } else SetError(); |
| 674 | | return jumpto; |
| 675 | | } |
| 676 | | |
| 677 | | /* |
| 678 | | selection |
| 679 | | ? <exp> |
| 680 | | 0x7b |
| 681 | | <0x0a|0x40> <ushort | uint> |
| 682 | | */ |
| 683 | | void Cmd::GetSelection(const char*& d) { |
| 684 | | dprintf("selection. "); |
| 685 | | if (*d == 0x28) { |
| 686 | | d++; |
| 687 | | GetExpression(d); |
| 688 | | if (*d != 0x29) { SetError(); return;} |
| 689 | | d++; |
| 690 | | } |
| 691 | | if (*d == 0x7b) { |
| 692 | | d++; |
| 693 | | dprintf("{\n\t"); |
| 694 | | } else SetError(); |
| 695 | | int arg_count = 0; |
| 696 | | while(*d != 0x7d) { |
| 697 | | if (d[0] == 0x0a || d[0] == 0x40) { |
| 698 | | int var; |
| 699 | | if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;} |
| 700 | | else { var = read_little_endian_short(d+1); d += 3;} |
| 701 | | dprintf("line %d; ",var); |
| 702 | | } else if (d[0] == 0x2c) { |
| 703 | | dprintf(":comma:"); |
| 704 | | } else if (d[0] == 0x28) { |
| 705 | | dprintf(":cond:"); |
| 706 | | d++; |
| 707 | | while(d[0] != 0x29) { |
| 708 | | GetExpressionCond(d); // PRINT- Àá€Ç€Ê€€€Ð€¢€€¡¢Ÿò·ïÉœŒš¡£Œ¡€ÏÊž»úÀá¡¢€Þ€¿€ÏPRINTÀá€Î€Ï€º |
| 709 | | if (IsError()) break; |
| 710 | | if (*d == 0x32) { d++; dprintf("##");} // 0x32 €Ê€é¡¢žœºß€ÎŸò·ïÀá€òÉœŒš€·€Ê€€ |
| 711 | | if (*d == 0x31) { d++; dprintf("**");} // 0x31 €Ê€é¡¢žœºß€ÎŸò·ïÀá€òÉœŒš€¹€ë(Little Busters! : œèÍý€¬Àµ€·€€€«€Ïʬ€«€é€Ê€€) |
| 712 | | dprintf(":"); |
| 713 | | } |
| 714 | | d++; |
| 715 | | } else if (StrType(d)) { |
| 716 | | GetString(d); |
| 717 | | arg_count++; |
| 718 | | dprintf("\n\t"); |
| 719 | | } else if (*d == 0x23 && strncmp(d,"###PRINT",8) == 0) { |
| 720 | | d += 8; |
| 721 | | if (d[0] != 0x28) SetError(); |
| 722 | | else { // Êž»úÊÑ¿ô€ÎÆâÍÆ€ÎÉœŒš |
| 723 | | d++; |
| 724 | | dprintf("Print."); |
| 725 | | VarInfo info; |
| 726 | | GetLeftToken(d, info); |
| 727 | | if (d[0] != 0x29 || info.type == -1) SetError(); |
| 728 | | d++; |
| 729 | | dprintf(";"); |
| 730 | | } |
| 731 | | } else { SetError(); break;} |
| 732 | | } |
| 733 | | d++; |
| 734 | | /* @@@ */ |
| 735 | | /* °ìÃ×€·€Ê€€Ÿì¹ç€¬€¢€ë€Î€Ç¥³¥á¥ó¥È¥¢¥Š¥È */ |
| 736 | | // if (arg_count != argc) SetError(); |
| 737 | | dprintf("\n}\n"); |
| 738 | | return; |
| 739 | | } |
| 740 | | |
| 741 | | char* op_str3[11] = { "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", "="}; |
| 742 | | void Cmd::GetCmd(Flags& flags_orig, const char*& d ) { |
| 743 | | ResetString(); |
| 744 | | |
| 745 | | cmdstr[0] = 0; |
| 746 | | debug_flag = true; |
| 747 | | if (*d == 0x23) { /* ¥³¥Þ¥ó¥É */ |
| 748 | | cmd_type = CMD_OTHER; |
| 749 | | cmd1 = *(unsigned const char*)(d+1); |
| 750 | | cmd2 = *(unsigned const char*)(d+2); |
| 751 | | cmd3 = read_little_endian_short(d+3); |
| 752 | | argc = read_little_endian_short(d+5); |
| 753 | | cmd4 = *(unsigned const char*)(d+7); |
| 754 | | d += 8; |
| 755 | | /* verbose */ |
| 756 | | // dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc); |
| 757 | | sprintf(cmdstr, "%02x-%02x:%04x:%02x : %s",cmd1,cmd2,cmd3,cmd4,CmdDescr(cmd1,cmd2,cmd3,cmd4)); |
| 758 | | /* °ú¿ô€òÆÀ€ë */ |
| 759 | | /* ÆÃŒì°ú¿ô€Î€â€Î */ |
| 760 | | int is_special = 0; |
| 761 | | if (cmd1 == 0) { |
| 762 | | if (cmd2 == 1) { |
| 763 | | int jump_arg = -1; |
| 764 | | if (cmd3 == 0 || cmd3 == 5) { |
| 765 | | /* gosub / goto */ |
| 766 | | jump_arg =read_little_endian_int(d); |
| 767 | | d += 4; |
| 768 | | dprintf("\tjmp -> %d\n", jump_arg); |
| 769 | | is_special = 1; |
| 770 | | } else if (cmd3 == 1 || cmd3 == 2) { |
| 771 | | /* conditional jump (if / unless) */ |
| 772 | | if (*d++ != 0x28) { SetError(); return;} |
| 773 | | dprintf("\t"); |
| 774 | | int cond = GetExpressionCond(d); |
| 775 | | if (IsError()) return; |
| 776 | | if (*d++ != 0x29) { SetError(); return; } |
| 777 | | int jumpto = read_little_endian_int(d); |
| 778 | | d += 4; |
| 779 | | dprintf("-> %d\n", jumpto); |
| 780 | | if (cond) jump_arg = jumpto; |
| 781 | | is_special = 1; |
| 782 | | } else if (cmd3 == 4) { |
| 783 | | /* switch to */ |
| 784 | | jump_arg = GetSwitch(d); |
| 785 | | is_special = 1; |
| 786 | | } else if (cmd3 == 16) { |
| 787 | | dprintf("local call with paramters;\n"); |
| 788 | | GetArgs(d); |
| 789 | | int jumpto = read_little_endian_int(d); |
| 790 | | d += 4; |
| 791 | | dprintf("\tjmp -> %d\n",jumpto); |
| 792 | | is_special = 1; |
| 793 | | } else if (cmd3 == 8 || cmd3 == 3) { |
| 794 | | /* switch to */ |
| 795 | | jump_arg = GetSimpleSwitch(d); |
| 796 | | dprintf("\tjmp -> %d\n",jump_arg); |
| 797 | | is_special = 1; |
| 798 | | } |
| 799 | | cmd_type = CMD_OTHER; |
| 800 | | args.push_back(VarInfo(jump_arg)); |
| 801 | | } else if (cmd2 == 2 && (cmd3 == 0 || cmd3 == 1 || cmd3 == 2 || cmd3 == 3 || cmd3 == 0x0d) ) { |
| 802 | | /* selection */ |
| 803 | | GetSelection(d); |
| 804 | | is_special = 1; |
| 805 | | } |
| 806 | | } |
| 807 | | /* °ìḚ̀ú¿ô€Î€â€Î */ |
| 808 | | if (!is_special) { |
| 809 | | dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] : %s\n",cmd1,cmd2,cmd3,cmd4,argc,CmdDescr(cmd1,cmd2,cmd3,cmd4)); |
| 810 | | dprintf("\t"); |
| 811 | | if (cmd1 == 1 && cmd2 == 0x22 && (cmd3 == 0xc1c || cmd3 == 0x835)) GetArgsSpecial(3, d); |
| 812 | | else if (cmd1 == 1 && cmd2 == 0x0b && cmd3 == 0x65) GetArgsSpecial(0, d); |
| 813 | | else if (cmd1 == 1 && cmd2 == 0x15 && cmd3 == 0x28) GetArgsSpecial(0, d); |
| 814 | | else if (cmd1 == 1 && cmd2 == 4 && (cmd3 == 0x26c || cmd3 == 0x26d || cmd3 == 0x270 || cmd3 == 0x276)) GetArgsSpecial(0, d); |
| 815 | | else if (cmd1 == 1 && (cmd2 == 0x21 && cmd3 == 0x4b) || (cmd2 == 0x28 && cmd3 == 0x64)) GetArgsSpecial(2,d); |
| 816 | | else GetArgs(d); |
| 817 | | dprintf("\n"); |
| 818 | | |
| 819 | | } |
| 820 | | if (cmd2 == 3 && cmd3 == 0x78 && cmd4 == 0) ruby_flag = true; |
| 821 | | if (cmd2 == 3 && cmd3 == 0x11) ret_flag = true; |
| 822 | | } else if (*d == 0x24) { /* ÂåÆþ±é»» */ |
| 823 | | if (d[1] == 0x12 || d[2] != 0x5b) SetError(); |
| 824 | | dprintf("expr: "); |
| 825 | | sprintf(cmdstr, "expr"); |
| 826 | | |
| 827 | | VarInfo info; |
| 828 | | int value = GetLeftToken(d, info); |
| 829 | | if (d[0] != 0x5c) SetError(); |
| 830 | | int type = d[1]; |
| 831 | | if (type < 20 || type > 30) SetError(); |
| 832 | | else dprintf("%s",op_str[type]); |
| 833 | | d += 2; |
| 834 | | int value2 = GetExpression(d); |
| 835 | | // ÂåÆþŸðÊó€òËä€á¹þ€à |
| 836 | | if (type != 30) value2 = eval(value, type-20, value2); |
| 837 | | cmd_type = CMD_FLAGS; |
| 838 | | args.push_back(info); |
| 839 | | args.push_back(value2); |
| 840 | | dprintf("\n"); |
| 841 | | } else if (StrType(d)) { /* Êž»úœÐÎÏ */ |
| 842 | | VarInfo info; |
| 843 | | info.type = TYPE_STR; |
| 844 | | info.value = GetString(d); |
| 845 | | args.push_back(info); |
| 846 | | cmd_type = CMD_TEXT; |
| 847 | | text_flag = true; |
| 848 | | dprintf("\n"); |
| 849 | | } else if (*d == 0x0a || *d == 0x40 || *d == 0x21) { /* ¥Ç¥Ð¥Ã¥°ÍѥǡŒ¥¿€ÈŽûÆÉ¥Õ¥é¥° */ |
| 850 | | cmd_type = CMD_OTHER; |
| 851 | | if (*d == 0x0a) { |
| 852 | | dprintf("line "); |
| 853 | | d++; |
| 854 | | int l; |
| 855 | | if (system_version == 0) { |
| 856 | | l = read_little_endian_int(d); |
| 857 | | d += 4; |
| 858 | | } else { |
| 859 | | l = read_little_endian_short(d); |
| 860 | | d += 2; |
| 861 | | } |
| 862 | | dprintf("%d\n", l); |
| 863 | | } else { /* 0x40, 0x21 */ |
| 864 | | // ŽûÆÉ¥Þ¡Œ¥«¡Œ€é€·€€¡£¥š¥ó¥È¥ê¡Œ¥Ý¥€¥ó¥È€È¥»¡Œ¥Ö¥Ý¥€¥ó¥È€â»È€ï€ì€ë¡£ |
| 865 | | // RealLive 1.2.5€«€é¡¢0x40€Ï¥»¡Œ¥Ö¥Ý¥€¥ó¥È¡¢0x21€Ï¥š¥ó¥È¥ê¡Œ¥Ý¥€¥ó¥È¡£ |
| 866 | | // 1.2.5°ÊÁ°¡¢€É€Á€é€â0x40€¬»È€ï€ì€ë¡£ |
| 867 | | int kidoku_index; |
| 868 | | d++; |
| 869 | | if (system_version == 0) { |
| 870 | | kidoku_index = read_little_endian_int(d); |
| 871 | | d += 4; |
| 872 | | } else { |
| 873 | | kidoku_index = read_little_endian_short(d); |
| 874 | | d += 2; |
| 875 | | } |
| 876 | | dprintf("kidoku marker %d\n", kidoku_index); |
| 877 | | // text_readflag€Ï¡¢€³€Îkidoku_index€ò»È€Ã€¿€éÎÉ€€€«€Ê¡£ |
| 878 | | } |
| 879 | | } else if (*d == 0x2c) { /* ??? */ |
| 880 | | dprintf("commd;0x2c\n"); // conditional jump €Î¹Ô€Àè€Ë€è€¯€¢€ë€é€·€€¡ÊŸï€Ë¡¢€«€Ï€ï€«€é€Ê€€¡Ë |
| 881 | | d++; |
| 882 | | } else { |
| 883 | | SetError(); |
| 884 | | } |
| 885 | | return; |
| 886 | | } |
| 887 | | |
| 888 | | char Cmd::strtype[256] = { |
| 889 | | 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +00 */ |
| 890 | | 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +10 */ |
| 891 | | 0,0,3,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +20 */ |
| 892 | | 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,1, /* +30 */ |
| 893 | | 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +40 */ |
| 894 | | 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +50 */ |
| 895 | | 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +60 */ |
| 896 | | 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +70 */ |
| 897 | | 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +80 */ |
| 898 | | 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +90 */ |
| 899 | | 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +A0 */ |
| 900 | | 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +B0 */ |
| 901 | | 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +C0 */ |
| 902 | | 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +D0 */ |
| 903 | | 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +E0 */ |
| 904 | | 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,0,0 /* +F0 */ |
| 905 | | }; |
| 906 | | |
| 907 | | int Cmd::GetString(const char*& d) { |
| 908 | | int retnum = -1; |
| 909 | | while(1) { |
| 910 | | if (*d == '\\') { |
| 911 | | d++; |
| 912 | | strheap[strend++] = *d++; |
| 913 | | } else if (*d == '"') { |
| 914 | | d++; |
| 915 | | if (retnum == -1) retnum = strend; |
| 916 | | while(*d != '"') strheap[strend++] = *d++; |
| 917 | | d++; |
| 918 | | } else if (StrType(d)) { |
| 919 | | if (retnum == -1) retnum = strend; |
| 920 | | int stype; |
| 921 | | while( (stype = StrType(d)) ) { |
| 922 | | if (stype == 3) break; // ÊžÃæ€Ë '"' €¬žœ€ì€¿Ÿì¹ç |
| 923 | | strheap[strend++] = *d++; |
| 924 | | if (stype == 2) strheap[strend++] = *d++; |
| 925 | | } |
| 926 | | } else break; |
| 927 | | } |
| 928 | | if (retnum != -1) strheap[strend++] = 0; |
| 929 | | dprintf("\"%s\"", strheap + retnum); |
| 930 | | if (strend >= STRHEAP_SIZE) { |
| 931 | | dprintf("Error: string heap overflow\n"); |
| 932 | | } |
| 933 | | return retnum; |
| 934 | | } |
| 935 | | |
| 936 | | int Cmd::StrVar(int var_num) { |
| 937 | | int retnum = strend; |
| 938 | | flags.Str(var_num, strheap+strend, STRHEAP_SIZE-strend); |
| 939 | | strend += strlen(strheap+strend)+1; |
| 940 | | return retnum; |
| 941 | | } |