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