acc.cpp revision e7b590666dba83c72b7f7bf210dad7239ab04b4f
1/* 2 * Android "Almost" C Compiler. 3 * This is a compiler for a small subset of the C language, intended for use 4 * in scripting environments where speed and memory footprint are important. 5 * 6 * This code is based upon the "unobfuscated" version of the 7 * Obfuscated Tiny C compiler, and retains the 8 * original copyright notice and license from that compiler, see below. 9 * 10 */ 11 12/* 13 Obfuscated Tiny C Compiler 14 15 Copyright (C) 2001-2003 Fabrice Bellard 16 17 This software is provided 'as-is', without any express or implied 18 warranty. In no event will the authors be held liable for any damages 19 arising from the use of this software. 20 21 Permission is granted to anyone to use this software for any purpose, 22 including commercial applications, and to alter it and redistribute it 23 freely, subject to the following restrictions: 24 25 1. The origin of this software must not be misrepresented; you must not 26 claim that you wrote the original software. If you use this software 27 in a product, an acknowledgment in the product and its documentation 28 *is* required. 29 2. Altered source versions must be plainly marked as such, and must not be 30 misrepresented as being the original software. 31 3. This notice may not be removed or altered from any source distribution. 32 */ 33 34#include <ctype.h> 35#include <dlfcn.h> 36#include <stdarg.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40 41#if defined(__arm__) 42#include <unistd.h> 43#endif 44 45#if defined(__arm__) 46#define DEFAULT_ARM_CODEGEN 47#elif defined(__i386__) 48#define DEFAULT_X86_CODEGEN 49#elif defined(__x86_64__) 50#define DEFAULT_X64_CODEGEN 51#endif 52 53#define PROVIDE_X86_CODEGEN 54#define PROVIDE_ARM_CODEGEN 55 56#ifdef PROVIDE_ARM_CODEGEN 57#include "disassem.h" 58#endif 59 60namespace acc { 61 62class Compiler { 63 class CodeBuf { 64 char* ind; 65 char* pProgramBase; 66 67 void release() { 68 if (pProgramBase != 0) { 69 free(pProgramBase); 70 pProgramBase = 0; 71 } 72 } 73 74 public: 75 CodeBuf() { 76 pProgramBase = 0; 77 ind = 0; 78 } 79 80 ~CodeBuf() { 81 release(); 82 } 83 84 void init(int size) { 85 release(); 86 pProgramBase = (char*) calloc(1, size); 87 ind = pProgramBase; 88 } 89 90 int o4(int n) { 91 int result = (int) ind; 92 * (int*) ind = n; 93 ind += 4; 94 return result; 95 } 96 97 /* 98 * Output a byte. Handles all values, 0..ff. 99 */ 100 void ob(int n) { 101 *ind++ = n; 102 } 103 104 inline void* getBase() { 105 return (void*) pProgramBase; 106 } 107 108 int getSize() { 109 return ind - pProgramBase; 110 } 111 112 int getPC() { 113 return (int) ind; 114 } 115 }; 116 117 class CodeGenerator { 118 public: 119 CodeGenerator() {} 120 virtual ~CodeGenerator() {} 121 122 virtual void init(CodeBuf* pCodeBuf) { 123 this->pCodeBuf = pCodeBuf; 124 } 125 126 /* returns address to patch with local variable size 127 */ 128 virtual int functionEntry(int argCount) = 0; 129 130 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) = 0; 131 132 /* load immediate value */ 133 virtual void li(int t) = 0; 134 135 virtual int gjmp(int t) = 0; 136 137 /* l = 0: je, l == 1: jne */ 138 virtual int gtst(bool l, int t) = 0; 139 140 virtual void gcmp(int op) = 0; 141 142 virtual void genOp(int op) = 0; 143 144 virtual void clearECX() = 0; 145 146 virtual void pushEAX() = 0; 147 148 virtual void popECX() = 0; 149 150 virtual void storeEAXToAddressECX(bool isInt) = 0; 151 152 virtual void loadEAXIndirect(bool isInt) = 0; 153 154 virtual void leaEAX(int ea) = 0; 155 156 virtual void storeEAX(int ea) = 0; 157 158 virtual void loadEAX(int ea, bool isIncDec, int op) = 0; 159 160 virtual int beginFunctionCallArguments() = 0; 161 162 virtual void storeEAToArg(int l) = 0; 163 164 virtual void endFunctionCallArguments(int a, int l) = 0; 165 166 167 virtual int callForward(int symbol) = 0; 168 169 virtual void callRelative(int t) = 0; 170 171 virtual void callIndirect(int l) = 0; 172 173 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0; 174 175 virtual int disassemble(FILE* out) = 0; 176 177 /* output a symbol and patch all calls to it */ 178 virtual void gsym(int t) = 0; 179 180 virtual int finishCompile() { 181#if defined(__arm__) 182 const long base = long(pCodeBuf->getBase()); 183 const long curr = base + long(pCodeBuf->getSize()); 184 int err = cacheflush(base, curr, 0); 185 return err; 186#else 187 return 0; 188#endif 189 } 190 191 /** 192 * Adjust relative branches by this amount. 193 */ 194 virtual int jumpOffset() = 0; 195 196 protected: 197 /* 198 * Output a byte. Handles all values, 0..ff. 199 */ 200 void ob(int n) { 201 pCodeBuf->ob(n); 202 } 203 204 int o4(int data) { 205 return pCodeBuf->o4(data); 206 } 207 208 int getBase() { 209 return (int) pCodeBuf->getBase(); 210 } 211 212 int getPC() { 213 return pCodeBuf->getPC(); 214 } 215 private: 216 CodeBuf* pCodeBuf; 217 }; 218 219#ifdef PROVIDE_ARM_CODEGEN 220 221 class ARMCodeGenerator : public CodeGenerator { 222 public: 223 ARMCodeGenerator() {} 224 virtual ~ARMCodeGenerator() {} 225 226 /* returns address to patch with local variable size 227 */ 228 virtual int functionEntry(int argCount) { 229 fprintf(stderr, "functionEntry(%d);\n", argCount); 230 // sp -> arg4 arg5 ... 231 // Push our register-based arguments back on the stack 232 if (argCount > 0) { 233 int regArgCount = argCount <= 4 ? argCount : 4; 234 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {} 235 } 236 // sp -> arg0 arg1 ... 237 o4(0xE92D4800); // stmfd sp!, {fp, lr} 238 // sp, fp -> oldfp, retadr, arg0 arg1 .... 239 o4(0xE1A0B00D); // mov fp, sp 240 return o4(0xE24DD000); // sub sp, sp, # <local variables> 241 } 242 243 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) { 244 fprintf(stderr, "functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize); 245 // Patch local variable allocation code: 246 if (localVariableSize < 0 || localVariableSize > 255) { 247 error("localVariables out of range: %d", localVariableSize); 248 } 249 *(char*) (localVariableAddress) = localVariableSize; 250 251 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ... 252 o4(0xE1A0E00B); // mov lr, fp 253 o4(0xE59BB000); // ldr fp, [fp] 254 o4(0xE28ED004); // add sp, lr, #4 255 // sp -> retadr, arg0, ... 256 o4(0xE8BD4000); // ldmfd sp!, {lr} 257 // sp -> arg0 .... 258 if (argCount > 0) { 259 // We store the PC into the lr so we can adjust the sp before 260 // returning. We need to pull off the registers we pushed 261 // earlier. We don't need to actually store them anywhere, 262 // just adjust the stack. 263 int regArgCount = argCount <= 4 ? argCount : 4; 264 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2 265 } 266 o4(0xE12FFF1E); // bx lr 267 } 268 269 /* load immediate value */ 270 virtual void li(int t) { 271 fprintf(stderr, "li(%d);\n", t); 272 if (t >= 0 && t < 255) { 273 o4(0xE3A00000 + t); // mov r0, #0 274 } else if (t >= -256 && t < 0) { 275 // mvn means move constant ^ ~0 276 o4(0xE3E00001 - t); // mvn r0, #0 277 } else { 278 o4(0xE51F0000); // ldr r0, .L3 279 o4(0xEA000000); // b .L99 280 o4(t); // .L3: .word 0 281 // .L99: 282 } 283 } 284 285 virtual int gjmp(int t) { 286 fprintf(stderr, "gjmp(%d);\n", t); 287 return o4(0xEA000000 | encodeAddress(t)); // b .L33 288 } 289 290 /* l = 0: je, l == 1: jne */ 291 virtual int gtst(bool l, int t) { 292 fprintf(stderr, "gtst(%d, %d);\n", l, t); 293 o4(0xE3500000); // cmp r0,#0 294 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq 295 return o4(branch | encodeAddress(t)); 296 } 297 298 virtual void gcmp(int op) { 299 fprintf(stderr, "gcmp(%d);\n", op); 300 o4(0xE1510000); // cmp r1, r1 301 switch(op) { 302 case OP_EQUALS: 303 o4(0x03A00001); // moveq r0,#1 304 o4(0x13A00000); // movne r0,#0 305 break; 306 case OP_NOT_EQUALS: 307 o4(0x03A00000); // moveq r0,#0 308 o4(0x13A00001); // movne r0,#1 309 break; 310 case OP_LESS_EQUAL: 311 o4(0xD3A00001); // movle r0,#1 312 o4(0xC3A00000); // movgt r0,#0 313 break; 314 case OP_GREATER: 315 o4(0xD3A00000); // movle r0,#0 316 o4(0xC3A00001); // movgt r0,#1 317 break; 318 case OP_GREATER_EQUAL: 319 o4(0xA3A00001); // movge r0,#1 320 o4(0xB3A00000); // movlt r0,#0 321 break; 322 case OP_LESS: 323 o4(0xA3A00000); // movge r0,#0 324 o4(0xB3A00001); // movlt r0,#1 325 break; 326 default: 327 error("Unknown comparison op %d", op); 328 break; 329 } 330 } 331 332 virtual void genOp(int op) { 333 fprintf(stderr, "genOp(%d);\n", op); 334 switch(op) { 335 case OP_MUL: 336 o4(0x0E0000091); // mul r0,r1,r0 337 break; 338 case OP_DIV: 339 callRuntime(runtime_DIV); 340 break; 341 case OP_MOD: 342 callRuntime(runtime_MOD); 343 break; 344 case OP_PLUS: 345 o4(0xE0810000); // add r0,r1,r0 346 break; 347 case OP_MINUS: 348 o4(0xE0410000); // sub r0,r1,r0 349 break; 350 case OP_SHIFT_LEFT: 351 o4(0xE1A00011); // lsl r0,r1,r0 352 break; 353 case OP_SHIFT_RIGHT: 354 o4(0xE1A00051); // asr r0,r1,r0 355 break; 356 case OP_BIT_AND: 357 o4(0xE0010000); // and r0,r1,r0 358 break; 359 case OP_BIT_XOR: 360 o4(0xE0210000); // eor r0,r1,r0 361 break; 362 case OP_BIT_OR: 363 o4(0xE1810000); // orr r0,r1,r0 364 break; 365 case OP_BIT_NOT: 366 o4(0xE1E00000); // mvn r0, r0 367 break; 368 default: 369 error("Unimplemented op %d\n", op); 370 break; 371 } 372#if 0 373 o(decodeOp(op)); 374 if (op == OP_MOD) 375 o(0x92); /* xchg %edx, %eax */ 376#endif 377 } 378 379 virtual void clearECX() { 380 fprintf(stderr, "clearECX();\n"); 381 o4(0xE3A01000); // mov r1, #0 382 } 383 384 virtual void pushEAX() { 385 fprintf(stderr, "pushEAX();\n"); 386 o4(0xE92D0001); // stmfd sp!,{r0} 387 } 388 389 virtual void popECX() { 390 fprintf(stderr, "popECX();\n"); 391 o4(0xE8BD0002); // ldmfd sp!,{r1} 392 } 393 394 virtual void storeEAXToAddressECX(bool isInt) { 395 fprintf(stderr, "storeEAXToAddressECX(%d);\n", isInt); 396 if (isInt) { 397 o4(0xE5810000); // str r0, [r1] 398 } else { 399 o4(0xE5C10000); // strb r0, [r1] 400 } 401 } 402 403 virtual void loadEAXIndirect(bool isInt) { 404 fprintf(stderr, "loadEAXIndirect(%d);\n", isInt); 405 if (isInt) 406 o4(0xE5900000); // ldr r0, [r0] 407 else 408 o4(0xE5D00000); // ldrb r0, [r0] 409 } 410 411 virtual void leaEAX(int ea) { 412 fprintf(stderr, "leaEAX(%d);\n", ea); 413 if (ea < LOCAL) { 414 // Local, fp relative 415 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) { 416 error("Offset out of range: %08x", ea); 417 } 418 if (ea < 0) { 419 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea 420 } else { 421 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea 422 } 423 } else { 424 // Global, absolute. 425 o4(0xE59F0000); // ldr r0, .L1 426 o4(0xEA000000); // b .L99 427 o4(ea); // .L1: .word 0 428 // .L99: 429 } 430 } 431 432 virtual void storeEAX(int ea) { 433 fprintf(stderr, "storeEAX(%d);\n", ea); 434 if (ea < LOCAL) { 435 // Local, fp relative 436 if (ea < -4095 || ea > 4095) { 437 error("Offset out of range: %08x", ea); 438 } 439 if (ea < 0) { 440 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea] 441 } else { 442 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea] 443 } 444 } else{ 445 // Global, absolute 446 o4(0xE59F1000); // ldr r1, .L1 447 o4(0xEA000000); // b .L99 448 o4(ea); // .L1: .word 0 449 o4(0xE5810000); // .L99: str r0, [r1] 450 } 451 } 452 453 virtual void loadEAX(int ea, bool isIncDec, int op) { 454 fprintf(stderr, "loadEAX(%d, %d, %d);\n", ea, isIncDec, op); 455 if (ea < LOCAL) { 456 // Local, fp relative 457 if (ea < -4095 || ea > 4095) { 458 error("Offset out of range: %08x", ea); 459 } 460 if (ea < 0) { 461 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea] 462 } else { 463 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea] 464 } 465 } else { 466 // Global, absolute 467 o4(0xE59F2000); // ldr r2, .L1 468 o4(0xEA000000); // b .L99 469 o4(ea); // .L1: .word ea 470 o4(0xE5920000); // .L99: ldr r0, [r2] 471 } 472 473 if (isIncDec) { 474 switch (op) { 475 case OP_INCREMENT: 476 o4(0xE2801001); // add r1, r0, #1 477 break; 478 case OP_DECREMENT: 479 o4(0xE2401001); // sub r1, r0, #1 480 break; 481 default: 482 error("unknown opcode: %d", op); 483 } 484 if (ea < LOCAL) { 485 // Local, fp relative 486 // Don't need range check, was already checked above 487 if (ea < 0) { 488 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea] 489 } else { 490 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea] 491 } 492 } else{ 493 // Global, absolute 494 // r2 is already set up from before. 495 o4(0xE5821000); // str r1, [r2] 496 } 497 } 498 } 499 500 virtual int beginFunctionCallArguments() { 501 fprintf(stderr, "beginFunctionCallArguments();\n"); 502 return o4(0xE24DDF00); // Placeholder 503 } 504 505 virtual void storeEAToArg(int l) { 506 fprintf(stderr, "storeEAToArg(%d);\n", l); 507 if (l < 0 || l > 4096-4) { 508 error("l out of range for stack offset: 0x%08x", l); 509 } 510 o4(0xE58D0000 + l); // str r0, [sp, #4] 511 } 512 513 virtual void endFunctionCallArguments(int a, int l) { 514 fprintf(stderr, "endFunctionCallArguments(0x%08x, %d);\n", a, l); 515 if (l < 0 || l > 0x3FC) { 516 error("L out of range for stack adjustment: 0x%08x", l); 517 } 518 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2 519 int argCount = l >> 2; 520 if (argCount > 0) { 521 int regArgCount = argCount > 4 ? 4 : argCount; 522 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{} 523 } 524 } 525 526 virtual int callForward(int symbol) { 527 fprintf(stderr, "callForward(%d);\n", symbol); 528 // Forward calls are always short (local) 529 return o4(0xEB000000 | encodeAddress(symbol)); 530 } 531 532 virtual void callRelative(int t) { 533 fprintf(stderr, "callRelative(%d);\n", t); 534 int abs = t + getPC() + jumpOffset(); 535 fprintf(stderr, "abs=%d (0x%08x)\n", abs, abs); 536 if (t >= - (1 << 25) && t < (1 << 25)) { 537 o4(0xEB000000 | encodeAddress(t)); 538 } else { 539 // Long call. 540 o4(0xE59FC000); // ldr r12, .L1 541 o4(0xEA000000); // b .L99 542 o4(t - 12); // .L1: .word 0 543 o4(0xE08CC00F); // .L99: add r12,pc 544 o4(0xE12FFF3C); // blx r12 545 } 546 } 547 548 virtual void callIndirect(int l) { 549 fprintf(stderr, "callIndirect(%d);\n", l); 550 int argCount = l >> 2; 551 int poppedArgs = argCount > 4 ? 4 : argCount; 552 int adjustedL = l - (poppedArgs << 2); 553 if (adjustedL < 0 || adjustedL > 4096-4) { 554 error("l out of range for stack offset: 0x%08x", l); 555 } 556 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL] 557 o4(0xE12FFF3C); // blx r12 558 } 559 560 virtual void adjustStackAfterCall(int l, bool isIndirect) { 561 fprintf(stderr, "adjustStackAfterCall(%d, %d);\n", l, isIndirect); 562 int argCount = l >> 2; 563 int stackArgs = argCount > 4 ? argCount - 4 : 0; 564 int stackUse = stackArgs + (isIndirect ? 1 : 0); 565 if (stackUse) { 566 if (stackUse < 0 || stackUse > 255) { 567 error("L out of range for stack adjustment: 0x%08x", l); 568 } 569 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2 570 } 571 } 572 573 virtual int jumpOffset() { 574 return 8; 575 } 576 577 /* output a symbol and patch all calls to it */ 578 virtual void gsym(int t) { 579 fprintf(stderr, "gsym(0x%x)\n", t); 580 int n; 581 int base = getBase(); 582 int pc = getPC(); 583 fprintf(stderr, "pc = 0x%x\n", pc); 584 while (t) { 585 int data = * (int*) t; 586 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2); 587 if (decodedOffset == 0) { 588 n = 0; 589 } else { 590 n = base + decodedOffset; /* next value */ 591 } 592 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK) 593 | encodeRelAddress(pc - t - 8); 594 t = n; 595 } 596 } 597 598 virtual int disassemble(FILE* out) { 599 disasmOut = out; 600 disasm_interface_t di; 601 di.di_readword = disassemble_readword; 602 di.di_printaddr = disassemble_printaddr; 603 di.di_printf = disassemble_printf; 604 605 int base = getBase(); 606 int pc = getPC(); 607 for(int i = base; i < pc; i += 4) { 608 fprintf(out, "%08x: %08x ", i, *(int*) i); 609 ::disasm(&di, i, 0); 610 } 611 return 0; 612 } 613 614 private: 615 static FILE* disasmOut; 616 617 static u_int 618 disassemble_readword(u_int address) 619 { 620 return(*((u_int *)address)); 621 } 622 623 static void 624 disassemble_printaddr(u_int address) 625 { 626 fprintf(disasmOut, "0x%08x", address); 627 } 628 629 static void 630 disassemble_printf(const char *fmt, ...) { 631 va_list ap; 632 va_start(ap, fmt); 633 vfprintf(disasmOut, fmt, ap); 634 va_end(ap); 635 } 636 637 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff; 638 639 /** Encode a relative address that might also be 640 * a label. 641 */ 642 int encodeAddress(int value) { 643 int base = getBase(); 644 if (value >= base && value <= getPC() ) { 645 // This is a label, encode it relative to the base. 646 value = value - base; 647 } 648 return encodeRelAddress(value); 649 } 650 651 int encodeRelAddress(int value) { 652 return BRANCH_REL_ADDRESS_MASK & (value >> 2); 653 } 654 655 typedef int (*int2FnPtr)(int a, int b); 656 void callRuntime(int2FnPtr fn) { 657 o4(0xE59F2000); // ldr r2, .L1 658 o4(0xEA000000); // b .L99 659 o4((int) fn); //.L1: .word fn 660 o4(0xE12FFF32); //.L99: blx r2 661 } 662 663 static int runtime_DIV(int a, int b) { 664 return b / a; 665 } 666 667 static int runtime_MOD(int a, int b) { 668 return b % a; 669 } 670 671 void error(const char* fmt,...) { 672 va_list ap; 673 va_start(ap, fmt); 674 vfprintf(stderr, fmt, ap); 675 va_end(ap); 676 exit(12); 677 } 678 }; 679 680#endif // PROVIDE_X86_CODEGEN 681 682#ifdef PROVIDE_X86_CODEGEN 683 684 class X86CodeGenerator : public CodeGenerator { 685 public: 686 X86CodeGenerator() {} 687 virtual ~X86CodeGenerator() {} 688 689 /* returns address to patch with local variable size 690 */ 691 virtual int functionEntry(int argCount) { 692 o(0xe58955); /* push %ebp, mov %esp, %ebp */ 693 return oad(0xec81, 0); /* sub $xxx, %esp */ 694 } 695 696 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) { 697 o(0xc3c9); /* leave, ret */ 698 *(int *) localVariableAddress = localVariableSize; /* save local variables */ 699 } 700 701 /* load immediate value */ 702 virtual void li(int t) { 703 oad(0xb8, t); /* mov $xx, %eax */ 704 } 705 706 virtual int gjmp(int t) { 707 return psym(0xe9, t); 708 } 709 710 /* l = 0: je, l == 1: jne */ 711 virtual int gtst(bool l, int t) { 712 o(0x0fc085); /* test %eax, %eax, je/jne xxx */ 713 return psym(0x84 + l, t); 714 } 715 716 virtual void gcmp(int op) { 717 int t = decodeOp(op); 718 o(0xc139); /* cmp %eax,%ecx */ 719 li(0); 720 o(0x0f); /* setxx %al */ 721 o(t + 0x90); 722 o(0xc0); 723 } 724 725 virtual void genOp(int op) { 726 o(decodeOp(op)); 727 if (op == OP_MOD) 728 o(0x92); /* xchg %edx, %eax */ 729 } 730 731 virtual void clearECX() { 732 oad(0xb9, 0); /* movl $0, %ecx */ 733 } 734 735 virtual void pushEAX() { 736 o(0x50); /* push %eax */ 737 } 738 739 virtual void popECX() { 740 o(0x59); /* pop %ecx */ 741 } 742 743 virtual void storeEAXToAddressECX(bool isInt) { 744 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */ 745 } 746 747 virtual void loadEAXIndirect(bool isInt) { 748 if (isInt) 749 o(0x8b); /* mov (%eax), %eax */ 750 else 751 o(0xbe0f); /* movsbl (%eax), %eax */ 752 ob(0); /* add zero in code */ 753 } 754 755 virtual void leaEAX(int ea) { 756 gmov(10, ea); /* leal EA, %eax */ 757 } 758 759 virtual void storeEAX(int ea) { 760 gmov(6, ea); /* mov %eax, EA */ 761 } 762 763 virtual void loadEAX(int ea, bool isIncDec, int op) { 764 gmov(8, ea); /* mov EA, %eax */ 765 if (isIncDec) { 766 /* Implement post-increment or post decrement. 767 */ 768 gmov(0, ea); /* 83 ADD */ 769 o(decodeOp(op)); 770 } 771 } 772 773 virtual int beginFunctionCallArguments() { 774 return oad(0xec81, 0); /* sub $xxx, %esp */ 775 } 776 777 virtual void storeEAToArg(int l) { 778 oad(0x248489, l); /* movl %eax, xxx(%esp) */ 779 } 780 781 virtual void endFunctionCallArguments(int a, int l) { 782 * (int*) a = l; 783 } 784 785 virtual int callForward(int symbol) { 786 return psym(0xe8, symbol); /* call xxx */ 787 } 788 789 virtual void callRelative(int t) { 790 psym(0xe8, t); /* call xxx */ 791 } 792 793 virtual void callIndirect(int l) { 794 oad(0x2494ff, l); /* call *xxx(%esp) */ 795 } 796 797 virtual void adjustStackAfterCall(int l, bool isIndirect) { 798 if (isIndirect) { 799 l += 4; 800 } 801 oad(0xc481, l); /* add $xxx, %esp */ 802 } 803 804 virtual int jumpOffset() { 805 return 5; 806 } 807 808 virtual int disassemble(FILE* out) { 809 return 1; 810 } 811 812 /* output a symbol and patch all calls to it */ 813 virtual void gsym(int t) { 814 int n; 815 int pc = getPC(); 816 while (t) { 817 n = *(int *) t; /* next value */ 818 *(int *) t = pc - t - 4; 819 t = n; 820 } 821 } 822 823 private: 824 825 /** Output 1 to 4 bytes. 826 * 827 */ 828 void o(int n) { 829 /* cannot use unsigned, so we must do a hack */ 830 while (n && n != -1) { 831 ob(n & 0xff); 832 n = n >> 8; 833 } 834 } 835 836 /* psym is used to put an instruction with a data field which is a 837 reference to a symbol. It is in fact the same as oad ! */ 838 int psym(int n, int t) { 839 return oad(n, t); 840 } 841 842 /* instruction + address */ 843 int oad(int n, int t) { 844 o(n); 845 int result = getPC(); 846 o4(t); 847 return result; 848 } 849 850 851 static const int operatorHelper[]; 852 853 int decodeOp(int op) { 854 if (op < 0 || op > OP_COUNT) { 855 fprintf(stderr, "Out-of-range operator: %d\n", op); 856 exit(1); 857 } 858 return operatorHelper[op]; 859 } 860 861 void gmov(int l, int t) { 862 o(l + 0x83); 863 oad((t < LOCAL) << 7 | 5, t); 864 } 865 }; 866 867#endif // PROVIDE_X86_CODEGEN 868 869 /* vars: value of variables 870 loc : local variable index 871 glo : global variable index 872 ind : output code ptr 873 rsym: return symbol 874 prog: output code 875 dstk: define stack 876 dptr, dch: macro state 877 */ 878 int tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk, 879 dptr, dch, last_id; 880 void* pSymbolBase; 881 void* pGlobalBase; 882 void* pVarsBase; 883 FILE* file; 884 885 CodeBuf codeBuf; 886 CodeGenerator* pGen; 887 888 static const int ALLOC_SIZE = 99999; 889 890 /* depends on the init string */ 891 static const int TOK_STR_SIZE = 48; 892 static const int TOK_IDENT = 0x100; 893 static const int TOK_INT = 0x100; 894 static const int TOK_IF = 0x120; 895 static const int TOK_ELSE = 0x138; 896 static const int TOK_WHILE = 0x160; 897 static const int TOK_BREAK = 0x190; 898 static const int TOK_RETURN = 0x1c0; 899 static const int TOK_FOR = 0x1f8; 900 static const int TOK_DEFINE = 0x218; 901 static const int TOK_MAIN = 0x250; 902 903 static const int TOK_DUMMY = 1; 904 static const int TOK_NUM = 2; 905 906 static const int LOCAL = 0x200; 907 908 static const int SYM_FORWARD = 0; 909 static const int SYM_DEFINE = 1; 910 911 /* tokens in string heap */ 912 static const int TAG_TOK = ' '; 913 static const int TAG_MACRO = 2; 914 915 static const int OP_INCREMENT = 0; 916 static const int OP_DECREMENT = 1; 917 static const int OP_MUL = 2; 918 static const int OP_DIV = 3; 919 static const int OP_MOD = 4; 920 static const int OP_PLUS = 5; 921 static const int OP_MINUS = 6; 922 static const int OP_SHIFT_LEFT = 7; 923 static const int OP_SHIFT_RIGHT = 8; 924 static const int OP_LESS_EQUAL = 9; 925 static const int OP_GREATER_EQUAL = 10; 926 static const int OP_LESS = 11; 927 static const int OP_GREATER = 12; 928 static const int OP_EQUALS = 13; 929 static const int OP_NOT_EQUALS = 14; 930 static const int OP_LOGICAL_AND = 15; 931 static const int OP_LOGICAL_OR = 16; 932 static const int OP_BIT_AND = 17; 933 static const int OP_BIT_XOR = 18; 934 static const int OP_BIT_OR = 19; 935 static const int OP_BIT_NOT = 20; 936 static const int OP_LOGICAL_NOT = 21; 937 static const int OP_COUNT = 22; 938 939 /* Operators are searched from front, the two-character operators appear 940 * before the single-character operators with the same first character. 941 * @ is used to pad out single-character operators. 942 */ 943 static const char* operatorChars; 944 static const char operatorLevel[]; 945 946 void pdef(int t) { 947 *(char *) dstk++ = t; 948 } 949 950 void inp() { 951 if (dptr) { 952 ch = *(char *) dptr++; 953 if (ch == TAG_MACRO) { 954 dptr = 0; 955 ch = dch; 956 } 957 } else 958 ch = fgetc(file); 959 /* printf("ch=%c 0x%x\n", ch, ch); */ 960 } 961 962 int isid() { 963 return isalnum(ch) | (ch == '_'); 964 } 965 966 /* read a character constant */ 967 void getq() { 968 if (ch == '\\') { 969 inp(); 970 if (ch == 'n') 971 ch = '\n'; 972 } 973 } 974 975 void next() { 976 int l, a; 977 978 while (isspace(ch) | (ch == '#')) { 979 if (ch == '#') { 980 inp(); 981 next(); 982 if (tok == TOK_DEFINE) { 983 next(); 984 pdef(TAG_TOK); /* fill last ident tag */ 985 *(int *) tok = SYM_DEFINE; 986 *(int *) (tok + 4) = dstk; /* define stack */ 987 } 988 /* well we always save the values ! */ 989 while (ch != '\n') { 990 pdef(ch); 991 inp(); 992 } 993 pdef(ch); 994 pdef(TAG_MACRO); 995 } 996 inp(); 997 } 998 tokl = 0; 999 tok = ch; 1000 /* encode identifiers & numbers */ 1001 if (isid()) { 1002 pdef(TAG_TOK); 1003 last_id = dstk; 1004 while (isid()) { 1005 pdef(ch); 1006 inp(); 1007 } 1008 if (isdigit(tok)) { 1009 tokc = strtol((char*) last_id, 0, 0); 1010 tok = TOK_NUM; 1011 } else { 1012 *(char *) dstk = TAG_TOK; /* no need to mark end of string (we 1013 suppose data is initialized to zero by calloc) */ 1014 tok = (int) (strstr((char*) sym_stk, (char*) (last_id - 1)) 1015 - sym_stk); 1016 *(char *) dstk = 0; /* mark real end of ident for dlsym() */ 1017 tok = tok * 8 + TOK_IDENT; 1018 if (tok > TOK_DEFINE) { 1019 tok = vars + tok; 1020 /* printf("tok=%s %x\n", last_id, tok); */ 1021 /* define handling */ 1022 if (*(int *) tok == SYM_DEFINE) { 1023 dptr = *(int *) (tok + 4); 1024 dch = ch; 1025 inp(); 1026 next(); 1027 } 1028 } 1029 } 1030 } else { 1031 inp(); 1032 if (tok == '\'') { 1033 tok = TOK_NUM; 1034 getq(); 1035 tokc = ch; 1036 inp(); 1037 inp(); 1038 } else if ((tok == '/') & (ch == '*')) { 1039 inp(); 1040 while (ch) { 1041 while (ch != '*') 1042 inp(); 1043 inp(); 1044 if (ch == '/') 1045 ch = 0; 1046 } 1047 inp(); 1048 next(); 1049 } else if ((tok == '/') & (ch == '/')) { 1050 inp(); 1051 while (ch && (ch != '\n')) { 1052 inp(); 1053 } 1054 inp(); 1055 next(); 1056 } else { 1057 const char* t = operatorChars; 1058 int opIndex = 0; 1059 while ((l = *t++) != 0) { 1060 a = *t++; 1061 tokl = operatorLevel[opIndex]; 1062 tokc = opIndex; 1063 if ((l == tok) & ((a == ch) | (a == '@'))) { 1064#if 0 1065 printf("%c%c -> tokl=%d tokc=0x%x\n", 1066 l, a, tokl, tokc); 1067#endif 1068 if (a == ch) { 1069 inp(); 1070 tok = TOK_DUMMY; /* dummy token for double tokens */ 1071 } 1072 break; 1073 } 1074 opIndex++; 1075 } 1076 if (l == 0) { 1077 tokl = 0; 1078 tokc = 0; 1079 } 1080 } 1081 } 1082#if 0 1083 { 1084 int p; 1085 1086 printf("tok=0x%x ", tok); 1087 if (tok >= TOK_IDENT) { 1088 printf("'"); 1089 if (tok> TOK_DEFINE) 1090 p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8; 1091 else 1092 p = sym_stk + 1 + (tok - TOK_IDENT) / 8; 1093 while (*(char *)p != TAG_TOK && *(char *)p) 1094 printf("%c", *(char *)p++); 1095 printf("'\n"); 1096 } else if (tok == TOK_NUM) { 1097 printf("%d\n", tokc); 1098 } else { 1099 printf("'%c'\n", tok); 1100 } 1101 } 1102#endif 1103 } 1104 1105 void error(const char *fmt, ...) { 1106 va_list ap; 1107 1108 va_start(ap, fmt); 1109 fprintf(stderr, "%ld: ", ftell((FILE *) file)); 1110 vfprintf(stderr, fmt, ap); 1111 fprintf(stderr, "\n"); 1112 va_end(ap); 1113 exit(1); 1114 } 1115 1116 void skip(int c) { 1117 if (tok != c) { 1118 error("'%c' expected", c); 1119 } 1120 next(); 1121 } 1122 1123 /* l is one if '=' parsing wanted (quick hack) */ 1124 void unary(int l) { 1125 int n, t, a, c; 1126 t = 0; 1127 n = 1; /* type of expression 0 = forward, 1 = value, other = 1128 lvalue */ 1129 if (tok == '\"') { 1130 pGen->li(glo); 1131 while (ch != '\"') { 1132 getq(); 1133 *(char *) glo++ = ch; 1134 inp(); 1135 } 1136 *(char *) glo = 0; 1137 glo = (glo + 4) & -4; /* align heap */ 1138 inp(); 1139 next(); 1140 } else { 1141 c = tokl; 1142 a = tokc; 1143 t = tok; 1144 next(); 1145 if (t == TOK_NUM) { 1146 pGen->li(a); 1147 } else if (c == 2) { 1148 /* -, +, !, ~ */ 1149 unary(0); 1150 pGen->clearECX(); 1151 if (t == '!') 1152 pGen->gcmp(a); 1153 else 1154 pGen->genOp(a); 1155 } else if (t == '(') { 1156 expr(); 1157 skip(')'); 1158 } else if (t == '*') { 1159 /* parse cast */ 1160 skip('('); 1161 t = tok; /* get type */ 1162 next(); /* skip int/char/void */ 1163 next(); /* skip '*' or '(' */ 1164 if (tok == '*') { 1165 /* function type */ 1166 skip('*'); 1167 skip(')'); 1168 skip('('); 1169 skip(')'); 1170 t = 0; 1171 } 1172 skip(')'); 1173 unary(0); 1174 if (tok == '=') { 1175 next(); 1176 pGen->pushEAX(); 1177 expr(); 1178 pGen->popECX(); 1179 pGen->storeEAXToAddressECX(t == TOK_INT); 1180 } else if (t) { 1181 pGen->loadEAXIndirect(t == TOK_INT); 1182 } 1183 } else if (t == '&') { 1184 pGen->leaEAX(*(int *) tok); 1185 next(); 1186 } else { 1187 n = *(int *) t; 1188 /* forward reference: try dlsym */ 1189 if (!n) { 1190 n = (int) dlsym(RTLD_DEFAULT, (char*) last_id); 1191 } 1192 if ((tok == '=') & l) { 1193 /* assignment */ 1194 next(); 1195 expr(); 1196 pGen->storeEAX(n); 1197 } else if (tok != '(') { 1198 /* variable */ 1199 pGen->loadEAX(n, tokl == 11, tokc); 1200 if (tokl == 11) { 1201 next(); 1202 } 1203 } 1204 } 1205 } 1206 1207 /* function call */ 1208 if (tok == '(') { 1209 if (n == 1) 1210 pGen->pushEAX(); 1211 1212 /* push args and invert order */ 1213 a = pGen->beginFunctionCallArguments(); 1214 next(); 1215 l = 0; 1216 while (tok != ')') { 1217 expr(); 1218 pGen->storeEAToArg(l); 1219 if (tok == ',') 1220 next(); 1221 l = l + 4; 1222 } 1223 pGen->endFunctionCallArguments(a, l); 1224 next(); 1225 if (!n) { 1226 /* forward reference */ 1227 t = t + 4; 1228 *(int *) t = pGen->callForward(*(int *) t); 1229 } else if (n == 1) { 1230 pGen->callIndirect(l); 1231 } else { 1232 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset()); 1233 } 1234 if (l | (n == 1)) 1235 pGen->adjustStackAfterCall(l, n == 1); 1236 } 1237 } 1238 1239 void sum(int l) { 1240 int t, n, a; 1241 t = 0; 1242 if (l-- == 1) 1243 unary(1); 1244 else { 1245 sum(l); 1246 a = 0; 1247 while (l == tokl) { 1248 n = tok; 1249 t = tokc; 1250 next(); 1251 1252 if (l > 8) { 1253 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */ 1254 sum(l); 1255 } else { 1256 pGen->pushEAX(); 1257 sum(l); 1258 pGen->popECX(); 1259 1260 if ((l == 4) | (l == 5)) { 1261 pGen->gcmp(t); 1262 } else { 1263 pGen->genOp(t); 1264 } 1265 } 1266 } 1267 /* && and || output code generation */ 1268 if (a && l > 8) { 1269 a = pGen->gtst(t == OP_LOGICAL_OR, a); 1270 pGen->li(t != OP_LOGICAL_OR); 1271 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */ 1272 pGen->gsym(a); 1273 pGen->li(t == OP_LOGICAL_OR); 1274 } 1275 } 1276 } 1277 1278 void expr() { 1279 sum(11); 1280 } 1281 1282 int test_expr() { 1283 expr(); 1284 return pGen->gtst(0, 0); 1285 } 1286 1287 void block(int l) { 1288 int a, n, t; 1289 1290 if (tok == TOK_IF) { 1291 next(); 1292 skip('('); 1293 a = test_expr(); 1294 skip(')'); 1295 block(l); 1296 if (tok == TOK_ELSE) { 1297 next(); 1298 n = pGen->gjmp(0); /* jmp */ 1299 pGen->gsym(a); 1300 block(l); 1301 pGen->gsym(n); /* patch else jmp */ 1302 } else { 1303 pGen->gsym(a); /* patch if test */ 1304 } 1305 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) { 1306 t = tok; 1307 next(); 1308 skip('('); 1309 if (t == TOK_WHILE) { 1310 n = codeBuf.getPC(); // top of loop, target of "next" iteration 1311 a = test_expr(); 1312 } else { 1313 if (tok != ';') 1314 expr(); 1315 skip(';'); 1316 n = codeBuf.getPC(); 1317 a = 0; 1318 if (tok != ';') 1319 a = test_expr(); 1320 skip(';'); 1321 if (tok != ')') { 1322 t = pGen->gjmp(0); 1323 expr(); 1324 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); 1325 pGen->gsym(t); 1326 n = t + 4; 1327 } 1328 } 1329 skip(')'); 1330 block((int) &a); 1331 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */ 1332 pGen->gsym(a); 1333 } else if (tok == '{') { 1334 next(); 1335 /* declarations */ 1336 decl(1); 1337 while (tok != '}') 1338 block(l); 1339 next(); 1340 } else { 1341 if (tok == TOK_RETURN) { 1342 next(); 1343 if (tok != ';') 1344 expr(); 1345 rsym = pGen->gjmp(rsym); /* jmp */ 1346 } else if (tok == TOK_BREAK) { 1347 next(); 1348 *(int *) l = pGen->gjmp(*(int *) l); 1349 } else if (tok != ';') 1350 expr(); 1351 skip(';'); 1352 } 1353 } 1354 1355 /* 'l' is true if local declarations */ 1356 void decl(int l) { 1357 int a; 1358 1359 while ((tok == TOK_INT) | ((tok != -1) & (!l))) { 1360 if (tok == TOK_INT) { 1361 next(); 1362 while (tok != ';') { 1363 if (l) { 1364 loc = loc + 4; 1365 *(int *) tok = -loc; 1366 } else { 1367 *(int *) tok = glo; 1368 glo = glo + 4; 1369 } 1370 next(); 1371 if (tok == ',') 1372 next(); 1373 } 1374 skip(';'); 1375 } else { 1376 /* patch forward references (XXX: do not work for function 1377 pointers) */ 1378 pGen->gsym(*(int *) (tok + 4)); 1379 /* put function address */ 1380 *(int *) tok = codeBuf.getPC(); 1381 next(); 1382 skip('('); 1383 a = 8; 1384 int argCount = 0; 1385 while (tok != ')') { 1386 /* read param name and compute offset */ 1387 *(int *) tok = a; 1388 a = a + 4; 1389 next(); 1390 if (tok == ',') 1391 next(); 1392 argCount++; 1393 } 1394 next(); /* skip ')' */ 1395 rsym = loc = 0; 1396 a = pGen->functionEntry(argCount); 1397 block(0); 1398 pGen->gsym(rsym); 1399 pGen->functionExit(argCount, a, loc); 1400 } 1401 } 1402 } 1403 1404 void cleanup() { 1405 if (sym_stk != 0) { 1406 free((void*) sym_stk); 1407 sym_stk = 0; 1408 } 1409 if (pGlobalBase != 0) { 1410 free((void*) pGlobalBase); 1411 pGlobalBase = 0; 1412 } 1413 if (pVarsBase != 0) { 1414 free(pVarsBase); 1415 pVarsBase = 0; 1416 } 1417 if (pGen) { 1418 delete pGen; 1419 pGen = 0; 1420 } 1421 } 1422 1423 void clear() { 1424 tok = 0; 1425 tokc = 0; 1426 tokl = 0; 1427 ch = 0; 1428 vars = 0; 1429 rsym = 0; 1430 loc = 0; 1431 glo = 0; 1432 sym_stk = 0; 1433 dstk = 0; 1434 dptr = 0; 1435 dch = 0; 1436 last_id = 0; 1437 file = 0; 1438 pGlobalBase = 0; 1439 pVarsBase = 0; 1440 pGen = 0; 1441 } 1442 1443 void setArchitecture(const char* architecture) { 1444 delete pGen; 1445 pGen = 0; 1446 1447 if (architecture != NULL) { 1448 if (strcmp(architecture, "arm") == 0) { 1449#ifdef PROVIDE_ARM_CODEGEN 1450 pGen = new ARMCodeGenerator(); 1451#else 1452 fprintf(stderr, "Unsupported architecture %s", architecture); 1453#endif 1454 } else if (strcmp(architecture, "x86") == 0) { 1455#ifdef PROVIDE_X86_CODEGEN 1456 pGen = new X86CodeGenerator(); 1457#else 1458 fprintf(stderr, "Unsupported architecture %s", architecture); 1459#endif 1460 } else { 1461 fprintf(stderr, "Unknown architecture %s", architecture); 1462 } 1463 } 1464 1465 if (pGen == NULL) { 1466#if defined(DEFAULT_ARM_CODEGEN) 1467 pGen = new ARMCodeGenerator(); 1468#elif defined(DEFAULT_X86_CODEGEN) 1469 pGen = new X86CodeGenerator(); 1470#endif 1471 } 1472 if (pGen == NULL) { 1473 fprintf(stderr, "No code generator defined."); 1474 } 1475 } 1476 1477public: 1478 struct args { 1479 args() { 1480 architecture = 0; 1481 } 1482 const char* architecture; 1483 }; 1484 1485 Compiler() { 1486 clear(); 1487 } 1488 1489 ~Compiler() { 1490 cleanup(); 1491 } 1492 1493 int compile(FILE* in, args& args) { 1494 cleanup(); 1495 clear(); 1496 codeBuf.init(ALLOC_SIZE); 1497 setArchitecture(args.architecture); 1498 pGen->init(&codeBuf); 1499 file = in; 1500 sym_stk = (int) calloc(1, ALLOC_SIZE); 1501 dstk = (int) strcpy((char*) sym_stk, 1502 " int if else while break return for define main ") 1503 + TOK_STR_SIZE; 1504 pGlobalBase = calloc(1, ALLOC_SIZE); 1505 glo = (int) pGlobalBase; 1506 pVarsBase = calloc(1, ALLOC_SIZE); 1507 vars = (int) pVarsBase; 1508 inp(); 1509 next(); 1510 decl(0); 1511 pGen->finishCompile(); 1512 return 0; 1513 } 1514 1515 int run(int argc, char** argv) { 1516 typedef int (*mainPtr)(int argc, char** argv); 1517 mainPtr aMain = (mainPtr) *(int*) (vars + TOK_MAIN); 1518 if (!aMain) { 1519 fprintf(stderr, "Could not find function \"main\".\n"); 1520 return -1; 1521 } 1522 return aMain(argc, argv); 1523 } 1524 1525 int dump(FILE* out) { 1526 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out); 1527 return 0; 1528 } 1529 1530 int disassemble(FILE* out) { 1531 return pGen->disassemble(out); 1532 } 1533 1534}; 1535 1536const char* Compiler::operatorChars = 1537 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@"; 1538 1539const char Compiler::operatorLevel[] = 1540 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 1541 5, 5, /* ==, != */ 1542 9, 10, /* &&, || */ 1543 6, 7, 8, /* & ^ | */ 1544 2, 2 /* ~ ! */ 1545 }; 1546 1547FILE* Compiler::ARMCodeGenerator::disasmOut; 1548 1549const int Compiler::X86CodeGenerator::operatorHelper[] = { 1550 0x1, // ++ 1551 0xff, // -- 1552 0xc1af0f, // * 1553 0xf9f79991, // / 1554 0xf9f79991, // % (With manual assist to swap results) 1555 0xc801, // + 1556 0xd8f7c829, // - 1557 0xe0d391, // << 1558 0xf8d391, // >> 1559 0xe, // <= 1560 0xd, // >= 1561 0xc, // < 1562 0xf, // > 1563 0x4, // == 1564 0x5, // != 1565 0x0, // && 1566 0x1, // || 1567 0xc821, // & 1568 0xc831, // ^ 1569 0xc809, // | 1570 0xd0f7, // ~ 1571 0x4 // ! 1572}; 1573 1574} // namespace acc 1575 1576// This is a separate function so it can easily be set by breakpoint in gdb. 1577int run(acc::Compiler& c, int argc, char** argv) { 1578 return c.run(argc, argv); 1579} 1580 1581int main(int argc, char** argv) { 1582 bool doDump = false; 1583 bool doDisassemble = false; 1584 const char* inFile = NULL; 1585 const char* outFile = NULL; 1586 const char* architecture = NULL; 1587 int i; 1588 for (i = 1; i < argc; i++) { 1589 char* arg = argv[i]; 1590 if (arg[0] == '-') { 1591 switch (arg[1]) { 1592 case 'a': 1593 if (i + 1 >= argc) { 1594 fprintf(stderr, "Expected architecture after -a\n"); 1595 return 2; 1596 } 1597 architecture = argv[i+1]; 1598 i += 1; 1599 break; 1600 case 'd': 1601 if (i + 1 >= argc) { 1602 fprintf(stderr, "Expected filename after -d\n"); 1603 return 2; 1604 } 1605 doDump = true; 1606 outFile = argv[i + 1]; 1607 i += 1; 1608 break; 1609 case 'S': 1610 doDisassemble = true; 1611 break; 1612 default: 1613 fprintf(stderr, "Unrecognized flag %s\n", arg); 1614 return 3; 1615 } 1616 } else if (inFile == NULL) { 1617 inFile = arg; 1618 } else { 1619 break; 1620 } 1621 } 1622 1623 FILE* in = stdin; 1624 if (inFile) { 1625 in = fopen(inFile, "r"); 1626 if (!in) { 1627 fprintf(stderr, "Could not open input file %s\n", inFile); 1628 return 1; 1629 } 1630 } 1631 acc::Compiler compiler; 1632 acc::Compiler::args args; 1633 if (architecture != NULL) { 1634 args.architecture = architecture; 1635 } 1636 int compileResult = compiler.compile(in, args); 1637 if (in != stdin) { 1638 fclose(in); 1639 } 1640 if (compileResult) { 1641 fprintf(stderr, "Compile failed: %d\n", compileResult); 1642 return 6; 1643 } 1644 if (doDisassemble) { 1645 compiler.disassemble(stderr); 1646 } 1647 if (doDump) { 1648 FILE* save = fopen(outFile, "w"); 1649 if (!save) { 1650 fprintf(stderr, "Could not open output file %s\n", outFile); 1651 return 5; 1652 } 1653 compiler.dump(save); 1654 fclose(save); 1655 } else { 1656 fprintf(stderr, "Executing compiled code:\n"); 1657 int codeArgc = argc - i + 1; 1658 char** codeArgv = argv + i - 1; 1659 codeArgv[0] = (char*) (inFile ? inFile : "stdin"); 1660 int result = run(compiler, codeArgc, codeArgv); 1661 fprintf(stderr, "result: %d\n", result); 1662 return result; 1663 } 1664 1665 return 0; 1666} 1667