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