acc.cpp revision 21a15a2416b4b138bf509186106525944e78ad08
1/* 2 Obfuscated Tiny C Compiler 3 4 Copyright (C) 2001-2003 Fabrice Bellard 5 6 This software is provided 'as-is', without any express or implied 7 warranty. In no event will the authors be held liable for any damages 8 arising from the use of this software. 9 10 Permission is granted to anyone to use this software for any purpose, 11 including commercial applications, and to alter it and redistribute it 12 freely, subject to the following restrictions: 13 14 1. The origin of this software must not be misrepresented; you must not 15 claim that you wrote the original software. If you use this software 16 in a product, an acknowledgment in the product and its documentation 17 *is* required. 18 2. Altered source versions must be plainly marked as such, and must not be 19 misrepresented as being the original software. 20 3. This notice may not be removed or altered from any source distribution. 21 */ 22 23#include <ctype.h> 24#include <dlfcn.h> 25#include <stdarg.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29 30namespace acc { 31 32class compiler { 33 34 class CodeBuf { 35 char* ind; 36 char* pProgramBase; 37 38 void release() { 39 if (pProgramBase != 0) { 40 free(pProgramBase); 41 pProgramBase = 0; 42 } 43 } 44 45 public: 46 CodeBuf() { 47 pProgramBase = 0; 48 ind = 0; 49 } 50 51 ~CodeBuf() { 52 release(); 53 } 54 55 void init(int size) { 56 release(); 57 pProgramBase = (char*) calloc(1, size); 58 ind = pProgramBase; 59 } 60 61 void o(int n) { 62 /* cannot use unsigned, so we must do a hack */ 63 while (n && n != -1) { 64 *ind++ = n; 65 n = n >> 8; 66 } 67 } 68 69 /* 70 * Output a byte. Handles all values, 0..ff. 71 */ 72 void ob(int n) { 73 *ind++ = n; 74 } 75 76 /* output a symbol and patch all calls to it */ 77 void gsym(int t) { 78 int n; 79 while (t) { 80 n = *(int *) t; /* next value */ 81 *(int *) t = ((int) ind) - t - 4; 82 t = n; 83 } 84 } 85 86 /* psym is used to put an instruction with a data field which is a 87 reference to a symbol. It is in fact the same as oad ! */ 88 int psym(int n, int t) { 89 return oad(n, t); 90 } 91 92 /* instruction + address */ 93 int oad(int n, int t) { 94 o(n); 95 *(int *) ind = t; 96 t = (int) ind; 97 ind = ind + 4; 98 return t; 99 } 100 101 inline void* getBase() { 102 return (void*) pProgramBase; 103 } 104 105 int getSize() { 106 return ind - pProgramBase; 107 } 108 109 int getPC() { 110 return (int) ind; 111 } 112 }; 113 114 class CodeGenerator { 115 public: 116 CodeGenerator() {} 117 virtual ~CodeGenerator() {} 118 119 void init(CodeBuf* pCodeBuf) { 120 this->pCodeBuf = pCodeBuf; 121 } 122 123 /* output a symbol and patch all calls to it */ 124 void gsym(int t) { 125 pCodeBuf->gsym(t); 126 } 127 128 protected: 129 void o(int n) { 130 pCodeBuf->o(n); 131 } 132 133 /* 134 * Output a byte. Handles all values, 0..ff. 135 */ 136 void ob(int n) { 137 pCodeBuf->ob(n); 138 } 139 140 /* psym is used to put an instruction with a data field which is a 141 reference to a symbol. It is in fact the same as oad ! */ 142 int psym(int n, int t) { 143 return oad(n, t); 144 } 145 146 /* instruction + address */ 147 int oad(int n, int t) { 148 return pCodeBuf->oad(n,t); 149 } 150 151 int getPC() { 152 return pCodeBuf->getPC(); 153 } 154 155 private: 156 CodeBuf* pCodeBuf; 157 }; 158 159 class X86CodeGenerator : public CodeGenerator { 160 public: 161 X86CodeGenerator() {} 162 virtual ~X86CodeGenerator() {} 163 164 /* load immediate value */ 165 int li(int t) { 166 oad(0xb8, t); /* mov $xx, %eax */ 167 } 168 169 int gjmp(int t) { 170 return psym(0xe9, t); 171 } 172 173 /* l = 0: je, l == 1: jne */ 174 int gtst(int l, int t) { 175 o(0x0fc085); /* test %eax, %eax, je/jne xxx */ 176 return psym(0x84 + l, t); 177 } 178 179 int gcmp(int t) { 180 o(0xc139); /* cmp %eax,%ecx */ 181 li(0); 182 o(0x0f); /* setxx %al */ 183 o(t + 0x90); 184 o(0xc0); 185 } 186 187 void clearECX() { 188 oad(0xb9, 0); /* movl $0, %ecx */ 189 } 190 191 void pushEAX() { 192 o(0x50); /* push %eax */ 193 } 194 195 void storeEAXIntoPoppedLVal(bool isInt) { 196 o(0x59); /* pop %ecx */ 197 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */ 198 } 199 200 void loadEAXIndirect(bool isInt) { 201 if (isInt) 202 o(0x8b); /* mov (%eax), %eax */ 203 else 204 o(0xbe0f); /* movsbl (%eax), %eax */ 205 ob(0); /* add zero in code */ 206 } 207 208 void leaEAX(int ea) { 209 gmov(10, ea); /* leal EA, %eax */ 210 } 211 212 void storeEAX(int ea) { 213 gmov(6, ea); /* mov %eax, EA */ 214 } 215 216 void loadEAX(int ea) { 217 gmov(8, ea); /* mov EA, %eax */ 218 } 219 220 void puzzleAdd(int n, int tokc) { 221 /* Not sure what this does, related to variable loading with an 222 * operator at level 11. 223 */ 224 gmov(0, n); /* 83 ADD */ 225 o(tokc); 226 } 227 228 int allocStackSpaceForArgs() { 229 return oad(0xec81, 0); /* sub $xxx, %esp */ 230 } 231 232 void storeEAToArg(int l) { 233 oad(0x248489, l); /* movl %eax, xxx(%esp) */ 234 } 235 236 int callForward(int symbol) { 237 return psym(0xe8, symbol); /* call xxx */ 238 } 239 240 void callRelative(int t) { 241 psym(0xe8, t); /* call xxx */ 242 } 243 244 void callIndirect(int l) { 245 oad(0x2494ff, l); /* call *xxx(%esp) */ 246 } 247 248 void adjustStackAfterCall(int l) { 249 oad(0xc481, l); /* add $xxx, %esp */ 250 } 251 252 void oHack(int n) { 253 o(n); 254 } 255 256 void oadHack(int n, int t) { 257 oad(n, t); 258 } 259 private: 260 261 int gmov(int l, int t) { 262 o(l + 0x83); 263 oad((t < LOCAL) << 7 | 5, t); 264 } 265 }; 266 267 /* vars: value of variables 268 loc : local variable index 269 glo : global variable index 270 ind : output code ptr 271 rsym: return symbol 272 prog: output code 273 dstk: define stack 274 dptr, dch: macro state 275 */ 276 int tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk, 277 dptr, dch, last_id; 278 void* pSymbolBase; 279 void* pGlobalBase; 280 void* pVarsBase; 281 FILE* file; 282 283 CodeBuf codeBuf; 284 X86CodeGenerator* pGen; 285 286 static const int ALLOC_SIZE = 99999; 287 288 /* depends on the init string */ 289 static const int TOK_STR_SIZE = 48; 290 static const int TOK_IDENT = 0x100; 291 static const int TOK_INT = 0x100; 292 static const int TOK_IF = 0x120; 293 static const int TOK_ELSE = 0x138; 294 static const int TOK_WHILE = 0x160; 295 static const int TOK_BREAK = 0x190; 296 static const int TOK_RETURN = 0x1c0; 297 static const int TOK_FOR = 0x1f8; 298 static const int TOK_DEFINE = 0x218; 299 static const int TOK_MAIN = 0x250; 300 301 static const int TOK_DUMMY = 1; 302 static const int TOK_NUM = 2; 303 304 static const int LOCAL = 0x200; 305 306 static const int SYM_FORWARD = 0; 307 static const int SYM_DEFINE = 1; 308 309 /* tokens in string heap */ 310 static const int TAG_TOK = ' '; 311 static const int TAG_MACRO = 2; 312 313 void pdef(int t) { 314 *(char *) dstk++ = t; 315 } 316 317 void inp() { 318 if (dptr) { 319 ch = *(char *) dptr++; 320 if (ch == TAG_MACRO) { 321 dptr = 0; 322 ch = dch; 323 } 324 } else 325 ch = fgetc(file); 326 /* printf("ch=%c 0x%x\n", ch, ch); */ 327 } 328 329 int isid() { 330 return isalnum(ch) | ch == '_'; 331 } 332 333 /* read a character constant */ 334 void getq() { 335 if (ch == '\\') { 336 inp(); 337 if (ch == 'n') 338 ch = '\n'; 339 } 340 } 341 342 void next() { 343 int l, a; 344 345 while (isspace(ch) | ch == '#') { 346 if (ch == '#') { 347 inp(); 348 next(); 349 if (tok == TOK_DEFINE) { 350 next(); 351 pdef(TAG_TOK); /* fill last ident tag */ 352 *(int *) tok = SYM_DEFINE; 353 *(int *) (tok + 4) = dstk; /* define stack */ 354 } 355 /* well we always save the values ! */ 356 while (ch != '\n') { 357 pdef(ch); 358 inp(); 359 } 360 pdef(ch); 361 pdef(TAG_MACRO); 362 } 363 inp(); 364 } 365 tokl = 0; 366 tok = ch; 367 /* encode identifiers & numbers */ 368 if (isid()) { 369 pdef(TAG_TOK); 370 last_id = dstk; 371 while (isid()) { 372 pdef(ch); 373 inp(); 374 } 375 if (isdigit(tok)) { 376 tokc = strtol((char*) last_id, 0, 0); 377 tok = TOK_NUM; 378 } else { 379 *(char *) dstk = TAG_TOK; /* no need to mark end of string (we 380 suppose data is initialized to zero by calloc) */ 381 tok = (int) (strstr((char*) sym_stk, (char*) (last_id - 1)) 382 - sym_stk); 383 *(char *) dstk = 0; /* mark real end of ident for dlsym() */ 384 tok = tok * 8 + TOK_IDENT; 385 if (tok > TOK_DEFINE) { 386 tok = vars + tok; 387 /* printf("tok=%s %x\n", last_id, tok); */ 388 /* define handling */ 389 if (*(int *) tok == SYM_DEFINE) { 390 dptr = *(int *) (tok + 4); 391 dch = ch; 392 inp(); 393 next(); 394 } 395 } 396 } 397 } else { 398 inp(); 399 if (tok == '\'') { 400 tok = TOK_NUM; 401 getq(); 402 tokc = ch; 403 inp(); 404 inp(); 405 } else if (tok == '/' & ch == '*') { 406 inp(); 407 while (ch) { 408 while (ch != '*') 409 inp(); 410 inp(); 411 if (ch == '/') 412 ch = 0; 413 } 414 inp(); 415 next(); 416 } else { 417 const char 418 * t = 419 "++#m--%am*@R<^1c/@%[_[H3c%@%[_[H3c+@.B#d-@%:_^BKd<<Z/03e>>`/03e<=0f>=/f<@.f>@1f==&g!=\'g&&k||#l&@.BCh^@.BSi|@.B+j~@/%Yd!@&d*@b"; 420 while (l = *t++) { 421 a = *t++; 422 tokc = 0; 423 while ((tokl = *t++ - 'b') < 0) 424 tokc = tokc * 64 + tokl + 64; 425 if (l == tok & (a == ch | a == '@')) { 426#if 0 427 printf("%c%c -> tokl=%d tokc=0x%x\n", 428 l, a, tokl, tokc); 429#endif 430 if (a == ch) { 431 inp(); 432 tok = TOK_DUMMY; /* dummy token for double tokens */ 433 } 434 break; 435 } 436 } 437 } 438 } 439#if 0 440 { 441 int p; 442 443 printf("tok=0x%x ", tok); 444 if (tok >= TOK_IDENT) { 445 printf("'"); 446 if (tok> TOK_DEFINE) 447 p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8; 448 else 449 p = sym_stk + 1 + (tok - TOK_IDENT) / 8; 450 while (*(char *)p != TAG_TOK && *(char *)p) 451 printf("%c", *(char *)p++); 452 printf("'\n"); 453 } else if (tok == TOK_NUM) { 454 printf("%d\n", tokc); 455 } else { 456 printf("'%c'\n", tok); 457 } 458 } 459#endif 460 } 461 462 void error(const char *fmt, ...) { 463 va_list ap; 464 465 va_start(ap, fmt); 466 fprintf(stderr, "%ld: ", ftell((FILE *) file)); 467 vfprintf(stderr, fmt, ap); 468 fprintf(stderr, "\n"); 469 va_end(ap); 470 exit(1); 471 } 472 473 void skip(int c) { 474 if (tok != c) { 475 error("'%c' expected", c); 476 } 477 next(); 478 } 479 480 /* load immediate value */ 481 int li(int t) { 482 return pGen->li(t); 483 } 484 485 int gjmp(int t) { 486 return pGen->gjmp(t); 487 } 488 489 /* l = 0: je, l == 1: jne */ 490 int gtst(int l, int t) { 491 return pGen->gtst(l, t); 492 } 493 494 int gcmp(int t) { 495 return pGen->gcmp(t); 496 } 497 498 void clearEXC() { 499 pGen->clearECX(); 500 } 501 502 void storeEAXIntoPoppedLVal(bool isInt) { 503 pGen->storeEAXIntoPoppedLVal(isInt); 504 } 505 506 void loadEAXIndirect(bool isInt) { 507 pGen->loadEAXIndirect(isInt); 508 } 509 510 void leaEAX(int ea) { 511 pGen->leaEAX(ea); 512 } 513 514 /* Temporary hack for emitting x86 code directly. */ 515 void o(int n) { 516 pGen->oHack(n); 517 } 518 519 /* instruction + address */ 520 int oad(int n, int t) { 521 pGen->oadHack(n,t); 522 } 523 524 /* instruction + address */ 525 int psym(int n, int t) { 526 pGen->oadHack(n,t); 527 } 528 529 void gsym(int n) { 530 pGen->gsym(n); 531 } 532 533 /* l is one if '=' parsing wanted (quick hack) */ 534 void unary(int l) { 535 int n, t, a, c; 536 537 n = 1; /* type of expression 0 = forward, 1 = value, other = 538 lvalue */ 539 if (tok == '\"') { 540 li(glo); 541 while (ch != '\"') { 542 getq(); 543 *(char *) glo++ = ch; 544 inp(); 545 } 546 *(char *) glo = 0; 547 glo = glo + 4 & -4; /* align heap */ 548 inp(); 549 next(); 550 } else { 551 c = tokl; 552 a = tokc; 553 t = tok; 554 next(); 555 if (t == TOK_NUM) { 556 li(a); 557 } else if (c == 2) { 558 /* -, +, !, ~ */ 559 unary(0); 560 clearEXC(); 561 if (t == '!') 562 gcmp(a); 563 else 564 o(a); 565 } else if (t == '(') { 566 expr(); 567 skip(')'); 568 } else if (t == '*') { 569 /* parse cast */ 570 skip('('); 571 t = tok; /* get type */ 572 next(); /* skip int/char/void */ 573 next(); /* skip '*' or '(' */ 574 if (tok == '*') { 575 /* function type */ 576 skip('*'); 577 skip(')'); 578 skip('('); 579 skip(')'); 580 t = 0; 581 } 582 skip(')'); 583 unary(0); 584 if (tok == '=') { 585 next(); 586 pGen->pushEAX(); 587 expr(); 588 storeEAXIntoPoppedLVal(t == TOK_INT); 589 } else if (t) { 590 loadEAXIndirect(t == TOK_INT); 591 } 592 } else if (t == '&') { 593 leaEAX(*(int *) tok); 594 next(); 595 } else { 596 n = *(int *) t; 597 /* forward reference: try dlsym */ 598 if (!n) 599 n = (int) dlsym(0, (char*) last_id); 600 if (tok == '=' & l) { 601 /* assignment */ 602 next(); 603 expr(); 604 pGen->storeEAX(n); 605 } else if (tok != '(') { 606 /* variable */ 607 pGen->loadEAX(n); 608 if (tokl == 11) { 609 pGen->puzzleAdd(n, tokc); 610 next(); 611 } 612 } 613 } 614 } 615 616 /* function call */ 617 if (tok == '(') { 618 if (n == 1) 619 pGen->pushEAX(); 620 621 /* push args and invert order */ 622 a = pGen->allocStackSpaceForArgs(); 623 next(); 624 l = 0; 625 while (tok != ')') { 626 expr(); 627 pGen->storeEAToArg(l); 628 if (tok == ',') 629 next(); 630 l = l + 4; 631 } 632 *(int *) a = l; 633 next(); 634 if (!n) { 635 /* forward reference */ 636 t = t + 4; 637 *(int *) t = pGen->callForward(*(int *) t); 638 } else if (n == 1) { 639 pGen->callIndirect(l); 640 l = l + 4; 641 } else { 642 pGen->callRelative(n - codeBuf.getPC() - 5); /* call xxx */ 643 } 644 if (l) 645 pGen->adjustStackAfterCall(l); 646 } 647 } 648 649 void sum(int l) { 650 int t, n, a; 651 652 if (l-- == 1) 653 unary(1); 654 else { 655 sum(l); 656 a = 0; 657 while (l == tokl) { 658 n = tok; 659 t = tokc; 660 next(); 661 662 if (l > 8) { 663 a = gtst(t, a); /* && and || output code generation */ 664 sum(l); 665 } else { 666 o(0x50); /* push %eax */ 667 sum(l); 668 o(0x59); /* pop %ecx */ 669 670 if (l == 4 | l == 5) { 671 gcmp(t); 672 } else { 673 o(t); 674 if (n == '%') 675 o(0x92); /* xchg %edx, %eax */ 676 } 677 } 678 } 679 /* && and || output code generation */ 680 if (a && l > 8) { 681 a = gtst(t, a); 682 li(t ^ 1); 683 gjmp(5); /* jmp $ + 5 */ 684 gsym(a); 685 li(t); 686 } 687 } 688 } 689 690 void expr() { 691 sum(11); 692 } 693 694 int test_expr() { 695 expr(); 696 return gtst(0, 0); 697 } 698 699 void block(int l) { 700 int a, n, t; 701 702 if (tok == TOK_IF) { 703 next(); 704 skip('('); 705 a = test_expr(); 706 skip(')'); 707 block(l); 708 if (tok == TOK_ELSE) { 709 next(); 710 n = gjmp(0); /* jmp */ 711 gsym(a); 712 block(l); 713 gsym(n); /* patch else jmp */ 714 } else { 715 gsym(a); /* patch if test */ 716 } 717 } else if (tok == TOK_WHILE | tok == TOK_FOR) { 718 t = tok; 719 next(); 720 skip('('); 721 if (t == TOK_WHILE) { 722 n = codeBuf.getPC(); 723 a = test_expr(); 724 } else { 725 if (tok != ';') 726 expr(); 727 skip(';'); 728 n = codeBuf.getPC(); 729 a = 0; 730 if (tok != ';') 731 a = test_expr(); 732 skip(';'); 733 if (tok != ')') { 734 t = gjmp(0); 735 expr(); 736 gjmp(n - codeBuf.getPC() - 5); 737 gsym(t); 738 n = t + 4; 739 } 740 } 741 skip(')'); 742 block((int) &a); 743 gjmp(n - codeBuf.getPC() - 5); /* jmp */ 744 gsym(a); 745 } else if (tok == '{') { 746 next(); 747 /* declarations */ 748 decl(1); 749 while (tok != '}') 750 block(l); 751 next(); 752 } else { 753 if (tok == TOK_RETURN) { 754 next(); 755 if (tok != ';') 756 expr(); 757 rsym = gjmp(rsym); /* jmp */ 758 } else if (tok == TOK_BREAK) { 759 next(); 760 *(int *) l = gjmp(*(int *) l); 761 } else if (tok != ';') 762 expr(); 763 skip(';'); 764 } 765 } 766 767 /* 'l' is true if local declarations */ 768 void decl(int l) { 769 int a; 770 771 while (tok == TOK_INT | tok != -1 & !l) { 772 if (tok == TOK_INT) { 773 next(); 774 while (tok != ';') { 775 if (l) { 776 loc = loc + 4; 777 *(int *) tok = -loc; 778 } else { 779 *(int *) tok = glo; 780 glo = glo + 4; 781 } 782 next(); 783 if (tok == ',') 784 next(); 785 } 786 skip(';'); 787 } else { 788 /* patch forward references (XXX: do not work for function 789 pointers) */ 790 gsym(*(int *) (tok + 4)); 791 /* put function address */ 792 *(int *) tok = codeBuf.getPC(); 793 next(); 794 skip('('); 795 a = 8; 796 while (tok != ')') { 797 /* read param name and compute offset */ 798 *(int *) tok = a; 799 a = a + 4; 800 next(); 801 if (tok == ',') 802 next(); 803 } 804 next(); /* skip ')' */ 805 rsym = loc = 0; 806 o(0xe58955); /* push %ebp, mov %esp, %ebp */ 807 a = oad(0xec81, 0); /* sub $xxx, %esp */ 808 block(0); 809 gsym(rsym); 810 o(0xc3c9); /* leave, ret */ 811 *(int *) a = loc; /* save local variables */ 812 } 813 } 814 } 815 816 void cleanup() { 817 if (sym_stk != 0) { 818 free((void*) sym_stk); 819 sym_stk = 0; 820 } 821 if (pGlobalBase != 0) { 822 free((void*) pGlobalBase); 823 pGlobalBase = 0; 824 } 825 if (pVarsBase != 0) { 826 free(pVarsBase); 827 pVarsBase = 0; 828 } 829 if (pGen) { 830 delete pGen; 831 pGen = 0; 832 } 833 } 834 835 void clear() { 836 tok = 0; 837 tokc = 0; 838 tokl = 0; 839 ch = 0; 840 vars = 0; 841 rsym = 0; 842 loc = 0; 843 glo = 0; 844 sym_stk = 0; 845 dstk = 0; 846 dptr = 0; 847 dch = 0; 848 last_id = 0; 849 file = 0; 850 pGlobalBase = 0; 851 pVarsBase = 0; 852 pGen = 0; 853 } 854 855public: 856 compiler() { 857 clear(); 858 } 859 860 ~compiler() { 861 cleanup(); 862 } 863 864 int compile(FILE* in) { 865 cleanup(); 866 clear(); 867 codeBuf.init(ALLOC_SIZE); 868 pGen = new X86CodeGenerator(); 869 pGen->init(&codeBuf); 870 file = in; 871 sym_stk = (int) calloc(1, ALLOC_SIZE); 872 dstk = (int) strcpy((char*) sym_stk, 873 " int if else while break return for define main ") 874 + TOK_STR_SIZE; 875 pGlobalBase = calloc(1, ALLOC_SIZE); 876 glo = (int) pGlobalBase; 877 pVarsBase = calloc(1, ALLOC_SIZE); 878 vars = (int) pVarsBase; 879 inp(); 880 next(); 881 decl(0); 882 return 0; 883 } 884 885 int run(int argc, char** argv) { 886 typedef int (*mainPtr)(int argc, char** argv); 887 mainPtr aMain = (mainPtr) *(int*) (vars + TOK_MAIN); 888 if (!aMain) { 889 fprintf(stderr, "Could not find function \"main\".\n"); 890 return -1; 891 } 892 return aMain(argc, argv); 893 } 894 895 int dump(FILE* out) { 896 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out); 897 return 0; 898 } 899 900}; 901 902} // namespace acc 903 904int main(int argc, char** argv) { 905 bool doTest = false; 906 const char* inFile = NULL; 907 const char* outFile = NULL; 908 int i; 909 for (i = 1; i < argc; i++) { 910 char* arg = argv[i]; 911 if (arg[0] == '-') { 912 switch (arg[1]) { 913 case 'T': 914 if (i + 1 >= argc) { 915 fprintf(stderr, "Expected filename after -T\n"); 916 return 2; 917 } 918 doTest = true; 919 outFile = argv[i + 1]; 920 i += 1; 921 break; 922 default: 923 fprintf(stderr, "Unrecognized flag %s\n", arg); 924 return 3; 925 } 926 } else if (inFile == NULL) { 927 inFile = arg; 928 } else { 929 break; 930 } 931 } 932 933 FILE* in = stdin; 934 if (inFile) { 935 in = fopen(inFile, "r"); 936 if (!in) { 937 fprintf(stderr, "Could not open input file %s\n", inFile); 938 return 1; 939 } 940 } 941 acc::compiler compiler; 942 int compileResult = compiler.compile(in); 943 if (in != stdin) { 944 fclose(in); 945 } 946 if (compileResult) { 947 fprintf(stderr, "Compile failed: %d\n", compileResult); 948 return 6; 949 } 950 if (doTest) { 951 FILE* save = fopen(outFile, "w"); 952 if (!save) { 953 fprintf(stderr, "Could not open output file %s\n", outFile); 954 return 5; 955 } 956 compiler.dump(save); 957 fclose(save); 958 } else { 959 int codeArgc = argc - i + 1; 960 char** codeArgv = argv + i - 1; 961 codeArgv[0] = (char*) (inFile ? inFile : "stdin"); 962 return compiler.run(codeArgc, codeArgv); 963 } 964 965 return 0; 966} 967