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