acc.cpp revision 61de31feff2c2507531064a3f330cf97dea4df6c
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, see the file LICENSE for details.
8 *
9 */
10
11#define LOG_TAG "acc"
12#include <cutils/log.h>
13
14#include <ctype.h>
15#include <errno.h>
16#include <limits.h>
17#include <stdarg.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23
24#include <cutils/hashmap.h>
25
26#if defined(__i386__)
27#include <sys/mman.h>
28#endif
29
30
31#if defined(__arm__)
32#define DEFAULT_ARM_CODEGEN
33#define PROVIDE_ARM_CODEGEN
34#elif defined(__i386__)
35#define DEFAULT_X86_CODEGEN
36#define PROVIDE_X86_CODEGEN
37#elif defined(__x86_64__)
38#define DEFAULT_X64_CODEGEN
39#define PROVIDE_X64_CODEGEN
40#endif
41
42#ifdef PROVIDE_ARM_CODEGEN
43#include "disassem.h"
44#endif
45
46#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
47#define ARM_USE_VFP
48#endif
49
50#include <acc/acc.h>
51
52#define LOG_API(...) do {} while(0)
53// #define LOG_API(...) fprintf (stderr, __VA_ARGS__)
54
55#define LOG_STACK(...) do {} while(0)
56// #define LOG_STACK(...) fprintf (stderr, __VA_ARGS__)
57
58#define ENABLE_ARM_DISASSEMBLY
59// #define PROVIDE_TRACE_CODEGEN
60
61// Uncomment to save input to a text file in DEBUG_DUMP_PATTERN
62// #define DEBUG_SAVE_INPUT_TO_FILE
63
64#ifdef ARM_USE_VFP
65#define DEBUG_DUMP_PATTERN "/sdcard/acc_dump/%d.c"
66#else
67#define DEBUG_DUMP_PATTERN "/tmp/acc_dump/%d.c"
68#endif
69
70#define assert(b) assertImpl(b, __LINE__)
71
72namespace acc {
73
74// Subset of STL vector.
75template<class E> class Vector {
76    public:
77    Vector() {
78        mpBase = 0;
79        mUsed = 0;
80        mSize = 0;
81    }
82
83    ~Vector() {
84        if (mpBase) {
85            for(size_t i = 0; i < mUsed; i++)  {
86                mpBase[mUsed].~E();
87            }
88            free(mpBase);
89        }
90    }
91
92    inline E& operator[](size_t i) {
93        return mpBase[i];
94    }
95
96    inline E& front() {
97        return mpBase[0];
98    }
99
100    inline E& back() {
101        return mpBase[mUsed - 1];
102    }
103
104    void pop_back() {
105        mUsed -= 1;
106        mpBase[mUsed].~E();
107    }
108
109    void push_back(const E& item) {
110        * ensure(1) = item;
111    }
112
113    size_t size() {
114        return mUsed;
115    }
116
117private:
118    E* ensure(int n) {
119        size_t newUsed = mUsed + n;
120        if (newUsed > mSize) {
121            size_t newSize = mSize * 2 + 10;
122            if (newSize < newUsed) {
123                newSize = newUsed;
124            }
125            mpBase = (E*) realloc(mpBase, sizeof(E) * newSize);
126            mSize = newSize;
127        }
128        E* result = mpBase + mUsed;
129        mUsed = newUsed;
130        return result;
131    }
132
133    E* mpBase;
134    size_t mUsed;
135    size_t mSize;
136};
137
138class ErrorSink {
139public:
140    void error(const char *fmt, ...) {
141        va_list ap;
142        va_start(ap, fmt);
143        verror(fmt, ap);
144        va_end(ap);
145    }
146
147    virtual ~ErrorSink() {}
148    virtual void verror(const char* fmt, va_list ap) = 0;
149};
150
151class Compiler : public ErrorSink {
152    typedef int tokenid_t;
153    enum TypeTag {
154        TY_INT,       // 0
155        TY_CHAR,      // 1
156        TY_SHORT,     // 2
157        TY_VOID,      // 3
158        TY_FLOAT,     // 4
159        TY_DOUBLE,    // 5
160        TY_POINTER,   // 6
161        TY_ARRAY,     // 7
162        TY_STRUCT,    // 8
163        TY_FUNC,      // 9
164        TY_PARAM      // 10
165    };
166
167    struct Type {
168        TypeTag tag;
169        tokenid_t id; // For function arguments, global vars, local vars, struct elements
170        tokenid_t structTag; // For structs the name of the struct
171        int length; // length of array, offset of struct element. -1 means struct is forward defined
172        int alignment; // for structs only
173        Type* pHead; // For a struct this is the prototype struct.
174        Type* pTail;
175    };
176
177    enum ExpressionType {
178        ET_RVALUE,
179        ET_LVALUE
180    };
181
182    struct ExpressionValue {
183        ExpressionValue() {
184            et = ET_RVALUE;
185            pType = NULL;
186        }
187        ExpressionType et;
188        Type* pType;
189    };
190
191    class CodeBuf {
192        char* ind; // Output code pointer
193        char* pProgramBase;
194        ErrorSink* mErrorSink;
195        int mSize;
196        bool mOverflowed;
197
198        void release() {
199            if (pProgramBase != 0) {
200                free(pProgramBase);
201                pProgramBase = 0;
202            }
203        }
204
205        bool check(int n) {
206            int newSize = ind - pProgramBase + n;
207            bool overflow = newSize > mSize;
208            if (overflow && !mOverflowed) {
209                mOverflowed = true;
210                if (mErrorSink) {
211                    mErrorSink->error("Code too large: %d bytes", newSize);
212                }
213            }
214            return overflow;
215        }
216
217    public:
218        CodeBuf() {
219            pProgramBase = 0;
220            ind = 0;
221            mErrorSink = 0;
222            mSize = 0;
223            mOverflowed = false;
224        }
225
226        ~CodeBuf() {
227            release();
228        }
229
230        void init(int size) {
231            release();
232            mSize = size;
233            pProgramBase = (char*) calloc(1, size);
234            ind = pProgramBase;
235        }
236
237        void setErrorSink(ErrorSink* pErrorSink) {
238            mErrorSink = pErrorSink;
239        }
240
241        int o4(int n) {
242            if(check(4)) {
243                return 0;
244            }
245            intptr_t result = (intptr_t) ind;
246            * (int*) ind = n;
247            ind += 4;
248            return result;
249        }
250
251        /*
252         * Output a byte. Handles all values, 0..ff.
253         */
254        void ob(int n) {
255            if(check(1)) {
256                return;
257            }
258            *ind++ = n;
259        }
260
261        inline void* getBase() {
262            return (void*) pProgramBase;
263        }
264
265        intptr_t getSize() {
266            return ind - pProgramBase;
267        }
268
269        intptr_t getPC() {
270            return (intptr_t) ind;
271        }
272    };
273
274    /**
275     * A code generator creates an in-memory program, generating the code on
276     * the fly. There is one code generator implementation for each supported
277     * architecture.
278     *
279     * The code generator implements the following abstract machine:
280     * R0 - the accumulator.
281     * FP - a frame pointer for accessing function arguments and local
282     *      variables.
283     * SP - a stack pointer for storing intermediate results while evaluating
284     *      expressions. The stack pointer grows downwards.
285     *
286     * The function calling convention is that all arguments are placed on the
287     * stack such that the first argument has the lowest address.
288     * After the call, the result is in R0. The caller is responsible for
289     * removing the arguments from the stack.
290     * The R0 register is not saved across function calls. The
291     * FP and SP registers are saved.
292     */
293
294    class CodeGenerator {
295    public:
296        CodeGenerator() {
297            mErrorSink = 0;
298            pCodeBuf = 0;
299            pushType();
300        }
301        virtual ~CodeGenerator() {}
302
303        virtual void init(CodeBuf* pCodeBuf) {
304            this->pCodeBuf = pCodeBuf;
305            pCodeBuf->setErrorSink(mErrorSink);
306        }
307
308        virtual void setErrorSink(ErrorSink* pErrorSink) {
309            mErrorSink = pErrorSink;
310            if (pCodeBuf) {
311                pCodeBuf->setErrorSink(mErrorSink);
312            }
313        }
314
315        /* Give the code generator some utility types so it can
316         * use its own types as needed for the results of some
317         * operations like gcmp.
318         */
319
320        void setTypes(Type* pInt) {
321            mkpInt = pInt;
322        }
323
324        /* Emit a function prolog.
325         * pDecl is the function declaration, which gives the arguments.
326         * Save the old value of the FP.
327         * Set the new value of the FP.
328         * Convert from the native platform calling convention to
329         * our stack-based calling convention. This may require
330         * pushing arguments from registers to the stack.
331         * Allocate "N" bytes of stack space. N isn't known yet, so
332         * just emit the instructions for adjusting the stack, and return
333         * the address to patch up. The patching will be done in
334         * functionExit().
335         * returns address to patch with local variable size.
336        */
337        virtual int functionEntry(Type* pDecl) = 0;
338
339        /* Emit a function epilog.
340         * Restore the old SP and FP register values.
341         * Return to the calling function.
342         * argCount - the number of arguments to the function.
343         * localVariableAddress - returned from functionEntry()
344         * localVariableSize - the size in bytes of the local variables.
345         */
346        virtual void functionExit(Type* pDecl, int localVariableAddress,
347                                  int localVariableSize) = 0;
348
349        /* load immediate value to R0 */
350        virtual void li(int i) = 0;
351
352        /* Load floating point value from global address. */
353        virtual void loadFloat(int address, Type* pType) = 0;
354
355        /* Add the struct offset in bytes to R0, change the type to pType */
356        virtual void addStructOffsetR0(int offset, Type* pType) = 0;
357
358        /* Jump to a target, and return the address of the word that
359         * holds the target data, in case it needs to be fixed up later.
360         */
361        virtual int gjmp(int t) = 0;
362
363        /* Test R0 and jump to a target if the test succeeds.
364         * l = 0: je, l == 1: jne
365         * Return the address of the word that holds the targed data, in
366         * case it needs to be fixed up later.
367         */
368        virtual int gtst(bool l, int t) = 0;
369
370        /* Compare TOS against R0, and store the boolean result in R0.
371         * Pops TOS.
372         * op specifies the comparison.
373         */
374        virtual void gcmp(int op) = 0;
375
376        /* Perform the arithmetic op specified by op. TOS is the
377         * left argument, R0 is the right argument.
378         * Pops TOS.
379         */
380        virtual void genOp(int op) = 0;
381
382        /* Compare 0 against R0, and store the boolean result in R0.
383         * op specifies the comparison.
384         */
385        virtual void gUnaryCmp(int op) = 0;
386
387        /* Perform the arithmetic op specified by op. 0 is the
388         * left argument, R0 is the right argument.
389         */
390        virtual void genUnaryOp(int op) = 0;
391
392        /* Push R0 onto the stack. (Also known as "dup" for duplicate.)
393         */
394        virtual void pushR0() = 0;
395
396        /* Turn R0, TOS into R0 TOS R0 */
397
398        virtual void over() = 0;
399
400        /* Pop R0 from the stack. (Also known as "drop")
401         */
402        virtual void popR0() = 0;
403
404        /* Store R0 to the address stored in TOS.
405         * The TOS is popped.
406         */
407        virtual void storeR0ToTOS() = 0;
408
409        /* Load R0 from the address stored in R0.
410         */
411        virtual void loadR0FromR0() = 0;
412
413        /* Load the absolute address of a variable to R0.
414         * If ea <= LOCAL, then this is a local variable, or an
415         * argument, addressed relative to FP.
416         * else it is an absolute global address.
417         *
418         * et is ET_RVALUE for things like string constants, ET_LVALUE for
419         * variables.
420         */
421        virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) = 0;
422
423        /* Load the pc-relative address of a forward-referenced variable to R0.
424         * Return the address of the 4-byte constant so that it can be filled
425         * in later.
426         */
427        virtual int leaForward(int ea, Type* pPointerType) = 0;
428
429        /**
430         * Convert R0 to the given type.
431         */
432
433        void convertR0(Type* pType) {
434            convertR0Imp(pType, false);
435        }
436
437        void castR0(Type* pType) {
438            convertR0Imp(pType, true);
439        }
440
441        virtual void convertR0Imp(Type* pType, bool isCast) = 0;
442
443        /* Emit code to adjust the stack for a function call. Return the
444         * label for the address of the instruction that adjusts the
445         * stack size. This will be passed as argument "a" to
446         * endFunctionCallArguments.
447         */
448        virtual int beginFunctionCallArguments() = 0;
449
450        /* Emit code to store R0 to the stack at byte offset l.
451         * Returns stack size of object (typically 4 or 8 bytes)
452         */
453        virtual size_t storeR0ToArg(int l, Type* pArgType) = 0;
454
455        /* Patch the function call preamble.
456         * a is the address returned from beginFunctionCallArguments
457         * l is the number of bytes the arguments took on the stack.
458         * Typically you would also emit code to convert the argument
459         * list into whatever the native function calling convention is.
460         * On ARM for example you would pop the first 5 arguments into
461         * R0..R4
462         */
463        virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0;
464
465        /* Emit a call to an unknown function. The argument "symbol" needs to
466         * be stored in the location where the address should go. It forms
467         * a chain. The address will be patched later.
468         * Return the address of the word that has to be patched.
469         */
470        virtual int callForward(int symbol, Type* pFunc) = 0;
471
472        /* Call a function pointer. L is the number of bytes the arguments
473         * take on the stack. The address of the function is stored at
474         * location SP + l.
475         */
476        virtual void callIndirect(int l, Type* pFunc) = 0;
477
478        /* Adjust SP after returning from a function call. l is the
479         * number of bytes of arguments stored on the stack. isIndirect
480         * is true if this was an indirect call. (In which case the
481         * address of the function is stored at location SP + l.)
482         */
483        virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0;
484
485        /* Print a disassembly of the assembled code to out. Return
486         * non-zero if there is an error.
487         */
488        virtual int disassemble(FILE* out) = 0;
489
490        /* Generate a symbol at the current PC. t is the head of a
491         * linked list of addresses to patch.
492         */
493        virtual void gsym(int t) = 0;
494
495        /* Resolve a forward reference function at the current PC.
496         * t is the head of a
497         * linked list of addresses to patch.
498         * (Like gsym, but using absolute address, not PC relative address.)
499         */
500        virtual void resolveForward(int t) = 0;
501
502        /*
503         * Do any cleanup work required at the end of a compile.
504         * For example, an instruction cache might need to be
505         * invalidated.
506         * Return non-zero if there is an error.
507         */
508        virtual int finishCompile() = 0;
509
510        /**
511         * Adjust relative branches by this amount.
512         */
513        virtual int jumpOffset() = 0;
514
515        /**
516         * Memory alignment (in bytes) for this type of data
517         */
518        virtual size_t alignmentOf(Type* type) = 0;
519
520        /**
521         * Array element alignment (in bytes) for this type of data.
522         */
523        virtual size_t sizeOf(Type* type) = 0;
524
525        virtual Type* getR0Type() {
526            return mExpressionStack.back().pType;
527        }
528
529        virtual ExpressionType getR0ExpressionType() {
530            return mExpressionStack.back().et;
531        }
532
533        virtual void setR0ExpressionType(ExpressionType et) {
534            mExpressionStack.back().et = et;
535        }
536
537        virtual size_t getExpressionStackDepth() {
538            return mExpressionStack.size();
539        }
540
541        virtual void forceR0RVal() {
542            if (getR0ExpressionType() == ET_LVALUE) {
543                loadR0FromR0();
544            }
545        }
546
547    protected:
548        /*
549         * Output a byte. Handles all values, 0..ff.
550         */
551        void ob(int n) {
552            pCodeBuf->ob(n);
553        }
554
555        intptr_t o4(int data) {
556            return pCodeBuf->o4(data);
557        }
558
559        intptr_t getBase() {
560            return (intptr_t) pCodeBuf->getBase();
561        }
562
563        intptr_t getPC() {
564            return pCodeBuf->getPC();
565        }
566
567        intptr_t getSize() {
568            return pCodeBuf->getSize();
569        }
570
571        void error(const char* fmt,...) {
572            va_list ap;
573            va_start(ap, fmt);
574            mErrorSink->verror(fmt, ap);
575            va_end(ap);
576        }
577
578        void assertImpl(bool test, int line) {
579            if (!test) {
580                error("code generator assertion failed at line %s:%d.", __FILE__, line);
581                LOGD("code generator assertion failed at line %s:%d.", __FILE__, line);
582                * (char*) 0 = 0;
583            }
584        }
585
586        void setR0Type(Type* pType) {
587            assert(pType != NULL);
588            mExpressionStack.back().pType = pType;
589            mExpressionStack.back().et = ET_RVALUE;
590        }
591
592        void setR0Type(Type* pType, ExpressionType et) {
593            assert(pType != NULL);
594            mExpressionStack.back().pType = pType;
595            mExpressionStack.back().et = et;
596        }
597
598        Type* getTOSType() {
599            return mExpressionStack[mExpressionStack.size()-2].pType;
600        }
601
602        void pushType() {
603            if (mExpressionStack.size()) {
604                mExpressionStack.push_back(mExpressionStack.back());
605            } else {
606                mExpressionStack.push_back(ExpressionValue());
607            }
608
609        }
610
611        void overType() {
612            size_t size = mExpressionStack.size();
613            if (size >= 2) {
614                mExpressionStack.push_back(mExpressionStack.back());
615                mExpressionStack[size-1] = mExpressionStack[size-2];
616                mExpressionStack[size-2] = mExpressionStack[size];
617            }
618        }
619
620        void popType() {
621            mExpressionStack.pop_back();
622        }
623
624        bool bitsSame(Type* pA, Type* pB) {
625            return collapseType(pA->tag) == collapseType(pB->tag);
626        }
627
628        TypeTag collapseType(TypeTag tag) {
629            static const TypeTag collapsedTag[] = {
630                    TY_INT,
631                    TY_INT,
632                    TY_INT,
633                    TY_VOID,
634                    TY_FLOAT,
635                    TY_DOUBLE,
636                    TY_INT,
637                    TY_INT,
638                    TY_VOID,
639                    TY_VOID,
640                    TY_VOID
641                };
642            return collapsedTag[tag];
643        }
644
645        TypeTag collapseTypeR0() {
646            return collapseType(getR0Type()->tag);
647        }
648
649        static bool isFloatType(Type* pType) {
650            return isFloatTag(pType->tag);
651        }
652
653        static bool isFloatTag(TypeTag tag) {
654            return tag == TY_FLOAT || tag == TY_DOUBLE;
655        }
656
657        static bool isPointerType(Type* pType) {
658            return isPointerTag(pType->tag);
659        }
660
661        static bool isPointerTag(TypeTag tag) {
662            return tag == TY_POINTER || tag == TY_ARRAY;
663        }
664
665        Type* getPointerArithmeticResultType(Type* a, Type* b) {
666            TypeTag aTag = a->tag;
667            TypeTag bTag = b->tag;
668            if (aTag == TY_POINTER) {
669                return a;
670            }
671            if (bTag == TY_POINTER) {
672                return b;
673            }
674            if (aTag == TY_ARRAY) {
675                return a->pTail;
676            }
677            if (bTag == TY_ARRAY) {
678                return b->pTail;
679            }
680            return NULL;
681        }
682        Type* mkpInt;
683
684    private:
685        Vector<ExpressionValue> mExpressionStack;
686        CodeBuf* pCodeBuf;
687        ErrorSink* mErrorSink;
688    };
689
690#ifdef PROVIDE_ARM_CODEGEN
691
692    class ARMCodeGenerator : public CodeGenerator {
693    public:
694        ARMCodeGenerator() {
695#ifdef ARM_USE_VFP
696            LOGD("Using ARM VFP hardware floating point.");
697#else
698            LOGD("Using ARM soft floating point.");
699#endif
700        }
701
702        virtual ~ARMCodeGenerator() {}
703
704        /* returns address to patch with local variable size
705        */
706        virtual int functionEntry(Type* pDecl) {
707            mStackUse = 0;
708            // sp -> arg4 arg5 ...
709            // Push our register-based arguments back on the stack
710            int regArgCount = calcRegArgCount(pDecl);
711            if (regArgCount > 0) {
712                mStackUse += regArgCount * 4;
713                o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd    sp!, {}
714            }
715            // sp -> arg0 arg1 ...
716            o4(0xE92D4800); // stmfd sp!, {fp, lr}
717            mStackUse += 2 * 4;
718            // sp, fp -> oldfp, retadr, arg0 arg1 ....
719            o4(0xE1A0B00D); // mov    fp, sp
720            LOG_STACK("functionEntry: %d\n", mStackUse);
721            return o4(0xE24DD000); // sub    sp, sp, # <local variables>
722            // We don't know how many local variables we are going to use,
723            // but we will round the allocation up to a multiple of
724            // STACK_ALIGNMENT, so it won't affect the stack alignment.
725        }
726
727        virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
728            // Round local variable size up to a multiple of stack alignment
729            localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) /
730                STACK_ALIGNMENT) * STACK_ALIGNMENT;
731            // Patch local variable allocation code:
732            if (localVariableSize < 0 || localVariableSize > 255) {
733                error("localVariables out of range: %d", localVariableSize);
734            }
735            *(char*) (localVariableAddress) = localVariableSize;
736
737#ifdef ARM_USE_VFP
738            {
739                Type* pReturnType = pDecl->pHead;
740                switch(pReturnType->tag) {
741                case TY_FLOAT:
742                    o4(0xEE170A90); // fmrs    r0, s15
743                    break;
744                case TY_DOUBLE:
745                    o4(0xEC510B17); // fmrrd r0, r1, d7
746                    break;
747                default:
748                    break;
749                }
750            }
751#endif
752
753            // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ...
754            o4(0xE1A0E00B); // mov lr, fp
755            o4(0xE59BB000); // ldr fp, [fp]
756            o4(0xE28ED004); // add sp, lr, #4
757            // sp -> retadr, arg0, ...
758            o4(0xE8BD4000); // ldmfd    sp!, {lr}
759            // sp -> arg0 ....
760
761            // We store the PC into the lr so we can adjust the sp before
762            // returning. We need to pull off the registers we pushed
763            // earlier. We don't need to actually store them anywhere,
764            // just adjust the stack.
765            int regArgCount = calcRegArgCount(pDecl);
766            if (regArgCount) {
767                o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2
768            }
769            o4(0xE12FFF1E); // bx lr
770        }
771
772        /* load immediate value */
773        virtual void li(int t) {
774            liReg(t, 0);
775            setR0Type(mkpInt);
776        }
777
778        virtual void loadFloat(int address, Type* pType) {
779            setR0Type(pType);
780            // Global, absolute address
781            o4(0xE59F0000); //        ldr r0, .L1
782            o4(0xEA000000); //        b .L99
783            o4(address);         // .L1:   .word ea
784                                 // .L99:
785
786            switch (pType->tag) {
787            case TY_FLOAT:
788#ifdef ARM_USE_VFP
789                o4(0xEDD07A00);      // flds    s15, [r0]
790#else
791                o4(0xE5900000);      // ldr r0, [r0]
792#endif
793                break;
794            case TY_DOUBLE:
795#ifdef ARM_USE_VFP
796                o4(0xED907B00);      // fldd    d7, [r0]
797#else
798                o4(0xE1C000D0);      // ldrd r0, [r0]
799#endif
800                break;
801            default:
802                assert(false);
803                break;
804            }
805        }
806
807
808        virtual void addStructOffsetR0(int offset, Type* pType) {
809            if (offset) {
810                size_t immediate = 0;
811                if (encode12BitImmediate(offset, &immediate)) {
812                    o4(0xE2800000 | immediate); // add    r0, r0, #offset
813                } else {
814                    error("structure offset out of range: %d", offset);
815                }
816            }
817            setR0Type(pType, ET_LVALUE);
818        }
819
820        virtual int gjmp(int t) {
821            return o4(0xEA000000 | encodeAddress(t)); // b .L33
822        }
823
824        /* l = 0: je, l == 1: jne */
825        virtual int gtst(bool l, int t) {
826            Type* pR0Type = getR0Type();
827            TypeTag tagR0 = pR0Type->tag;
828            switch(tagR0) {
829                case TY_FLOAT:
830#ifdef ARM_USE_VFP
831                    o4(0xEEF57A40); // fcmpzs    s15
832                    o4(0xEEF1FA10); // fmstat
833#else
834                    callRuntime((void*) runtime_is_non_zero_f);
835                    o4(0xE3500000); // cmp r0,#0
836#endif
837                    break;
838                case TY_DOUBLE:
839#ifdef ARM_USE_VFP
840                    o4(0xEEB57B40); // fcmpzd    d7
841                    o4(0xEEF1FA10); // fmstat
842#else
843                    callRuntime((void*) runtime_is_non_zero_d);
844                    o4(0xE3500000); // cmp r0,#0
845#endif
846                    break;
847                default:
848                    o4(0xE3500000); // cmp r0,#0
849                    break;
850            }
851            int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq
852            return o4(branch | encodeAddress(t));
853        }
854
855        virtual void gcmp(int op) {
856            Type* pR0Type = getR0Type();
857            Type* pTOSType = getTOSType();
858            TypeTag tagR0 = collapseType(pR0Type->tag);
859            TypeTag tagTOS = collapseType(pTOSType->tag);
860            if (tagR0 == TY_INT && tagTOS == TY_INT) {
861                setupIntPtrArgs();
862                o4(0xE1510000); // cmp r1, r1
863                switch(op) {
864                case OP_EQUALS:
865                    o4(0x03A00001); // moveq r0,#1
866                    o4(0x13A00000); // movne r0,#0
867                    break;
868                case OP_NOT_EQUALS:
869                    o4(0x03A00000); // moveq r0,#0
870                    o4(0x13A00001); // movne r0,#1
871                    break;
872                case OP_LESS_EQUAL:
873                    o4(0xD3A00001); // movle r0,#1
874                    o4(0xC3A00000); // movgt r0,#0
875                    break;
876                case OP_GREATER:
877                    o4(0xD3A00000); // movle r0,#0
878                    o4(0xC3A00001); // movgt r0,#1
879                    break;
880                case OP_GREATER_EQUAL:
881                    o4(0xA3A00001); // movge r0,#1
882                    o4(0xB3A00000); // movlt r0,#0
883                    break;
884                case OP_LESS:
885                    o4(0xA3A00000); // movge r0,#0
886                    o4(0xB3A00001); // movlt r0,#1
887                    break;
888                default:
889                    error("Unknown comparison op %d", op);
890                    break;
891                }
892            } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) {
893                setupDoubleArgs();
894#ifdef ARM_USE_VFP
895                o4(0xEEB46BC7); //         fcmped    d6, d7
896                   o4(0xEEF1FA10); // fmstat
897                switch(op) {
898                case OP_EQUALS:
899                    o4(0x03A00001); // moveq r0,#1
900                    o4(0x13A00000); // movne r0,#0
901                    break;
902                case OP_NOT_EQUALS:
903                    o4(0x03A00000); // moveq r0,#0
904                    o4(0x13A00001); // movne r0,#1
905                    break;
906                case OP_LESS_EQUAL:
907                    o4(0xD3A00001); // movle r0,#1
908                    o4(0xC3A00000); // movgt r0,#0
909                    break;
910                case OP_GREATER:
911                    o4(0xD3A00000); // movle r0,#0
912                    o4(0xC3A00001); // movgt r0,#1
913                    break;
914                case OP_GREATER_EQUAL:
915                    o4(0xA3A00001); // movge r0,#1
916                    o4(0xB3A00000); // movlt r0,#0
917                    break;
918                case OP_LESS:
919                    o4(0xA3A00000); // movge r0,#0
920                    o4(0xB3A00001); // movlt r0,#1
921                    break;
922                default:
923                    error("Unknown comparison op %d", op);
924                    break;
925                }
926#else
927                switch(op) {
928                    case OP_EQUALS:
929                        callRuntime((void*) runtime_cmp_eq_dd);
930                        break;
931                    case OP_NOT_EQUALS:
932                        callRuntime((void*) runtime_cmp_ne_dd);
933                        break;
934                    case OP_LESS_EQUAL:
935                        callRuntime((void*) runtime_cmp_le_dd);
936                        break;
937                    case OP_GREATER:
938                        callRuntime((void*) runtime_cmp_gt_dd);
939                        break;
940                    case OP_GREATER_EQUAL:
941                        callRuntime((void*) runtime_cmp_ge_dd);
942                        break;
943                    case OP_LESS:
944                        callRuntime((void*) runtime_cmp_lt_dd);
945                        break;
946                    default:
947                        error("Unknown comparison op %d", op);
948                        break;
949                }
950#endif
951            } else {
952                setupFloatArgs();
953#ifdef ARM_USE_VFP
954                o4(0xEEB47AE7); // fcmpes s14, s15
955                   o4(0xEEF1FA10); // fmstat
956                switch(op) {
957                case OP_EQUALS:
958                    o4(0x03A00001); // moveq r0,#1
959                    o4(0x13A00000); // movne r0,#0
960                    break;
961                case OP_NOT_EQUALS:
962                    o4(0x03A00000); // moveq r0,#0
963                    o4(0x13A00001); // movne r0,#1
964                    break;
965                case OP_LESS_EQUAL:
966                    o4(0xD3A00001); // movle r0,#1
967                    o4(0xC3A00000); // movgt r0,#0
968                    break;
969                case OP_GREATER:
970                    o4(0xD3A00000); // movle r0,#0
971                    o4(0xC3A00001); // movgt r0,#1
972                    break;
973                case OP_GREATER_EQUAL:
974                    o4(0xA3A00001); // movge r0,#1
975                    o4(0xB3A00000); // movlt r0,#0
976                    break;
977                case OP_LESS:
978                    o4(0xA3A00000); // movge r0,#0
979                    o4(0xB3A00001); // movlt r0,#1
980                    break;
981                default:
982                    error("Unknown comparison op %d", op);
983                    break;
984                }
985#else
986                switch(op) {
987                    case OP_EQUALS:
988                        callRuntime((void*) runtime_cmp_eq_ff);
989                        break;
990                    case OP_NOT_EQUALS:
991                        callRuntime((void*) runtime_cmp_ne_ff);
992                        break;
993                    case OP_LESS_EQUAL:
994                        callRuntime((void*) runtime_cmp_le_ff);
995                        break;
996                    case OP_GREATER:
997                        callRuntime((void*) runtime_cmp_gt_ff);
998                        break;
999                    case OP_GREATER_EQUAL:
1000                        callRuntime((void*) runtime_cmp_ge_ff);
1001                        break;
1002                    case OP_LESS:
1003                        callRuntime((void*) runtime_cmp_lt_ff);
1004                        break;
1005                    default:
1006                        error("Unknown comparison op %d", op);
1007                        break;
1008                }
1009#endif
1010            }
1011            setR0Type(mkpInt);
1012        }
1013
1014        virtual void genOp(int op) {
1015            Type* pR0Type = getR0Type();
1016            Type* pTOSType = getTOSType();
1017            TypeTag tagR0 = pR0Type->tag;
1018            TypeTag tagTOS = pTOSType->tag;
1019            bool isFloatR0 = isFloatTag(tagR0);
1020            bool isFloatTOS = isFloatTag(tagTOS);
1021            if (!isFloatR0 && !isFloatTOS) {
1022                setupIntPtrArgs();
1023                bool isPtrR0 = isPointerTag(tagR0);
1024                bool isPtrTOS = isPointerTag(tagTOS);
1025                if (isPtrR0 || isPtrTOS) {
1026                    if (isPtrR0 && isPtrTOS) {
1027                        if (op != OP_MINUS) {
1028                            error("Unsupported pointer-pointer operation %d.", op);
1029                        }
1030                        if (! typeEqual(pR0Type, pTOSType)) {
1031                            error("Incompatible pointer types for subtraction.");
1032                        }
1033                        o4(0xE0410000); // sub     r0,r1,r0
1034                        setR0Type(mkpInt);
1035                        int size = sizeOf(pR0Type->pHead);
1036                        if (size != 1) {
1037                            pushR0();
1038                            li(size);
1039                            // TODO: Optimize for power-of-two.
1040                            genOp(OP_DIV);
1041                        }
1042                    } else {
1043                        if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
1044                            error("Unsupported pointer-scalar operation %d", op);
1045                        }
1046                        Type* pPtrType = getPointerArithmeticResultType(
1047                                pR0Type, pTOSType);
1048                        int size = sizeOf(pPtrType->pHead);
1049                        if (size != 1) {
1050                            // TODO: Optimize for power-of-two.
1051                            liReg(size, 2);
1052                            if (isPtrR0) {
1053                                o4(0x0E0010192); // mul     r1,r2,r1
1054                            } else {
1055                                o4(0x0E0000092); // mul     r0,r2,r0
1056                            }
1057                        }
1058                        switch(op) {
1059                            case OP_PLUS:
1060                            o4(0xE0810000); // add     r0,r1,r0
1061                            break;
1062                            case OP_MINUS:
1063                            o4(0xE0410000); // sub     r0,r1,r0
1064                            break;
1065                        }
1066                        setR0Type(pPtrType);
1067                    }
1068                } else {
1069                    switch(op) {
1070                        case OP_MUL:
1071                        o4(0x0E0000091); // mul     r0,r1,r0
1072                        break;
1073                        case OP_DIV:
1074                        callRuntime((void*) runtime_DIV);
1075                        break;
1076                        case OP_MOD:
1077                        callRuntime((void*) runtime_MOD);
1078                        break;
1079                        case OP_PLUS:
1080                        o4(0xE0810000); // add     r0,r1,r0
1081                        break;
1082                        case OP_MINUS:
1083                        o4(0xE0410000); // sub     r0,r1,r0
1084                        break;
1085                        case OP_SHIFT_LEFT:
1086                        o4(0xE1A00011); // lsl     r0,r1,r0
1087                        break;
1088                        case OP_SHIFT_RIGHT:
1089                        o4(0xE1A00051); // asr     r0,r1,r0
1090                        break;
1091                        case OP_BIT_AND:
1092                        o4(0xE0010000); // and     r0,r1,r0
1093                        break;
1094                        case OP_BIT_XOR:
1095                        o4(0xE0210000); // eor     r0,r1,r0
1096                        break;
1097                        case OP_BIT_OR:
1098                        o4(0xE1810000); // orr     r0,r1,r0
1099                        break;
1100                        case OP_BIT_NOT:
1101                        o4(0xE1E00000); // mvn     r0, r0
1102                        break;
1103                        default:
1104                        error("Unimplemented op %d\n", op);
1105                        break;
1106                    }
1107                }
1108            } else {
1109                Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
1110                if (pResultType->tag == TY_DOUBLE) {
1111                    setupDoubleArgs();
1112
1113                    switch(op) {
1114                    case OP_MUL:
1115#ifdef ARM_USE_VFP
1116                        o4(0xEE267B07); // fmuld d7, d6, d7
1117#else
1118                        callRuntime((void*) runtime_op_mul_dd);
1119#endif
1120                        break;
1121                    case OP_DIV:
1122#ifdef ARM_USE_VFP
1123                        o4(0xEE867B07); // fdivd d7, d6, d7
1124#else
1125                        callRuntime((void*) runtime_op_div_dd);
1126#endif
1127                        break;
1128                    case OP_PLUS:
1129#ifdef ARM_USE_VFP
1130                        o4(0xEE367B07); // faddd d7, d6, d7
1131#else
1132                        callRuntime((void*) runtime_op_add_dd);
1133#endif
1134                        break;
1135                    case OP_MINUS:
1136#ifdef ARM_USE_VFP
1137                        o4(0xEE367B47); // fsubd d7, d6, d7
1138#else
1139                        callRuntime((void*) runtime_op_sub_dd);
1140#endif
1141                        break;
1142                    default:
1143                        error("Unsupported binary floating operation %d\n", op);
1144                        break;
1145                    }
1146                } else {
1147                    setupFloatArgs();
1148                    switch(op) {
1149                    case OP_MUL:
1150#ifdef ARM_USE_VFP
1151                        o4(0xEE677A27); // fmuls s15, s14, s15
1152#else
1153                        callRuntime((void*) runtime_op_mul_ff);
1154#endif
1155                        break;
1156                    case OP_DIV:
1157#ifdef ARM_USE_VFP
1158                        o4(0xEEC77A27); // fdivs s15, s14, s15
1159#else
1160                        callRuntime((void*) runtime_op_div_ff);
1161#endif
1162                        break;
1163                    case OP_PLUS:
1164#ifdef ARM_USE_VFP
1165                        o4(0xEE777A27); // fadds s15, s14, s15
1166#else
1167                        callRuntime((void*) runtime_op_add_ff);
1168#endif
1169                        break;
1170                    case OP_MINUS:
1171#ifdef ARM_USE_VFP
1172                        o4(0xEE777A67); // fsubs s15, s14, s15
1173#else
1174                        callRuntime((void*) runtime_op_sub_ff);
1175#endif
1176                        break;
1177                    default:
1178                        error("Unsupported binary floating operation %d\n", op);
1179                        break;
1180                    }
1181                }
1182                setR0Type(pResultType);
1183            }
1184        }
1185
1186        virtual void gUnaryCmp(int op) {
1187            if (op != OP_LOGICAL_NOT) {
1188                error("Unknown unary cmp %d", op);
1189            } else {
1190                Type* pR0Type = getR0Type();
1191                TypeTag tag = collapseType(pR0Type->tag);
1192                switch(tag) {
1193                    case TY_INT:
1194                        o4(0xE3A01000); // mov    r1, #0
1195                        o4(0xE1510000); // cmp r1, r0
1196                        o4(0x03A00001); // moveq r0,#1
1197                        o4(0x13A00000); // movne r0,#0
1198                        break;
1199                    case TY_FLOAT:
1200#ifdef ARM_USE_VFP
1201                        o4(0xEEF57A40); // fcmpzs s15
1202                        o4(0xEEF1FA10); // fmstat
1203                        o4(0x03A00001); // moveq r0,#1
1204                        o4(0x13A00000); // movne r0,#0
1205#else
1206                        callRuntime((void*) runtime_is_zero_f);
1207#endif
1208                        break;
1209                    case TY_DOUBLE:
1210#ifdef ARM_USE_VFP
1211                        o4(0xEEB57B40); // fcmpzd d7
1212                        o4(0xEEF1FA10); // fmstat
1213                        o4(0x03A00001); // moveq r0,#1
1214                        o4(0x13A00000); // movne r0,#0
1215#else
1216                        callRuntime((void*) runtime_is_zero_d);
1217#endif
1218                        break;
1219                    default:
1220                        error("gUnaryCmp unsupported type");
1221                        break;
1222                }
1223            }
1224            setR0Type(mkpInt);
1225        }
1226
1227        virtual void genUnaryOp(int op) {
1228            Type* pR0Type = getR0Type();
1229            TypeTag tag = collapseType(pR0Type->tag);
1230            switch(tag) {
1231                case TY_INT:
1232                    switch(op) {
1233                    case OP_MINUS:
1234                        o4(0xE3A01000);  // mov    r1, #0
1235                        o4(0xE0410000);  // sub     r0,r1,r0
1236                        break;
1237                    case OP_BIT_NOT:
1238                        o4(0xE1E00000);  // mvn     r0, r0
1239                        break;
1240                    default:
1241                        error("Unknown unary op %d\n", op);
1242                        break;
1243                    }
1244                    break;
1245                case TY_FLOAT:
1246                case TY_DOUBLE:
1247                    switch (op) {
1248                        case OP_MINUS:
1249                            if (tag == TY_FLOAT) {
1250#ifdef ARM_USE_VFP
1251                                o4(0xEEF17A67); // fnegs    s15, s15
1252#else
1253                                callRuntime((void*) runtime_op_neg_f);
1254#endif
1255                            } else {
1256#ifdef ARM_USE_VFP
1257                                o4(0xEEB17B47); // fnegd    d7, d7
1258#else
1259                                callRuntime((void*) runtime_op_neg_d);
1260#endif
1261                            }
1262                            break;
1263                        case OP_BIT_NOT:
1264                            error("Can't apply '~' operator to a float or double.");
1265                            break;
1266                        default:
1267                            error("Unknown unary op %d\n", op);
1268                            break;
1269                        }
1270                    break;
1271                default:
1272                    error("genUnaryOp unsupported type");
1273                    break;
1274            }
1275        }
1276
1277        virtual void pushR0() {
1278            Type* pR0Type = getR0Type();
1279            TypeTag r0ct = collapseType(pR0Type->tag);
1280
1281#ifdef ARM_USE_VFP
1282            switch (r0ct ) {
1283            case TY_FLOAT:
1284                o4(0xED6D7A01); // fstmfds   sp!,{s15}
1285                mStackUse += 4;
1286                break;
1287            case TY_DOUBLE:
1288                o4(0xED2D7B02); // fstmfdd   sp!,{d7}
1289                mStackUse += 8;
1290                break;
1291            default:
1292                o4(0xE92D0001);  // stmfd   sp!,{r0}
1293                mStackUse += 4;
1294            }
1295#else
1296
1297            if (r0ct != TY_DOUBLE) {
1298                    o4(0xE92D0001);  // stmfd   sp!,{r0}
1299                    mStackUse += 4;
1300            } else {
1301                    o4(0xE92D0003);  // stmfd   sp!,{r0,r1}
1302                    mStackUse += 8;
1303            }
1304#endif
1305            pushType();
1306            LOG_STACK("pushR0: %d\n", mStackUse);
1307        }
1308
1309        virtual void over() {
1310            // We know it's only used for int-ptr ops (++/--)
1311
1312            Type* pR0Type = getR0Type();
1313            TypeTag r0ct = collapseType(pR0Type->tag);
1314
1315            Type* pTOSType = getTOSType();
1316            TypeTag tosct = collapseType(pTOSType->tag);
1317
1318            assert (r0ct == TY_INT  && tosct == TY_INT);
1319
1320            o4(0xE8BD0002);  // ldmfd   sp!,{r1}
1321            o4(0xE92D0001);  // stmfd   sp!,{r0}
1322            o4(0xE92D0002);  // stmfd   sp!,{r1}
1323            overType();
1324            mStackUse += 4;
1325        }
1326
1327        virtual void popR0() {
1328            Type* pTOSType = getTOSType();
1329            TypeTag tosct = collapseType(pTOSType->tag);
1330#ifdef ARM_USE_VFP
1331            if (tosct == TY_FLOAT || tosct == TY_DOUBLE) {
1332                error("Unsupported popR0 float/double");
1333            }
1334#endif
1335            switch (tosct){
1336                case TY_INT:
1337                case TY_FLOAT:
1338                    o4(0xE8BD0001);  // ldmfd   sp!,{r0}
1339                    mStackUse -= 4;
1340                    break;
1341                case TY_DOUBLE:
1342                    o4(0xE8BD0003);  // ldmfd   sp!,{r0, r1}  // Restore R0
1343                        mStackUse -= 8;
1344                    break;
1345                default:
1346                    error("Can't pop this type.");
1347                    break;
1348            }
1349            popType();
1350            LOG_STACK("popR0: %d\n", mStackUse);
1351        }
1352
1353        virtual void storeR0ToTOS() {
1354            Type* pPointerType = getTOSType();
1355            assert(pPointerType->tag == TY_POINTER);
1356            Type* pDestType = pPointerType->pHead;
1357            convertR0(pDestType);
1358            o4(0xE8BD0004);  // ldmfd   sp!,{r2}
1359            popType();
1360            mStackUse -= 4;
1361            switch (pDestType->tag) {
1362                case TY_POINTER:
1363                case TY_INT:
1364                    o4(0xE5820000); // str r0, [r2]
1365                    break;
1366                case TY_FLOAT:
1367#ifdef ARM_USE_VFP
1368                    o4(0xEDC27A00); // fsts    s15, [r2, #0]
1369#else
1370                    o4(0xE5820000); // str r0, [r2]
1371#endif
1372                    break;
1373                case TY_SHORT:
1374                    o4(0xE1C200B0); // strh r0, [r2]
1375                    break;
1376                case TY_CHAR:
1377                    o4(0xE5C20000); // strb r0, [r2]
1378                    break;
1379                case TY_DOUBLE:
1380#ifdef ARM_USE_VFP
1381                    o4(0xED827B00); // fstd    d7, [r2, #0]
1382#else
1383                    o4(0xE1C200F0); // strd r0, [r2]
1384#endif
1385                    break;
1386                case TY_STRUCT:
1387                {
1388                    int size = sizeOf(pDestType);
1389                    if (size > 0) {
1390                        liReg(size, 1);
1391                        callRuntime((void*) runtime_structCopy);
1392                    }
1393                }
1394                    break;
1395                default:
1396                    error("storeR0ToTOS: unimplemented type %d",
1397                            pDestType->tag);
1398                    break;
1399            }
1400        }
1401
1402        virtual void loadR0FromR0() {
1403            Type* pPointerType = getR0Type();
1404            assert(pPointerType->tag == TY_POINTER);
1405            Type* pNewType = pPointerType->pHead;
1406            TypeTag tag = pNewType->tag;
1407            switch (tag) {
1408                case TY_POINTER:
1409                case TY_INT:
1410                    o4(0xE5900000); // ldr r0, [r0]
1411                    break;
1412                case TY_FLOAT:
1413#ifdef ARM_USE_VFP
1414                    o4(0xEDD07A00); // flds    s15, [r0, #0]
1415#else
1416                    o4(0xE5900000); // ldr r0, [r0]
1417#endif
1418                    break;
1419                case TY_SHORT:
1420                    o4(0xE1D000F0); // ldrsh r0, [r0]
1421                    break;
1422                case TY_CHAR:
1423                    o4(0xE5D00000); // ldrb r0, [r0]
1424                    break;
1425                case TY_DOUBLE:
1426#ifdef ARM_USE_VFP
1427                    o4(0xED907B00); // fldd    d7, [r0, #0]
1428#else
1429                    o4(0xE1C000D0); // ldrd   r0, [r0]
1430#endif
1431                    break;
1432                case TY_ARRAY:
1433                    pNewType = pNewType->pTail;
1434                    break;
1435                case TY_STRUCT:
1436                    break;
1437                default:
1438                    error("loadR0FromR0: unimplemented type %d", tag);
1439                    break;
1440            }
1441            setR0Type(pNewType);
1442        }
1443
1444        virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
1445            if (ea > -LOCAL && ea < LOCAL) {
1446                // Local, fp relative
1447
1448                size_t immediate = 0;
1449                bool inRange = false;
1450                if (ea < 0) {
1451                    inRange = encode12BitImmediate(-ea, &immediate);
1452                    o4(0xE24B0000 | immediate); // sub    r0, fp, #ea
1453                } else {
1454                    inRange = encode12BitImmediate(ea, &immediate);
1455                    o4(0xE28B0000 | immediate); // add    r0, fp, #ea
1456                }
1457                if (! inRange) {
1458                    error("Offset out of range: %08x", ea);
1459                }
1460            } else {
1461                // Global, absolute.
1462                o4(0xE59F0000); //        ldr    r0, .L1
1463                o4(0xEA000000); //        b .L99
1464                o4(ea);         // .L1:   .word 0
1465                                // .L99:
1466            }
1467            setR0Type(pPointerType, et);
1468        }
1469
1470        virtual int leaForward(int ea, Type* pPointerType) {
1471            setR0Type(pPointerType);
1472            int result = ea;
1473            int pc = getPC();
1474            int offset = 0;
1475            if (ea) {
1476                offset = (pc - ea - 8) >> 2;
1477                if ((offset & 0xffff) != offset) {
1478                    error("function forward reference out of bounds");
1479                }
1480            } else {
1481                offset = 0;
1482            }
1483            o4(0xE59F0000 | offset); //        ldr    r0, .L1
1484
1485            if (ea == 0) {
1486                o4(0xEA000000); //        b .L99
1487                result = o4(ea);         // .L1:   .word 0
1488                            // .L99:
1489            }
1490            return result;
1491        }
1492
1493        virtual void convertR0Imp(Type* pType, bool isCast){
1494            Type* pR0Type = getR0Type();
1495            if (isPointerType(pType) && isPointerType(pR0Type)) {
1496                Type* pA = pR0Type;
1497                Type* pB = pType;
1498                // Array decays to pointer
1499                if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
1500                    pA = pA->pTail;
1501                }
1502                if (! (typeEqual(pA, pB)
1503                        || pB->pHead->tag == TY_VOID
1504                        || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
1505                    )) {
1506                    error("Incompatible pointer or array types");
1507                }
1508            } else if (bitsSame(pType, pR0Type)) {
1509                // do nothing special
1510            } else {
1511                TypeTag r0Tag = collapseType(pR0Type->tag);
1512                TypeTag destTag = collapseType(pType->tag);
1513                if (r0Tag == TY_INT) {
1514                    if (destTag == TY_FLOAT) {
1515#ifdef ARM_USE_VFP
1516                        o4(0xEE070A90); // fmsr    s15, r0
1517                        o4(0xEEF87AE7); // fsitos s15, s15
1518
1519#else
1520                        callRuntime((void*) runtime_int_to_float);
1521#endif
1522                    } else {
1523                        assert(destTag == TY_DOUBLE);
1524#ifdef ARM_USE_VFP
1525                        o4(0xEE070A90); // fmsr s15, r0
1526                        o4(0xEEB87BE7); // fsitod d7, s15
1527
1528#else
1529                        callRuntime((void*) runtime_int_to_double);
1530#endif
1531                    }
1532                } else if (r0Tag == TY_FLOAT) {
1533                    if (destTag == TY_INT) {
1534#ifdef ARM_USE_VFP
1535                        o4(0xEEFD7AE7); // ftosizs s15, s15
1536                        o4(0xEE170A90); // fmrs r0, s15
1537#else
1538                        callRuntime((void*) runtime_float_to_int);
1539#endif
1540                    } else {
1541                        assert(destTag == TY_DOUBLE);
1542#ifdef ARM_USE_VFP
1543                        o4(0xEEB77AE7); // fcvtds    d7, s15
1544#else
1545                        callRuntime((void*) runtime_float_to_double);
1546#endif
1547                    }
1548                } else {
1549                    assert (r0Tag == TY_DOUBLE);
1550                    if (destTag == TY_INT) {
1551#ifdef ARM_USE_VFP
1552                        o4(0xEEFD7BC7); // ftosizd s15, d7
1553                        o4(0xEE170A90); // fmrs r0, s15
1554#else
1555                        callRuntime((void*) runtime_double_to_int);
1556#endif
1557                    } else {
1558                        assert(destTag == TY_FLOAT);
1559#ifdef ARM_USE_VFP
1560                        o4(0xEEF77BC7); // fcvtsd s15, d7
1561#else
1562                        callRuntime((void*) runtime_double_to_float);
1563#endif
1564                    }
1565                }
1566            }
1567            setR0Type(pType);
1568        }
1569
1570        virtual int beginFunctionCallArguments() {
1571            return o4(0xE24DDF00); // Placeholder
1572        }
1573
1574        virtual size_t storeR0ToArg(int l, Type* pArgType) {
1575            convertR0(pArgType);
1576            Type* pR0Type = getR0Type();
1577            TypeTag r0ct = collapseType(pR0Type->tag);
1578#ifdef ARM_USE_VFP
1579            switch(r0ct) {
1580                case TY_INT:
1581                    if (l < 0 || l > 4096-4) {
1582                        error("l out of range for stack offset: 0x%08x", l);
1583                    }
1584                    o4(0xE58D0000 | l); // str r0, [sp, #l]
1585                    return 4;
1586                case TY_FLOAT:
1587                    if (l < 0 || l > 1020 || (l & 3)) {
1588                        error("l out of range for stack offset: 0x%08x", l);
1589                    }
1590                    o4(0xEDCD7A00 | (l >> 2)); // fsts    s15, [sp, #l]
1591                    return 4;
1592                case TY_DOUBLE: {
1593                    // Align to 8 byte boundary
1594                    int l2 = (l + 7) & ~7;
1595                    if (l2 < 0 || l2 > 1020 || (l2 & 3)) {
1596                        error("l out of range for stack offset: 0x%08x", l);
1597                    }
1598                    o4(0xED8D7B00 | (l2 >> 2)); // fstd    d7, [sp, #l2]
1599                    return (l2 - l) + 8;
1600                }
1601                default:
1602                    assert(false);
1603                    return 0;
1604            }
1605#else
1606            switch(r0ct) {
1607                case TY_INT:
1608                case TY_FLOAT:
1609                    if (l < 0 || l > 4096-4) {
1610                        error("l out of range for stack offset: 0x%08x", l);
1611                    }
1612                    o4(0xE58D0000 + l); // str r0, [sp, #l]
1613                    return 4;
1614                case TY_DOUBLE: {
1615                    // Align to 8 byte boundary
1616                    int l2 = (l + 7) & ~7;
1617                    if (l2 < 0 || l2 > 4096-8) {
1618                        error("l out of range for stack offset: 0x%08x", l);
1619                    }
1620                    o4(0xE58D0000 + l2); // str r0, [sp, #l]
1621                    o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4]
1622                    return (l2 - l) + 8;
1623                }
1624                default:
1625                    assert(false);
1626                    return 0;
1627            }
1628#endif
1629        }
1630
1631        virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
1632            int argumentStackUse = l;
1633            // Have to calculate register arg count from actual stack size,
1634            // in order to properly handle ... functions.
1635            int regArgCount = l >> 2;
1636            if (regArgCount > 4) {
1637                regArgCount = 4;
1638            }
1639            if (regArgCount > 0) {
1640                argumentStackUse -= regArgCount * 4;
1641                o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd   sp!,{}
1642            }
1643            mStackUse += argumentStackUse;
1644
1645            // Align stack.
1646            int missalignment = mStackUse - ((mStackUse / STACK_ALIGNMENT)
1647                    * STACK_ALIGNMENT);
1648            mStackAlignmentAdjustment = 0;
1649            if (missalignment > 0) {
1650                mStackAlignmentAdjustment = STACK_ALIGNMENT - missalignment;
1651            }
1652            l += mStackAlignmentAdjustment;
1653
1654            if (l < 0 || l > 0x3FC) {
1655                error("L out of range for stack adjustment: 0x%08x", l);
1656            }
1657            * (int*) a = 0xE24DDF00 | (l >> 2); // sub    sp, sp, #0 << 2
1658            mStackUse += mStackAlignmentAdjustment;
1659            LOG_STACK("endFunctionCallArguments mStackUse: %d, mStackAlignmentAdjustment %d\n",
1660                      mStackUse, mStackAlignmentAdjustment);
1661        }
1662
1663        virtual int callForward(int symbol, Type* pFunc) {
1664            setR0Type(pFunc->pHead);
1665            // Forward calls are always short (local)
1666            return o4(0xEB000000 | encodeAddress(symbol));
1667        }
1668
1669        virtual void callIndirect(int l, Type* pFunc) {
1670            assert(pFunc->tag == TY_FUNC);
1671            popType(); // Get rid of indirect fn pointer type
1672            int argCount = l >> 2;
1673            int poppedArgs = argCount > 4 ? 4 : argCount;
1674            int adjustedL = l - (poppedArgs << 2) + mStackAlignmentAdjustment;
1675            if (adjustedL < 0 || adjustedL > 4096-4) {
1676                error("l out of range for stack offset: 0x%08x", l);
1677            }
1678            o4(0xE59DC000 | (0xfff & adjustedL)); // ldr    r12, [sp,#adjustedL]
1679            o4(0xE12FFF3C); // blx r12
1680            Type* pReturnType = pFunc->pHead;
1681            setR0Type(pReturnType);
1682#ifdef ARM_USE_VFP
1683            switch(pReturnType->tag) {
1684            case TY_FLOAT:
1685                o4(0xEE070A90); // fmsr s15, r0
1686                break;
1687            case TY_DOUBLE:
1688                o4(0xEC410B17); // fmdrr d7, r0, r1
1689                break;
1690            default:
1691                break;
1692            }
1693#endif
1694        }
1695
1696        virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
1697            int argCount = l >> 2;
1698            // Have to calculate register arg count from actual stack size,
1699            // in order to properly handle ... functions.
1700            int regArgCount = l >> 2;
1701            if (regArgCount > 4) {
1702                regArgCount = 4;
1703            }
1704            int stackArgs = argCount - regArgCount;
1705            int stackUse =  stackArgs + (isIndirect ? 1 : 0)
1706                + (mStackAlignmentAdjustment >> 2);
1707            if (stackUse) {
1708                if (stackUse < 0 || stackUse > 255) {
1709                    error("L out of range for stack adjustment: 0x%08x", l);
1710                }
1711                o4(0xE28DDF00 | stackUse); // add    sp, sp, #stackUse << 2
1712                mStackUse -= stackUse * 4;
1713                LOG_STACK("adjustStackAfterCall: %d\n", mStackUse);
1714            }
1715        }
1716
1717        virtual int jumpOffset() {
1718            return 8;
1719        }
1720
1721        /* output a symbol and patch all calls to it */
1722        virtual void gsym(int t) {
1723            int n;
1724            int base = getBase();
1725            int pc = getPC();
1726            while (t) {
1727                int data = * (int*) t;
1728                int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2);
1729                if (decodedOffset == 0) {
1730                    n = 0;
1731                } else {
1732                    n = base + decodedOffset; /* next value */
1733                }
1734                *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK)
1735                    | encodeRelAddress(pc - t - 8);
1736                t = n;
1737            }
1738        }
1739
1740        /* output a symbol and patch all calls to it */
1741        virtual void resolveForward(int t) {
1742            if (t) {
1743                int pc = getPC();
1744                *(int *) t = pc;
1745            }
1746        }
1747
1748        virtual int finishCompile() {
1749#if defined(__arm__)
1750            const long base = long(getBase());
1751            const long curr = long(getPC());
1752            int err = cacheflush(base, curr, 0);
1753            return err;
1754#else
1755            return 0;
1756#endif
1757        }
1758
1759        virtual int disassemble(FILE* out) {
1760#ifdef ENABLE_ARM_DISASSEMBLY
1761            disasmOut = out;
1762            disasm_interface_t  di;
1763            di.di_readword = disassemble_readword;
1764            di.di_printaddr = disassemble_printaddr;
1765            di.di_printf = disassemble_printf;
1766
1767            int base = getBase();
1768            int pc = getPC();
1769            for(int i = base; i < pc; i += 4) {
1770                fprintf(out, "%08x: %08x  ", i, *(int*) i);
1771                ::disasm(&di, i, 0);
1772            }
1773#endif
1774            return 0;
1775        }
1776
1777        /**
1778         * alignment (in bytes) for this type of data
1779         */
1780        virtual size_t alignmentOf(Type* pType){
1781            switch(pType->tag) {
1782                case TY_CHAR:
1783                    return 1;
1784                case TY_SHORT:
1785                    return 2;
1786                case TY_DOUBLE:
1787                    return 8;
1788                case TY_ARRAY:
1789                    return alignmentOf(pType->pHead);
1790                case TY_STRUCT:
1791                    return pType->pHead->alignment & 0x7fffffff;
1792                case TY_FUNC:
1793                    error("alignment of func not supported");
1794                    return 1;
1795                default:
1796                    return 4;
1797            }
1798        }
1799
1800        /**
1801         * Array element alignment (in bytes) for this type of data.
1802         */
1803        virtual size_t sizeOf(Type* pType){
1804            switch(pType->tag) {
1805                case TY_INT:
1806                    return 4;
1807                case TY_SHORT:
1808                    return 2;
1809                case TY_CHAR:
1810                    return 1;
1811                case TY_FLOAT:
1812                    return 4;
1813                case TY_DOUBLE:
1814                    return 8;
1815                case TY_POINTER:
1816                    return 4;
1817                case TY_ARRAY:
1818                    return pType->length * sizeOf(pType->pHead);
1819                case TY_STRUCT:
1820                    return pType->pHead->length;
1821                default:
1822                    error("Unsupported type %d", pType->tag);
1823                    return 0;
1824            }
1825        }
1826
1827    private:
1828        static FILE* disasmOut;
1829
1830        static u_int
1831        disassemble_readword(u_int address)
1832        {
1833            return(*((u_int *)address));
1834        }
1835
1836        static void
1837        disassemble_printaddr(u_int address)
1838        {
1839            fprintf(disasmOut, "0x%08x", address);
1840        }
1841
1842        static void
1843        disassemble_printf(const char *fmt, ...) {
1844            va_list ap;
1845            va_start(ap, fmt);
1846            vfprintf(disasmOut, fmt, ap);
1847            va_end(ap);
1848        }
1849
1850        static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff;
1851
1852        /** Encode a relative address that might also be
1853         * a label.
1854         */
1855        int encodeAddress(int value) {
1856            int base = getBase();
1857            if (value >= base && value <= getPC() ) {
1858                // This is a label, encode it relative to the base.
1859                value = value - base;
1860            }
1861            return encodeRelAddress(value);
1862        }
1863
1864        int encodeRelAddress(int value) {
1865            return BRANCH_REL_ADDRESS_MASK & (value >> 2);
1866        }
1867
1868        int calcRegArgCount(Type* pDecl) {
1869            int reg = 0;
1870            Type* pArgs = pDecl->pTail;
1871            while (pArgs && reg < 4) {
1872                Type* pArg = pArgs->pHead;
1873                if ( pArg->tag == TY_DOUBLE) {
1874                    int evenReg = (reg + 1) & ~1;
1875                    if (evenReg >= 4) {
1876                        break;
1877                    }
1878                    reg = evenReg + 2;
1879                } else {
1880                    reg++;
1881                }
1882                pArgs = pArgs->pTail;
1883            }
1884            return reg;
1885        }
1886
1887        void setupIntPtrArgs() {
1888            o4(0xE8BD0002);  // ldmfd   sp!,{r1}
1889            mStackUse -= 4;
1890            popType();
1891        }
1892
1893        /* Pop TOS to R1 (use s14 if VFP)
1894         * Make sure both R0 and TOS are floats. (Could be ints)
1895         * We know that at least one of R0 and TOS is already a float
1896         */
1897        void setupFloatArgs() {
1898            Type* pR0Type = getR0Type();
1899            Type* pTOSType = getTOSType();
1900            TypeTag tagR0 = collapseType(pR0Type->tag);
1901            TypeTag tagTOS = collapseType(pTOSType->tag);
1902            if (tagR0 != TY_FLOAT) {
1903                assert(tagR0 == TY_INT);
1904#ifdef ARM_USE_VFP
1905                o4(0xEE070A90); // fmsr    s15, r0
1906                o4(0xEEF87AE7); // fsitos s15, s15
1907#else
1908                callRuntime((void*) runtime_int_to_float);
1909#endif
1910            }
1911            if (tagTOS != TY_FLOAT) {
1912                assert(tagTOS == TY_INT);
1913                assert(tagR0 == TY_FLOAT);
1914#ifdef ARM_USE_VFP
1915                o4(0xECBD7A01); // fldmfds sp!, {s14}
1916                o4(0xEEB87AC7); // fsitos s14, s14
1917#else
1918                o4(0xE92D0001);  // stmfd   sp!,{r0}  // push R0
1919                o4(0xE59D0004);  // ldr     r0, [sp, #4]
1920                callRuntime((void*) runtime_int_to_float);
1921                o4(0xE1A01000);  // mov r1, r0
1922                o4(0xE8BD0001);  // ldmfd   sp!,{r0}  // pop R0
1923                o4(0xE28DD004);  // add sp, sp, #4 // Pop sp
1924#endif
1925            } else {
1926                // Pop TOS
1927#ifdef ARM_USE_VFP
1928                o4(0xECBD7A01); // fldmfds sp!, {s14}
1929
1930#else
1931                o4(0xE8BD0002);  // ldmfd   sp!,{r1}
1932#endif
1933            }
1934            mStackUse -= 4;
1935            popType();
1936        }
1937
1938        /* Pop TOS into R2..R3 (use D6 if VFP)
1939         * Make sure both R0 and TOS are doubles. Could be floats or ints.
1940         * We know that at least one of R0 and TOS are already a double.
1941         */
1942
1943        void setupDoubleArgs() {
1944            Type* pR0Type = getR0Type();
1945            Type* pTOSType = getTOSType();
1946            TypeTag tagR0 = collapseType(pR0Type->tag);
1947            TypeTag tagTOS = collapseType(pTOSType->tag);
1948            if (tagR0 != TY_DOUBLE) {
1949                if (tagR0 == TY_INT) {
1950#ifdef ARM_USE_VFP
1951                    o4(0xEE070A90); // fmsr s15, r0
1952                    o4(0xEEB87BE7); // fsitod d7, s15
1953
1954#else
1955                    callRuntime((void*) runtime_int_to_double);
1956#endif
1957                } else {
1958                    assert(tagR0 == TY_FLOAT);
1959#ifdef ARM_USE_VFP
1960                    o4(0xEEB77AE7); // fcvtds    d7, s15
1961#else
1962                    callRuntime((void*) runtime_float_to_double);
1963#endif
1964                }
1965            }
1966            if (tagTOS != TY_DOUBLE) {
1967#ifdef ARM_USE_VFP
1968                if (tagTOS == TY_INT) {
1969                    o4(0xECFD6A01);  // fldmfds sp!,{s13}
1970                    o4(0xEEB86BE6);  // fsitod  d6, s13
1971                } else {
1972                    assert(tagTOS == TY_FLOAT);
1973                    o4(0xECFD6A01);  // fldmfds sp!,{s13}
1974                    o4(0xEEB76AE6);  // fcvtds    d6, s13
1975                }
1976#else
1977                o4(0xE92D0003);  // stmfd   sp!,{r0,r1}  // push r0,r1
1978                o4(0xE59D0008);  // ldr     r0, [sp, #8]
1979                if (tagTOS == TY_INT) {
1980                    callRuntime((void*) runtime_int_to_double);
1981                } else {
1982                    assert(tagTOS == TY_FLOAT);
1983                    callRuntime((void*) runtime_float_to_double);
1984                }
1985                o4(0xE1A02000);  // mov r2, r0
1986                o4(0xE1A03001);  // mov r3, r1
1987                o4(0xE8BD0003);  // ldmfd   sp!,{r0, r1}  // Restore R0
1988                o4(0xE28DD004);  // add sp, sp, #4 // Pop sp
1989#endif
1990                mStackUse -= 4;
1991            } else {
1992#ifdef ARM_USE_VFP
1993                o4(0xECBD6B02);  // fldmfdd    sp!, {d6}
1994#else
1995                o4(0xE8BD000C);  // ldmfd   sp!,{r2,r3}
1996#endif
1997                mStackUse -= 8;
1998            }
1999            popType();
2000        }
2001
2002        void liReg(int t, int reg) {
2003            assert(reg >= 0 && reg < 16);
2004            int rN = (reg & 0xf) << 12;
2005            size_t encodedImmediate;
2006            if (encode12BitImmediate(t, &encodedImmediate)) {
2007                 o4(0xE3A00000 | encodedImmediate | rN); // mov    rN, #0
2008            } else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
2009                // mvn means move constant ^ ~0
2010                o4(0xE3E00000 | encodedImmediate | rN); // mvn    rN, #0
2011            } else {
2012                o4(0xE51F0000 | rN); //         ldr    rN, .L3
2013                o4(0xEA000000); //         b .L99
2014                o4(t);          // .L3:   .word 0
2015                                  // .L99:
2016            }
2017        }
2018
2019        bool encode12BitImmediate(size_t immediate, size_t* pResult) {
2020            for(size_t i = 0; i < 16; i++) {
2021                size_t rotate = i * 2;
2022                size_t mask = rotateRight(0xff, rotate);
2023                if ((immediate | mask) == mask) {
2024                    size_t bits8 = rotateLeft(immediate, rotate);
2025                    assert(bits8 <= 0xff);
2026                    *pResult = (i << 8) | bits8;
2027                    return true;
2028                }
2029            }
2030            return false;
2031        }
2032
2033        size_t rotateRight(size_t n, size_t rotate) {
2034            return (n >> rotate) | (n << (32 - rotate));
2035        }
2036
2037        size_t rotateLeft(size_t n, size_t rotate) {
2038            return (n << rotate) | (n >> (32 - rotate));
2039        }
2040
2041        void callRuntime(void* fn) {
2042            o4(0xE59FC000); // ldr    r12, .L1
2043            o4(0xEA000000); // b      .L99
2044            o4((int) fn);   //.L1:  .word  fn
2045            o4(0xE12FFF3C); //.L99: blx    r12
2046        }
2047
2048        // Integer math:
2049
2050        static int runtime_DIV(int b, int a) {
2051            return a / b;
2052        }
2053
2054        static int runtime_MOD(int b, int a) {
2055            return a % b;
2056        }
2057
2058        static void runtime_structCopy(void* src, size_t size, void* dest) {
2059            memcpy(dest, src, size);
2060        }
2061
2062#ifndef ARM_USE_VFP
2063
2064        // Comparison to zero
2065
2066        static int runtime_is_non_zero_f(float a) {
2067            return a != 0;
2068        }
2069
2070        static int runtime_is_non_zero_d(double a) {
2071            return a != 0;
2072        }
2073
2074        // Comparison to zero
2075
2076        static int runtime_is_zero_f(float a) {
2077            return a == 0;
2078        }
2079
2080        static int runtime_is_zero_d(double a) {
2081            return a == 0;
2082        }
2083
2084        // Type conversion
2085
2086        static int runtime_float_to_int(float a) {
2087            return (int) a;
2088        }
2089
2090        static double runtime_float_to_double(float a) {
2091            return (double) a;
2092        }
2093
2094        static int runtime_double_to_int(double a) {
2095            return (int) a;
2096        }
2097
2098        static float runtime_double_to_float(double a) {
2099            return (float) a;
2100        }
2101
2102        static float runtime_int_to_float(int a) {
2103            return (float) a;
2104        }
2105
2106        static double runtime_int_to_double(int a) {
2107            return (double) a;
2108        }
2109
2110        // Comparisons float
2111
2112        static int runtime_cmp_eq_ff(float b, float a) {
2113            return a == b;
2114        }
2115
2116        static int runtime_cmp_ne_ff(float b, float a) {
2117            return a != b;
2118        }
2119
2120        static int runtime_cmp_lt_ff(float b, float a) {
2121            return a < b;
2122        }
2123
2124        static int runtime_cmp_le_ff(float b, float a) {
2125            return a <= b;
2126        }
2127
2128        static int runtime_cmp_ge_ff(float b, float a) {
2129            return a >= b;
2130        }
2131
2132        static int runtime_cmp_gt_ff(float b, float a) {
2133            return a > b;
2134        }
2135
2136        // Comparisons double
2137
2138        static int runtime_cmp_eq_dd(double b, double a) {
2139            return a == b;
2140        }
2141
2142        static int runtime_cmp_ne_dd(double b, double a) {
2143            return a != b;
2144        }
2145
2146        static int runtime_cmp_lt_dd(double b, double a) {
2147            return a < b;
2148        }
2149
2150        static int runtime_cmp_le_dd(double b, double a) {
2151            return a <= b;
2152        }
2153
2154        static int runtime_cmp_ge_dd(double b, double a) {
2155            return a >= b;
2156        }
2157
2158        static int runtime_cmp_gt_dd(double b, double a) {
2159            return a > b;
2160        }
2161
2162        // Math float
2163
2164        static float runtime_op_add_ff(float b, float a) {
2165            return a + b;
2166        }
2167
2168        static float runtime_op_sub_ff(float b, float a) {
2169            return a - b;
2170        }
2171
2172        static float runtime_op_mul_ff(float b, float a) {
2173            return a * b;
2174        }
2175
2176        static float runtime_op_div_ff(float b, float a) {
2177            return a / b;
2178        }
2179
2180        static float runtime_op_neg_f(float a) {
2181            return -a;
2182        }
2183
2184        // Math double
2185
2186        static double runtime_op_add_dd(double b, double a) {
2187            return a + b;
2188        }
2189
2190        static double runtime_op_sub_dd(double b, double a) {
2191            return a - b;
2192        }
2193
2194        static double runtime_op_mul_dd(double b, double a) {
2195            return a * b;
2196        }
2197
2198        static double runtime_op_div_dd(double b, double a) {
2199            return a / b;
2200        }
2201
2202        static double runtime_op_neg_d(double a) {
2203            return -a;
2204        }
2205
2206#endif
2207
2208        static const int STACK_ALIGNMENT = 8;
2209        int mStackUse;
2210        // This variable holds the amount we adjusted the stack in the most
2211        // recent endFunctionCallArguments call. It's examined by the
2212        // following adjustStackAfterCall call.
2213        int mStackAlignmentAdjustment;
2214    };
2215
2216#endif // PROVIDE_ARM_CODEGEN
2217
2218#ifdef PROVIDE_X86_CODEGEN
2219
2220    class X86CodeGenerator : public CodeGenerator {
2221    public:
2222        X86CodeGenerator() {}
2223        virtual ~X86CodeGenerator() {}
2224
2225        /* returns address to patch with local variable size
2226        */
2227        virtual int functionEntry(Type* pDecl) {
2228            o(0xe58955); /* push   %ebp, mov %esp, %ebp */
2229            return oad(0xec81, 0); /* sub $xxx, %esp */
2230        }
2231
2232        virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2233            o(0xc3c9); /* leave, ret */
2234            *(int *) localVariableAddress = localVariableSize; /* save local variables */
2235        }
2236
2237        /* load immediate value */
2238        virtual void li(int i) {
2239            oad(0xb8, i); /* mov $xx, %eax */
2240            setR0Type(mkpInt);
2241        }
2242
2243        virtual void loadFloat(int address, Type* pType) {
2244            setR0Type(pType);
2245            switch (pType->tag) {
2246            case TY_FLOAT:
2247                oad(0x05D9, address);      // flds
2248                break;
2249            case TY_DOUBLE:
2250                oad(0x05DD, address);      // fldl
2251                break;
2252            default:
2253                assert(false);
2254                break;
2255            }
2256        }
2257
2258        virtual void addStructOffsetR0(int offset, Type* pType) {
2259            if (offset) {
2260                oad(0x05, offset); // addl offset, %eax
2261            }
2262            setR0Type(pType, ET_LVALUE);
2263        }
2264
2265        virtual int gjmp(int t) {
2266            return psym(0xe9, t);
2267        }
2268
2269        /* l = 0: je, l == 1: jne */
2270        virtual int gtst(bool l, int t) {
2271            Type* pR0Type = getR0Type();
2272            TypeTag tagR0 = pR0Type->tag;
2273            bool isFloatR0 = isFloatTag(tagR0);
2274            if (isFloatR0) {
2275                o(0xeed9); // fldz
2276                o(0xe9da); // fucompp
2277                o(0xe0df); // fnstsw %ax
2278                o(0x9e);   // sahf
2279            } else {
2280                o(0xc085); // test %eax, %eax
2281            }
2282            // Use two output statements to generate one instruction.
2283            o(0x0f);   // je/jne xxx
2284            return psym(0x84 + l, t);
2285        }
2286
2287        virtual void gcmp(int op) {
2288            Type* pR0Type = getR0Type();
2289            Type* pTOSType = getTOSType();
2290            TypeTag tagR0 = pR0Type->tag;
2291            TypeTag tagTOS = pTOSType->tag;
2292            bool isFloatR0 = isFloatTag(tagR0);
2293            bool isFloatTOS = isFloatTag(tagTOS);
2294            if (!isFloatR0 && !isFloatTOS) {
2295                int t = decodeOp(op);
2296                o(0x59); /* pop %ecx */
2297                o(0xc139); /* cmp %eax,%ecx */
2298                li(0);
2299                o(0x0f); /* setxx %al */
2300                o(t + 0x90);
2301                o(0xc0);
2302                popType();
2303            } else {
2304                setupFloatOperands();
2305                switch (op) {
2306                    case OP_EQUALS:
2307                        o(0xe9da);   // fucompp
2308                        o(0xe0df);   // fnstsw %ax
2309                        o(0x9e);     // sahf
2310                        o(0xc0940f); // sete %al
2311                        o(0xc29b0f); // setnp %dl
2312                        o(0xd021);   // andl %edx, %eax
2313                        break;
2314                    case OP_NOT_EQUALS:
2315                        o(0xe9da);   // fucompp
2316                        o(0xe0df);   // fnstsw %ax
2317                        o(0x9e);     // sahf
2318                        o(0xc0950f); // setne %al
2319                        o(0xc29a0f); // setp %dl
2320                        o(0xd009);   // orl %edx, %eax
2321                        break;
2322                    case OP_GREATER_EQUAL:
2323                        o(0xe9da);   // fucompp
2324                        o(0xe0df);   // fnstsw %ax
2325                        o(0x05c4f6); // testb $5, %ah
2326                        o(0xc0940f); // sete %al
2327                        break;
2328                    case OP_LESS:
2329                        o(0xc9d9);   // fxch %st(1)
2330                        o(0xe9da);   // fucompp
2331                        o(0xe0df);   // fnstsw %ax
2332                        o(0x9e);     // sahf
2333                        o(0xc0970f); // seta %al
2334                        break;
2335                    case OP_LESS_EQUAL:
2336                        o(0xc9d9);   // fxch %st(1)
2337                        o(0xe9da);   // fucompp
2338                        o(0xe0df);   // fnstsw %ax
2339                        o(0x9e);     // sahf
2340                        o(0xc0930f); // setea %al
2341                        break;
2342                    case OP_GREATER:
2343                        o(0xe9da);   // fucompp
2344                        o(0xe0df);   // fnstsw %ax
2345                        o(0x45c4f6); // testb $69, %ah
2346                        o(0xc0940f); // sete %al
2347                        break;
2348                    default:
2349                        error("Unknown comparison op");
2350                }
2351                o(0xc0b60f); // movzbl %al, %eax
2352            }
2353            setR0Type(mkpInt);
2354        }
2355
2356        virtual void genOp(int op) {
2357            Type* pR0Type = getR0Type();
2358            Type* pTOSType = getTOSType();
2359            TypeTag tagR0 = pR0Type->tag;
2360            TypeTag tagTOS = pTOSType->tag;
2361            bool isFloatR0 = isFloatTag(tagR0);
2362            bool isFloatTOS = isFloatTag(tagTOS);
2363            if (!isFloatR0 && !isFloatTOS) {
2364                bool isPtrR0 = isPointerTag(tagR0);
2365                bool isPtrTOS = isPointerTag(tagTOS);
2366                if (isPtrR0 || isPtrTOS) {
2367                    if (isPtrR0 && isPtrTOS) {
2368                        if (op != OP_MINUS) {
2369                            error("Unsupported pointer-pointer operation %d.", op);
2370                        }
2371                        if (! typeEqual(pR0Type, pTOSType)) {
2372                            error("Incompatible pointer types for subtraction.");
2373                        }
2374                        o(0x59); /* pop %ecx */
2375                        o(decodeOp(op));
2376                        popType();
2377                        setR0Type(mkpInt);
2378                        int size = sizeOf(pR0Type->pHead);
2379                        if (size != 1) {
2380                            pushR0();
2381                            li(size);
2382                            // TODO: Optimize for power-of-two.
2383                            genOp(OP_DIV);
2384                        }
2385                    } else {
2386                        if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
2387                            error("Unsupported pointer-scalar operation %d", op);
2388                        }
2389                        Type* pPtrType = getPointerArithmeticResultType(
2390                                pR0Type, pTOSType);
2391                        o(0x59); /* pop %ecx */
2392                        int size = sizeOf(pPtrType->pHead);
2393                        if (size != 1) {
2394                            // TODO: Optimize for power-of-two.
2395                            if (isPtrR0) {
2396                                oad(0xC969, size); // imull $size, %ecx
2397                            } else {
2398                                oad(0xC069, size); // mul $size, %eax
2399                            }
2400                        }
2401                        o(decodeOp(op));
2402                        popType();
2403                        setR0Type(pPtrType);
2404                    }
2405                } else {
2406                    o(0x59); /* pop %ecx */
2407                    o(decodeOp(op));
2408                    if (op == OP_MOD)
2409                        o(0x92); /* xchg %edx, %eax */
2410                    popType();
2411                }
2412            } else {
2413                Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType;
2414                setupFloatOperands();
2415                // Both float. x87 R0 == left hand, x87 R1 == right hand
2416                switch (op) {
2417                    case OP_MUL:
2418                        o(0xc9de); // fmulp
2419                        break;
2420                    case OP_DIV:
2421                        o(0xf1de); // fdivp
2422                        break;
2423                    case OP_PLUS:
2424                        o(0xc1de); // faddp
2425                        break;
2426                    case OP_MINUS:
2427                        o(0xe1de); // fsubp
2428                        break;
2429                    default:
2430                        error("Unsupported binary floating operation.");
2431                        break;
2432                }
2433                setR0Type(pResultType);
2434            }
2435        }
2436
2437        virtual void gUnaryCmp(int op) {
2438            if (op != OP_LOGICAL_NOT) {
2439                error("Unknown unary cmp %d", op);
2440            } else {
2441                Type* pR0Type = getR0Type();
2442                TypeTag tag = collapseType(pR0Type->tag);
2443                switch(tag) {
2444                    case TY_INT: {
2445                            oad(0xb9, 0); /* movl $0, %ecx */
2446                            int t = decodeOp(op);
2447                            o(0xc139); /* cmp %eax,%ecx */
2448                            li(0);
2449                            o(0x0f); /* setxx %al */
2450                            o(t + 0x90);
2451                            o(0xc0);
2452                        }
2453                        break;
2454                    case TY_FLOAT:
2455                    case TY_DOUBLE:
2456                        o(0xeed9);   // fldz
2457                        o(0xe9da);   // fucompp
2458                        o(0xe0df);   // fnstsw %ax
2459                        o(0x9e);     // sahf
2460                        o(0xc0950f); // setne %al
2461                        o(0xc29a0f); // setp %dl
2462                        o(0xd009);   // orl %edx, %eax
2463                        o(0xc0b60f); // movzbl %al, %eax
2464                        o(0x01f083); // xorl $1,  %eax
2465                        break;
2466                    default:
2467                        error("gUnaryCmp unsupported type");
2468                        break;
2469                }
2470            }
2471            setR0Type(mkpInt);
2472        }
2473
2474        virtual void genUnaryOp(int op) {
2475            Type* pR0Type = getR0Type();
2476            TypeTag tag = collapseType(pR0Type->tag);
2477            switch(tag) {
2478                case TY_INT:
2479                    oad(0xb9, 0); /* movl $0, %ecx */
2480                    o(decodeOp(op));
2481                    break;
2482                case TY_FLOAT:
2483                case TY_DOUBLE:
2484                    switch (op) {
2485                        case OP_MINUS:
2486                            o(0xe0d9);  // fchs
2487                            break;
2488                        case OP_BIT_NOT:
2489                            error("Can't apply '~' operator to a float or double.");
2490                            break;
2491                        default:
2492                            error("Unknown unary op %d\n", op);
2493                            break;
2494                        }
2495                    break;
2496                default:
2497                    error("genUnaryOp unsupported type");
2498                    break;
2499            }
2500        }
2501
2502        virtual void pushR0() {
2503            Type* pR0Type = getR0Type();
2504            TypeTag r0ct = collapseType(pR0Type->tag);
2505            switch(r0ct) {
2506                case TY_INT:
2507                    o(0x50); /* push %eax */
2508                    break;
2509                case TY_FLOAT:
2510                    o(0x50); /* push %eax */
2511                    o(0x241cd9); // fstps 0(%esp)
2512                    break;
2513                case TY_DOUBLE:
2514                    o(0x50); /* push %eax */
2515                    o(0x50); /* push %eax */
2516                    o(0x241cdd); // fstpl 0(%esp)
2517                    break;
2518                default:
2519                    error("pushR0 unsupported type %d", r0ct);
2520                    break;
2521            }
2522            pushType();
2523        }
2524
2525        virtual void over() {
2526            // We know it's only used for int-ptr ops (++/--)
2527
2528            Type* pR0Type = getR0Type();
2529            TypeTag r0ct = collapseType(pR0Type->tag);
2530
2531            Type* pTOSType = getTOSType();
2532            TypeTag tosct = collapseType(pTOSType->tag);
2533
2534            assert (r0ct == TY_INT && tosct == TY_INT);
2535
2536            o(0x59); /* pop %ecx */
2537            o(0x50); /* push %eax */
2538            o(0x51); /* push %ecx */
2539
2540            overType();
2541        }
2542
2543        virtual void popR0() {
2544            Type* pR0Type = getR0Type();
2545            TypeTag r0ct = collapseType(pR0Type->tag);
2546            switch(r0ct) {
2547                case TY_INT:
2548                    o(0x58); /* popl %eax */
2549                    break;
2550                case TY_FLOAT:
2551                    o(0x2404d9); // flds (%esp)
2552                    o(0x58); /* popl %eax */
2553                    break;
2554                case TY_DOUBLE:
2555                    o(0x2404dd); // fldl (%esp)
2556                    o(0x58); /* popl %eax */
2557                    o(0x58); /* popl %eax */
2558                    break;
2559                default:
2560                    error("popR0 unsupported type %d", r0ct);
2561                    break;
2562            }
2563            popType();
2564        }
2565
2566        virtual void storeR0ToTOS() {
2567            Type* pPointerType = getTOSType();
2568            assert(pPointerType->tag == TY_POINTER);
2569            Type* pTargetType = pPointerType->pHead;
2570            convertR0(pTargetType);
2571            o(0x59); /* pop %ecx */
2572            popType();
2573            switch (pTargetType->tag) {
2574                case TY_POINTER:
2575                case TY_INT:
2576                    o(0x0189); /* movl %eax/%al, (%ecx) */
2577                    break;
2578                case TY_SHORT:
2579                    o(0x018966); /* movw %ax, (%ecx) */
2580                    break;
2581                case TY_CHAR:
2582                    o(0x0188); /* movl %eax/%al, (%ecx) */
2583                    break;
2584                case TY_FLOAT:
2585                    o(0x19d9); /* fstps (%ecx) */
2586                    break;
2587                case TY_DOUBLE:
2588                    o(0x19dd); /* fstpl (%ecx) */
2589                    break;
2590                case TY_STRUCT:
2591                {
2592                    // TODO: use alignment information to use movsw/movsl instead of movsb
2593                    int size = sizeOf(pTargetType);
2594                    if (size > 0) {
2595                        o(0x9c);         // pushf
2596                        o(0x57);         // pushl %edi
2597                        o(0x56);         // pushl %esi
2598                        o(0xcf89);       // movl %ecx, %edi
2599                        o(0xc689);       // movl %eax, %esi
2600                        oad(0xb9, size);  // mov #size, %ecx
2601                        o(0xfc);         // cld
2602                        o(0xf3);         // rep
2603                        o(0xa4);         // movsb
2604                        o(0x5e);         // popl %esi
2605                        o(0x5f);         // popl %edi
2606                        o(0x9d);         // popf
2607                    }
2608                }
2609                    break;
2610                default:
2611                    error("storeR0ToTOS: unsupported type %d",
2612                            pTargetType->tag);
2613                    break;
2614            }
2615        }
2616
2617        virtual void loadR0FromR0() {
2618            Type* pPointerType = getR0Type();
2619            assert(pPointerType->tag == TY_POINTER);
2620            Type* pNewType = pPointerType->pHead;
2621            TypeTag tag = pNewType->tag;
2622            switch (tag) {
2623                case TY_POINTER:
2624                case TY_INT:
2625                    o2(0x008b); /* mov (%eax), %eax */
2626                    break;
2627                case TY_SHORT:
2628                    o(0xbf0f); /* movswl (%eax), %eax */
2629                    ob(0);
2630                    break;
2631                case TY_CHAR:
2632                    o(0xbe0f); /* movsbl (%eax), %eax */
2633                    ob(0); /* add zero in code */
2634                    break;
2635                case TY_FLOAT:
2636                    o2(0x00d9); // flds (%eax)
2637                    break;
2638                case TY_DOUBLE:
2639                    o2(0x00dd); // fldl (%eax)
2640                    break;
2641                case TY_ARRAY:
2642                    pNewType = pNewType->pTail;
2643                    break;
2644                case TY_STRUCT:
2645                    break;
2646                default:
2647                    error("loadR0FromR0: unsupported type %d", tag);
2648                    break;
2649            }
2650            setR0Type(pNewType);
2651        }
2652
2653        virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
2654            gmov(10, ea); /* leal EA, %eax */
2655            setR0Type(pPointerType, et);
2656        }
2657
2658        virtual int leaForward(int ea, Type* pPointerType) {
2659            oad(0xb8, ea); /* mov $xx, %eax */
2660            setR0Type(pPointerType);
2661            return getPC() - 4;
2662        }
2663
2664        virtual void convertR0Imp(Type* pType, bool isCast){
2665            Type* pR0Type = getR0Type();
2666            if (pR0Type == NULL) {
2667                assert(false);
2668                setR0Type(pType);
2669                return;
2670            }
2671            if (isPointerType(pType) && isPointerType(pR0Type)) {
2672                Type* pA = pR0Type;
2673                Type* pB = pType;
2674                // Array decays to pointer
2675                if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
2676                    pA = pA->pTail;
2677                }
2678                if (! (typeEqual(pA, pB)
2679                        || pB->pHead->tag == TY_VOID
2680                        || (pA->tag == TY_POINTER && pB->tag == TY_POINTER && isCast)
2681                    )) {
2682                    error("Incompatible pointer or array types");
2683                }
2684            } else if (bitsSame(pType, pR0Type)) {
2685                // do nothing special
2686            } else if (isFloatType(pType) && isFloatType(pR0Type)) {
2687                // do nothing special, both held in same register on x87.
2688            } else {
2689                TypeTag r0Tag = collapseType(pR0Type->tag);
2690                TypeTag destTag = collapseType(pType->tag);
2691                if (r0Tag == TY_INT && isFloatTag(destTag)) {
2692                    // Convert R0 from int to float
2693                    o(0x50);      // push %eax
2694                    o(0x2404DB);  // fildl 0(%esp)
2695                    o(0x58);      // pop %eax
2696                } else if (isFloatTag(r0Tag) && destTag == TY_INT) {
2697                    // Convert R0 from float to int. Complicated because
2698                    // need to save and restore the rounding mode.
2699                    o(0x50);       // push %eax
2700                    o(0x50);       // push %eax
2701                    o(0x02247cD9); // fnstcw 2(%esp)
2702                    o(0x2444b70f); // movzwl 2(%esp), %eax
2703                    o(0x02);
2704                    o(0x0cb4);     // movb $12, %ah
2705                    o(0x24048966); // movw %ax, 0(%esp)
2706                    o(0x242cd9);   // fldcw 0(%esp)
2707                    o(0x04245cdb); // fistpl 4(%esp)
2708                    o(0x02246cd9); // fldcw  2(%esp)
2709                    o(0x58); // pop %eax
2710                    o(0x58); // pop %eax
2711                } else {
2712                    error("Incompatible types old: %d new: %d",
2713                          pR0Type->tag, pType->tag);
2714                }
2715            }
2716            setR0Type(pType);
2717        }
2718
2719        virtual int beginFunctionCallArguments() {
2720            return oad(0xec81, 0); /* sub $xxx, %esp */
2721        }
2722
2723        virtual size_t storeR0ToArg(int l, Type* pArgType) {
2724            convertR0(pArgType);
2725            Type* pR0Type = getR0Type();
2726            TypeTag r0ct = collapseType(pR0Type->tag);
2727            switch(r0ct) {
2728                case TY_INT:
2729                    oad(0x248489, l); /* movl %eax, xxx(%esp) */
2730                    return 4;
2731                case TY_FLOAT:
2732                    oad(0x249CD9, l); /* fstps   xxx(%esp) */
2733                    return 4;
2734                case TY_DOUBLE:
2735                    oad(0x249CDD, l); /* fstpl   xxx(%esp) */
2736                    return 8;
2737                default:
2738                    assert(false);
2739                    return 0;
2740            }
2741        }
2742
2743        virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
2744            * (int*) a = l;
2745        }
2746
2747        virtual int callForward(int symbol, Type* pFunc) {
2748            assert(pFunc->tag == TY_FUNC);
2749            setR0Type(pFunc->pHead);
2750            return psym(0xe8, symbol); /* call xxx */
2751        }
2752
2753        virtual void callIndirect(int l, Type* pFunc) {
2754            assert(pFunc->tag == TY_FUNC);
2755            popType(); // Get rid of indirect fn pointer type
2756            setR0Type(pFunc->pHead);
2757            oad(0x2494ff, l); /* call *xxx(%esp) */
2758        }
2759
2760        virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
2761            assert(pDecl->tag == TY_FUNC);
2762            if (isIndirect) {
2763                l += 4;
2764            }
2765            if (l > 0) {
2766                oad(0xc481, l); /* add $xxx, %esp */
2767            }
2768        }
2769
2770        virtual int jumpOffset() {
2771            return 5;
2772        }
2773
2774        virtual int disassemble(FILE* out) {
2775            return 0;
2776        }
2777
2778        /* output a symbol and patch all calls to it */
2779        virtual void gsym(int t) {
2780            int n;
2781            int pc = getPC();
2782            while (t) {
2783                n = *(int *) t; /* next value */
2784                *(int *) t = pc - t - 4;
2785                t = n;
2786            }
2787        }
2788
2789        /* output a symbol and patch all calls to it, using absolute address */
2790        virtual void resolveForward(int t) {
2791            int n;
2792            int pc = getPC();
2793            while (t) {
2794                n = *(int *) t; /* next value */
2795                *(int *) t = pc;
2796                t = n;
2797            }
2798        }
2799
2800        virtual int finishCompile() {
2801            size_t pagesize = 4096;
2802            size_t base = (size_t) getBase() & ~ (pagesize - 1);
2803            size_t top =  ((size_t) getPC() + pagesize - 1) & ~ (pagesize - 1);
2804            int err = mprotect((void*) base, top - base, PROT_READ | PROT_WRITE | PROT_EXEC);
2805            if (err) {
2806               error("mprotect() failed: %d", errno);
2807            }
2808            return err;
2809        }
2810
2811        /**
2812         * Alignment (in bytes) for this type of data
2813         */
2814        virtual size_t alignmentOf(Type* pType){
2815            switch (pType->tag) {
2816            case TY_CHAR:
2817                return 1;
2818            case TY_SHORT:
2819                return 2;
2820            case TY_ARRAY:
2821                return alignmentOf(pType->pHead);
2822            case TY_STRUCT:
2823                return pType->pHead->alignment & 0x7fffffff;
2824            case TY_FUNC:
2825                error("alignment of func not supported");
2826                return 1;
2827            default:
2828                return 4;
2829            }
2830        }
2831
2832        /**
2833         * Array element alignment (in bytes) for this type of data.
2834         */
2835        virtual size_t sizeOf(Type* pType){
2836            switch(pType->tag) {
2837                case TY_INT:
2838                    return 4;
2839                case TY_SHORT:
2840                    return 2;
2841                case TY_CHAR:
2842                    return 1;
2843                case TY_FLOAT:
2844                    return 4;
2845                case TY_DOUBLE:
2846                    return 8;
2847                case TY_POINTER:
2848                    return 4;
2849                case TY_ARRAY:
2850                    return pType->length * sizeOf(pType->pHead);
2851                case TY_STRUCT:
2852                    return pType->pHead->length;
2853                default:
2854                    error("Unsupported type %d", pType->tag);
2855                    return 0;
2856            }
2857        }
2858
2859    private:
2860
2861        /** Output 1 to 4 bytes.
2862         *
2863         */
2864        void o(int n) {
2865            /* cannot use unsigned, so we must do a hack */
2866            while (n && n != -1) {
2867                ob(n & 0xff);
2868                n = n >> 8;
2869            }
2870        }
2871
2872        /* Output exactly 2 bytes
2873         */
2874        void o2(int n) {
2875            ob(n & 0xff);
2876            ob(0xff & (n >> 8));
2877        }
2878
2879        /* psym is used to put an instruction with a data field which is a
2880         reference to a symbol. It is in fact the same as oad ! */
2881        int psym(int n, int t) {
2882            return oad(n, t);
2883        }
2884
2885        /* instruction + address */
2886        int oad(int n, int t) {
2887            o(n);
2888            int result = getPC();
2889            o4(t);
2890            return result;
2891        }
2892
2893        static const int operatorHelper[];
2894
2895        int decodeOp(int op) {
2896            if (op < 0 || op > OP_COUNT) {
2897                error("Out-of-range operator: %d\n", op);
2898                op = 0;
2899            }
2900            return operatorHelper[op];
2901        }
2902
2903        void gmov(int l, int t) {
2904            o(l + 0x83);
2905            oad((t > -LOCAL && t < LOCAL) << 7 | 5, t);
2906        }
2907
2908        void setupFloatOperands() {
2909            Type* pR0Type = getR0Type();
2910            Type* pTOSType = getTOSType();
2911            TypeTag tagR0 = pR0Type->tag;
2912            TypeTag tagTOS = pTOSType->tag;
2913            bool isFloatR0 = isFloatTag(tagR0);
2914            bool isFloatTOS = isFloatTag(tagTOS);
2915            if (! isFloatR0) {
2916                // Convert R0 from int to float
2917                o(0x50);      // push %eax
2918                o(0x2404DB);  // fildl 0(%esp)
2919                o(0x58);      // pop %eax
2920            }
2921            if (! isFloatTOS){
2922                o(0x2404DB);  // fildl 0(%esp);
2923                o(0x58);      // pop %eax
2924            } else {
2925                if (tagTOS == TY_FLOAT) {
2926                    o(0x2404d9);  // flds (%esp)
2927                    o(0x58);      // pop %eax
2928                } else {
2929                    o(0x2404dd);  // fldl (%esp)
2930                    o(0x58);      // pop %eax
2931                    o(0x58);      // pop %eax
2932                }
2933            }
2934            popType();
2935        }
2936    };
2937
2938#endif // PROVIDE_X86_CODEGEN
2939
2940#ifdef PROVIDE_TRACE_CODEGEN
2941    class TraceCodeGenerator : public CodeGenerator {
2942    private:
2943        CodeGenerator* mpBase;
2944
2945    public:
2946        TraceCodeGenerator(CodeGenerator* pBase) {
2947            mpBase = pBase;
2948        }
2949
2950        virtual ~TraceCodeGenerator() {
2951            delete mpBase;
2952        }
2953
2954        virtual void init(CodeBuf* pCodeBuf) {
2955            mpBase->init(pCodeBuf);
2956        }
2957
2958        void setErrorSink(ErrorSink* pErrorSink) {
2959            mpBase->setErrorSink(pErrorSink);
2960        }
2961
2962        /* returns address to patch with local variable size
2963        */
2964        virtual int functionEntry(Type* pDecl) {
2965            int result = mpBase->functionEntry(pDecl);
2966            fprintf(stderr, "functionEntry(pDecl) -> %d\n", result);
2967            return result;
2968        }
2969
2970        virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) {
2971            fprintf(stderr, "functionExit(pDecl, %d, %d)\n",
2972                    localVariableAddress, localVariableSize);
2973            mpBase->functionExit(pDecl, localVariableAddress, localVariableSize);
2974        }
2975
2976        /* load immediate value */
2977        virtual void li(int t) {
2978            fprintf(stderr, "li(%d)\n", t);
2979            mpBase->li(t);
2980        }
2981
2982        virtual void loadFloat(int address, Type* pType) {
2983            fprintf(stderr, "loadFloat(%d, type=%d)\n", address, pType->tag);
2984            mpBase->loadFloat(address, pType);
2985        }
2986
2987        virtual void addStructOffsetR0(int offset, Type* pType) {
2988            fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
2989            mpBase->addStructOffsetR0(offset, pType);
2990        }
2991
2992        virtual int gjmp(int t) {
2993            int result = mpBase->gjmp(t);
2994            fprintf(stderr, "gjmp(%d) = %d\n", t, result);
2995            return result;
2996        }
2997
2998        /* l = 0: je, l == 1: jne */
2999        virtual int gtst(bool l, int t) {
3000            int result = mpBase->gtst(l, t);
3001            fprintf(stderr, "gtst(%d,%d) = %d\n", l, t, result);
3002            return result;
3003        }
3004
3005        virtual void gcmp(int op) {
3006            fprintf(stderr, "gcmp(%d)\n", op);
3007            mpBase->gcmp(op);
3008        }
3009
3010        virtual void genOp(int op) {
3011            fprintf(stderr, "genOp(%d)\n", op);
3012            mpBase->genOp(op);
3013        }
3014
3015
3016        virtual void gUnaryCmp(int op) {
3017            fprintf(stderr, "gUnaryCmp(%d)\n", op);
3018            mpBase->gUnaryCmp(op);
3019        }
3020
3021        virtual void genUnaryOp(int op) {
3022            fprintf(stderr, "genUnaryOp(%d)\n", op);
3023            mpBase->genUnaryOp(op);
3024        }
3025
3026        virtual void pushR0() {
3027            fprintf(stderr, "pushR0()\n");
3028            mpBase->pushR0();
3029        }
3030
3031        virtual void over() {
3032            fprintf(stderr, "over()\n");
3033            mpBase->over();
3034        }
3035
3036        virtual void popR0() {
3037            fprintf(stderr, "popR0()\n");
3038            mpBase->popR0();
3039        }
3040
3041        virtual void storeR0ToTOS() {
3042            fprintf(stderr, "storeR0ToTOS()\n");
3043            mpBase->storeR0ToTOS();
3044        }
3045
3046        virtual void loadR0FromR0() {
3047            fprintf(stderr, "loadR0FromR0()\n");
3048            mpBase->loadR0FromR0();
3049        }
3050
3051        virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
3052            fprintf(stderr, "leaR0(%d, %d, %d)\n", ea,
3053                    pPointerType->pHead->tag, et);
3054            mpBase->leaR0(ea, pPointerType, et);
3055        }
3056
3057        virtual int leaForward(int ea, Type* pPointerType) {
3058            fprintf(stderr, "leaForward(%d)\n", ea);
3059            return mpBase->leaForward(ea, pPointerType);
3060        }
3061
3062        virtual void convertR0Imp(Type* pType, bool isCast){
3063            fprintf(stderr, "convertR0(pType tag=%d, %d)\n",  pType->tag, isCast);
3064            mpBase->convertR0Imp(pType, isCast);
3065        }
3066
3067        virtual int beginFunctionCallArguments() {
3068            int result = mpBase->beginFunctionCallArguments();
3069            fprintf(stderr, "beginFunctionCallArguments() = %d\n", result);
3070            return result;
3071        }
3072
3073        virtual size_t storeR0ToArg(int l, Type* pArgType) {
3074            fprintf(stderr, "storeR0ToArg(%d, pArgType=%d)\n", l,
3075                    pArgType->tag);
3076            return mpBase->storeR0ToArg(l, pArgType);
3077        }
3078
3079        virtual void endFunctionCallArguments(Type* pDecl, int a, int l) {
3080            fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l);
3081            mpBase->endFunctionCallArguments(pDecl, a, l);
3082        }
3083
3084        virtual int callForward(int symbol, Type* pFunc) {
3085            int result = mpBase->callForward(symbol, pFunc);
3086            fprintf(stderr, "callForward(%d) = %d\n", symbol, result);
3087            return result;
3088        }
3089
3090        virtual void callIndirect(int l, Type* pFunc) {
3091            fprintf(stderr, "callIndirect(%d returntype = %d)\n", l,
3092                    pFunc->pHead->tag);
3093            mpBase->callIndirect(l, pFunc);
3094        }
3095
3096        virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) {
3097            fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect);
3098            mpBase->adjustStackAfterCall(pDecl, l, isIndirect);
3099        }
3100
3101        virtual int jumpOffset() {
3102            return mpBase->jumpOffset();
3103        }
3104
3105        virtual int disassemble(FILE* out) {
3106            return mpBase->disassemble(out);
3107        }
3108
3109        /* output a symbol and patch all calls to it */
3110        virtual void gsym(int t) {
3111            fprintf(stderr, "gsym(%d)\n", t);
3112            mpBase->gsym(t);
3113        }
3114
3115        virtual void resolveForward(int t) {
3116            mpBase->resolveForward(t);
3117        }
3118
3119        virtual int finishCompile() {
3120            int result = mpBase->finishCompile();
3121            fprintf(stderr, "finishCompile() = %d\n", result);
3122            return result;
3123        }
3124
3125        /**
3126         * Alignment (in bytes) for this type of data
3127         */
3128        virtual size_t alignmentOf(Type* pType){
3129            return mpBase->alignmentOf(pType);
3130        }
3131
3132        /**
3133         * Array element alignment (in bytes) for this type of data.
3134         */
3135        virtual size_t sizeOf(Type* pType){
3136            return mpBase->sizeOf(pType);
3137        }
3138
3139        virtual Type* getR0Type() {
3140            return mpBase->getR0Type();
3141        }
3142
3143        virtual ExpressionType getR0ExpressionType() {
3144            return mpBase->getR0ExpressionType();
3145        }
3146
3147        virtual void setR0ExpressionType(ExpressionType et) {
3148            mpBase->setR0ExpressionType(et);
3149        }
3150
3151        virtual size_t getExpressionStackDepth() {
3152            return mpBase->getExpressionStackDepth();
3153        }
3154
3155        virtual void forceR0RVal() {
3156            return mpBase->forceR0RVal();
3157        }
3158    };
3159
3160#endif // PROVIDE_TRACE_CODEGEN
3161
3162    class Arena {
3163    public:
3164        // Used to record a given allocation amount.
3165        // Used:
3166        // Mark mark = arena.mark();
3167        // ... lots of arena.allocate()
3168        // arena.free(mark);
3169
3170        struct Mark {
3171            size_t chunk;
3172            size_t offset;
3173        };
3174
3175        Arena() {
3176            mCurrentChunk = 0;
3177            Chunk start(CHUNK_SIZE);
3178            mData.push_back(start);
3179        }
3180
3181        ~Arena() {
3182            for(size_t i = 0; i < mData.size(); i++) {
3183                mData[i].free();
3184            }
3185        }
3186
3187        // Alloc using the standard alignment size safe for any variable
3188        void* alloc(size_t size) {
3189            return alloc(size, 8);
3190        }
3191
3192        Mark mark(){
3193            Mark result;
3194            result.chunk = mCurrentChunk;
3195            result.offset = mData[mCurrentChunk].mOffset;
3196            return result;
3197        }
3198
3199        void freeToMark(const Mark& mark) {
3200            mCurrentChunk = mark.chunk;
3201            mData[mCurrentChunk].mOffset = mark.offset;
3202        }
3203
3204    private:
3205        // Allocate memory aligned to a given size
3206        // and a given power-of-two-sized alignment (e.g. 1,2,4,8,...)
3207        // Memory is not zero filled.
3208
3209        void* alloc(size_t size, size_t alignment) {
3210            while (size > mData[mCurrentChunk].remainingCapacity(alignment)) {
3211                if (mCurrentChunk + 1 < mData.size()) {
3212                    mCurrentChunk++;
3213                } else {
3214                    size_t allocSize = CHUNK_SIZE;
3215                    if (allocSize < size + alignment - 1) {
3216                        allocSize = size + alignment - 1;
3217                    }
3218                    Chunk chunk(allocSize);
3219                    mData.push_back(chunk);
3220                    mCurrentChunk++;
3221                }
3222            }
3223            return mData[mCurrentChunk].allocate(size, alignment);
3224        }
3225
3226        static const size_t CHUNK_SIZE = 128*1024;
3227        // Note: this class does not deallocate its
3228        // memory when it's destroyed. It depends upon
3229        // its parent to deallocate the memory.
3230        struct Chunk {
3231            Chunk() {
3232                mpData = 0;
3233                mSize = 0;
3234                mOffset = 0;
3235            }
3236
3237            Chunk(size_t size) {
3238                mSize = size;
3239                mpData = (char*) malloc(size);
3240                mOffset = 0;
3241            }
3242
3243            ~Chunk() {
3244                // Doesn't deallocate memory.
3245            }
3246
3247            void* allocate(size_t size, size_t alignment) {
3248                size_t alignedOffset = aligned(mOffset, alignment);
3249                void* result = mpData + alignedOffset;
3250                mOffset = alignedOffset + size;
3251                return result;
3252            }
3253
3254            void free() {
3255                if (mpData) {
3256                    ::free(mpData);
3257                    mpData = 0;
3258                }
3259            }
3260
3261            size_t remainingCapacity(size_t alignment) {
3262                return aligned(mSize, alignment) - aligned(mOffset, alignment);
3263            }
3264
3265            // Assume alignment is a power of two
3266            inline size_t aligned(size_t v, size_t alignment) {
3267                size_t mask = alignment-1;
3268                return (v + mask) & ~mask;
3269            }
3270
3271            char* mpData;
3272            size_t mSize;
3273            size_t mOffset;
3274        };
3275
3276        size_t mCurrentChunk;
3277
3278        Vector<Chunk> mData;
3279    };
3280
3281    struct VariableInfo;
3282
3283    struct Token {
3284        int hash;
3285        size_t length;
3286        char* pText;
3287        tokenid_t id;
3288
3289        // Current values for the token
3290        char* mpMacroDefinition;
3291        VariableInfo* mpVariableInfo;
3292        VariableInfo* mpStructInfo;
3293    };
3294
3295    class TokenTable {
3296    public:
3297        // Don't use 0..0xff, allows characters and operators to be tokens too.
3298
3299        static const int TOKEN_BASE = 0x100;
3300        TokenTable() {
3301            mpMap = hashmapCreate(128, hashFn, equalsFn);
3302        }
3303
3304        ~TokenTable() {
3305            hashmapFree(mpMap);
3306        }
3307
3308        void setArena(Arena* pArena) {
3309            mpArena = pArena;
3310        }
3311
3312        // Returns a token for a given string of characters.
3313        tokenid_t intern(const char* pText, size_t length) {
3314            Token probe;
3315            int hash = hashmapHash((void*) pText, length);
3316            {
3317                Token probe;
3318                probe.hash = hash;
3319                probe.length = length;
3320                probe.pText = (char*) pText;
3321                Token* pValue = (Token*) hashmapGet(mpMap, &probe);
3322                if (pValue) {
3323                    return pValue->id;
3324                }
3325            }
3326
3327            Token* pToken = (Token*) mpArena->alloc(sizeof(Token));
3328            memset(pToken, 0, sizeof(*pToken));
3329            pToken->hash = hash;
3330            pToken->length = length;
3331            pToken->pText = (char*) mpArena->alloc(length + 1);
3332            memcpy(pToken->pText, pText, length);
3333            pToken->pText[length] = 0;
3334            pToken->id = mTokens.size() + TOKEN_BASE;
3335            mTokens.push_back(pToken);
3336            hashmapPut(mpMap, pToken, pToken);
3337            return pToken->id;
3338        }
3339
3340        // Return the Token for a given tokenid.
3341        Token& operator[](tokenid_t id) {
3342            return *mTokens[id - TOKEN_BASE];
3343        }
3344
3345        inline size_t size() {
3346            return mTokens.size();
3347        }
3348
3349    private:
3350
3351        static int hashFn(void* pKey) {
3352            Token* pToken = (Token*) pKey;
3353            return pToken->hash;
3354        }
3355
3356        static bool equalsFn(void* keyA, void* keyB) {
3357            Token* pTokenA = (Token*) keyA;
3358            Token* pTokenB = (Token*) keyB;
3359            // Don't need to compare hash values, they should always be equal
3360            return pTokenA->length == pTokenB->length
3361                && strcmp(pTokenA->pText, pTokenB->pText) == 0;
3362        }
3363
3364        Hashmap* mpMap;
3365        Vector<Token*> mTokens;
3366        Arena* mpArena;
3367    };
3368
3369    class InputStream {
3370    public:
3371        virtual ~InputStream() {}
3372        virtual int getChar() = 0;
3373    };
3374
3375    class TextInputStream : public InputStream {
3376    public:
3377        TextInputStream(const char* text, size_t textLength)
3378            : pText(text), mTextLength(textLength), mPosition(0) {
3379        }
3380
3381        virtual int getChar() {
3382            return mPosition < mTextLength ? pText[mPosition++] : EOF;
3383        }
3384
3385    private:
3386        const char* pText;
3387        size_t mTextLength;
3388        size_t mPosition;
3389    };
3390
3391    class String {
3392    public:
3393        String() {
3394            mpBase = 0;
3395            mUsed = 0;
3396            mSize = 0;
3397        }
3398
3399        String(const char* item, int len, bool adopt) {
3400            if (len < 0) {
3401                len = strlen(item);
3402            }
3403            if (adopt) {
3404                mpBase = (char*) item;
3405                mUsed = len;
3406                mSize = len + 1;
3407            } else {
3408                mpBase = 0;
3409                mUsed = 0;
3410                mSize = 0;
3411                appendBytes(item, len);
3412            }
3413        }
3414
3415        String(const String& other) {
3416            mpBase = 0;
3417            mUsed = 0;
3418            mSize = 0;
3419            appendBytes(other.getUnwrapped(), other.len());
3420        }
3421
3422        ~String() {
3423            if (mpBase) {
3424                free(mpBase);
3425            }
3426        }
3427
3428        String& operator=(const String& other) {
3429            clear();
3430            appendBytes(other.getUnwrapped(), other.len());
3431            return *this;
3432        }
3433
3434        inline char* getUnwrapped() const {
3435            return mpBase;
3436        }
3437
3438        void clear() {
3439            mUsed = 0;
3440            if (mSize > 0) {
3441                mpBase[0] = 0;
3442            }
3443        }
3444
3445        void appendCStr(const char* s) {
3446            appendBytes(s, strlen(s));
3447        }
3448
3449        void appendBytes(const char* s, int n) {
3450            memcpy(ensure(n), s, n + 1);
3451        }
3452
3453        void append(char c) {
3454            * ensure(1) = c;
3455        }
3456
3457        void append(String& other) {
3458            appendBytes(other.getUnwrapped(), other.len());
3459        }
3460
3461        char* orphan() {
3462            char* result = mpBase;
3463            mpBase = 0;
3464            mUsed = 0;
3465            mSize = 0;
3466            return result;
3467        }
3468
3469        void printf(const char* fmt,...) {
3470            va_list ap;
3471            va_start(ap, fmt);
3472            vprintf(fmt, ap);
3473            va_end(ap);
3474        }
3475
3476        void vprintf(const char* fmt, va_list ap) {
3477            char* temp;
3478            int numChars = vasprintf(&temp, fmt, ap);
3479            memcpy(ensure(numChars), temp, numChars+1);
3480            free(temp);
3481        }
3482
3483        inline size_t len() const {
3484            return mUsed;
3485        }
3486
3487    private:
3488        char* ensure(int n) {
3489            size_t newUsed = mUsed + n;
3490            if (newUsed > mSize) {
3491                size_t newSize = mSize * 2 + 10;
3492                if (newSize < newUsed) {
3493                    newSize = newUsed;
3494                }
3495                mpBase = (char*) realloc(mpBase, newSize + 1);
3496                mSize = newSize;
3497            }
3498            mpBase[newUsed] = '\0';
3499            char* result = mpBase + mUsed;
3500            mUsed = newUsed;
3501            return result;
3502        }
3503
3504        char* mpBase;
3505        size_t mUsed;
3506        size_t mSize;
3507    };
3508
3509    void internKeywords() {
3510        // Note: order has to match TOK_ constants
3511        static const char* keywords[] = {
3512            "int",
3513            "char",
3514            "void",
3515            "if",
3516            "else",
3517            "while",
3518            "break",
3519            "return",
3520            "for",
3521            "auto",
3522            "case",
3523            "const",
3524            "continue",
3525            "default",
3526            "do",
3527            "double",
3528            "enum",
3529            "extern",
3530            "float",
3531            "goto",
3532            "long",
3533            "register",
3534            "short",
3535            "signed",
3536            "sizeof",
3537            "static",
3538            "struct",
3539            "switch",
3540            "typedef",
3541            "union",
3542            "unsigned",
3543            "volatile",
3544            "_Bool",
3545            "_Complex",
3546            "_Imaginary",
3547            "inline",
3548            "restrict",
3549
3550            // predefined tokens that can also be symbols start here:
3551            "pragma",
3552            "define",
3553            "line",
3554            0};
3555
3556        for(int i = 0; keywords[i]; i++) {
3557            mTokenTable.intern(keywords[i], strlen(keywords[i]));
3558        }
3559    }
3560
3561    struct InputState {
3562        InputStream* pStream;
3563        int oldCh;
3564    };
3565
3566    struct VariableInfo {
3567        void* pAddress;
3568        void* pForward; // For a forward direction, linked list of data to fix up
3569        tokenid_t tok;
3570        size_t level;
3571        VariableInfo* pOldDefinition;
3572        Type* pType;
3573        bool isStructTag;
3574    };
3575
3576    class SymbolStack {
3577    public:
3578        SymbolStack() {
3579            mpArena = 0;
3580            mpTokenTable = 0;
3581        }
3582
3583        void setArena(Arena* pArena) {
3584            mpArena = pArena;
3585        }
3586
3587        void setTokenTable(TokenTable* pTokenTable) {
3588            mpTokenTable = pTokenTable;
3589        }
3590
3591        void pushLevel() {
3592            Mark mark;
3593            mark.mArenaMark = mpArena->mark();
3594            mark.mSymbolHead = mStack.size();
3595            mLevelStack.push_back(mark);
3596        }
3597
3598        void popLevel() {
3599            // Undo any shadowing that was done:
3600            Mark mark = mLevelStack.back();
3601            mLevelStack.pop_back();
3602            while (mStack.size() > mark.mSymbolHead) {
3603                VariableInfo* pV = mStack.back();
3604                mStack.pop_back();
3605                if (pV->isStructTag) {
3606                    (*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
3607                } else {
3608                    (*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
3609                }
3610            }
3611            mpArena->freeToMark(mark.mArenaMark);
3612        }
3613
3614        bool isDefinedAtCurrentLevel(tokenid_t tok) {
3615            VariableInfo* pV = (*mpTokenTable)[tok].mpVariableInfo;
3616            return pV && pV->level == level();
3617        }
3618
3619        bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
3620            VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
3621            return pV && pV->level == level();
3622        }
3623
3624        VariableInfo* add(tokenid_t tok) {
3625            Token& token = (*mpTokenTable)[tok];
3626            VariableInfo* pOldV = token.mpVariableInfo;
3627            VariableInfo* pNewV =
3628                (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3629            memset(pNewV, 0, sizeof(VariableInfo));
3630            pNewV->tok = tok;
3631            pNewV->level = level();
3632            pNewV->pOldDefinition = pOldV;
3633            token.mpVariableInfo = pNewV;
3634            mStack.push_back(pNewV);
3635            return pNewV;
3636        }
3637
3638        VariableInfo* addStructTag(tokenid_t tok) {
3639            Token& token = (*mpTokenTable)[tok];
3640            VariableInfo* pOldS = token.mpStructInfo;
3641            VariableInfo* pNewS =
3642                (VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
3643            memset(pNewS, 0, sizeof(VariableInfo));
3644            pNewS->tok = tok;
3645            pNewS->level = level();
3646            pNewS->isStructTag = true;
3647            pNewS->pOldDefinition = pOldS;
3648            token.mpStructInfo = pNewS;
3649            mStack.push_back(pNewS);
3650            return pNewS;
3651        }
3652
3653        VariableInfo* add(Type* pType) {
3654            VariableInfo* pVI = add(pType->id);
3655            pVI->pType = pType;
3656            return pVI;
3657        }
3658
3659        void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
3660            for (size_t i = 0; i < mStack.size(); i++) {
3661                if (! fn(mStack[i], context)) {
3662                    break;
3663                }
3664            }
3665        }
3666
3667    private:
3668        inline size_t level() {
3669            return mLevelStack.size();
3670        }
3671
3672        struct Mark {
3673            Arena::Mark mArenaMark;
3674            size_t mSymbolHead;
3675        };
3676
3677        Arena* mpArena;
3678        TokenTable* mpTokenTable;
3679        Vector<VariableInfo*> mStack;
3680        Vector<Mark> mLevelStack;
3681    };
3682
3683    int ch; // Current input character, or EOF
3684    tokenid_t tok;      // token
3685    intptr_t tokc;    // token extra info
3686    double tokd;     // floating point constant value
3687    int tokl;         // token operator level
3688    intptr_t rsym; // return symbol
3689    Type* pReturnType; // type of the current function's return.
3690    intptr_t loc; // local variable index
3691    char* glo;  // global variable index
3692    String mTokenString;
3693    bool mbSuppressMacroExpansion;
3694    char* dptr; // Macro state: Points to macro text during macro playback.
3695    int dch;    // Macro state: Saves old value of ch during a macro playback.
3696    char* pGlobalBase;
3697    ACCSymbolLookupFn mpSymbolLookupFn;
3698    void* mpSymbolLookupContext;
3699
3700    // Arena for the duration of the compile
3701    Arena mGlobalArena;
3702    // Arena for data that's only needed when compiling a single function
3703    Arena mLocalArena;
3704
3705    Arena* mpCurrentArena;
3706
3707    TokenTable mTokenTable;
3708    SymbolStack mGlobals;
3709    SymbolStack mLocals;
3710
3711    SymbolStack* mpCurrentSymbolStack;
3712
3713    // Prebuilt types, makes things slightly faster.
3714    Type* mkpInt;        // int
3715    Type* mkpShort;      // short
3716    Type* mkpChar;       // char
3717    Type* mkpVoid;       // void
3718    Type* mkpFloat;
3719    Type* mkpDouble;
3720    Type* mkpIntFn;
3721    Type* mkpIntPtr;
3722    Type* mkpCharPtr;
3723    Type* mkpFloatPtr;
3724    Type* mkpDoublePtr;
3725    Type* mkpPtrIntFn;
3726
3727    InputStream* file;
3728    int mLineNumber;
3729    bool mbBumpLine;
3730
3731    CodeBuf codeBuf;
3732    CodeGenerator* pGen;
3733
3734    String mErrorBuf;
3735
3736    String mPragmas;
3737    int mPragmaStringCount;
3738    int mCompileResult;
3739
3740    static const int ALLOC_SIZE = 99999;
3741
3742    static const int TOK_DUMMY = 1;
3743    static const int TOK_NUM = 2;
3744    static const int TOK_NUM_FLOAT = 3;
3745    static const int TOK_NUM_DOUBLE = 4;
3746    static const int TOK_OP_ASSIGNMENT = 5;
3747    static const int TOK_OP_ARROW = 6;
3748
3749    // 3..255 are character and/or operators
3750
3751    // Keywords start at 0x100 and increase by 1
3752    // Order has to match string list in "internKeywords".
3753    enum {
3754        TOK_KEYWORD = TokenTable::TOKEN_BASE,
3755        TOK_INT = TOK_KEYWORD,
3756        TOK_CHAR,
3757        TOK_VOID,
3758        TOK_IF,
3759        TOK_ELSE,
3760        TOK_WHILE,
3761        TOK_BREAK,
3762        TOK_RETURN,
3763        TOK_FOR,
3764        TOK_AUTO,
3765        TOK_CASE,
3766        TOK_CONST,
3767        TOK_CONTINUE,
3768        TOK_DEFAULT,
3769        TOK_DO,
3770        TOK_DOUBLE,
3771        TOK_ENUM,
3772        TOK_EXTERN,
3773        TOK_FLOAT,
3774        TOK_GOTO,
3775        TOK_LONG,
3776        TOK_REGISTER,
3777        TOK_SHORT,
3778        TOK_SIGNED,
3779        TOK_SIZEOF,
3780        TOK_STATIC,
3781        TOK_STRUCT,
3782        TOK_SWITCH,
3783        TOK_TYPEDEF,
3784        TOK_UNION,
3785        TOK_UNSIGNED,
3786        TOK_VOLATILE,
3787        TOK__BOOL,
3788        TOK__COMPLEX,
3789        TOK__IMAGINARY,
3790        TOK_INLINE,
3791        TOK_RESTRICT,
3792
3793        // Symbols start after keywords
3794
3795        TOK_SYMBOL,
3796        TOK_PRAGMA = TOK_SYMBOL,
3797        TOK_DEFINE,
3798        TOK_LINE
3799    };
3800
3801    static const int LOCAL = 0x200;
3802
3803    static const int SYM_FORWARD = 0;
3804    static const int SYM_DEFINE = 1;
3805
3806    /* tokens in string heap */
3807    static const int TAG_TOK = ' ';
3808
3809    static const int OP_INCREMENT = 0;
3810    static const int OP_DECREMENT = 1;
3811    static const int OP_MUL = 2;
3812    static const int OP_DIV = 3;
3813    static const int OP_MOD = 4;
3814    static const int OP_PLUS = 5;
3815    static const int OP_MINUS = 6;
3816    static const int OP_SHIFT_LEFT = 7;
3817    static const int OP_SHIFT_RIGHT = 8;
3818    static const int OP_LESS_EQUAL = 9;
3819    static const int OP_GREATER_EQUAL = 10;
3820    static const int OP_LESS = 11;
3821    static const int OP_GREATER = 12;
3822    static const int OP_EQUALS = 13;
3823    static const int OP_NOT_EQUALS = 14;
3824    static const int OP_LOGICAL_AND = 15;
3825    static const int OP_LOGICAL_OR = 16;
3826    static const int OP_BIT_AND = 17;
3827    static const int OP_BIT_XOR = 18;
3828    static const int OP_BIT_OR = 19;
3829    static const int OP_BIT_NOT = 20;
3830    static const int OP_LOGICAL_NOT = 21;
3831    static const int OP_COUNT = 22;
3832
3833    /* Operators are searched from front, the two-character operators appear
3834     * before the single-character operators with the same first character.
3835     * @ is used to pad out single-character operators.
3836     */
3837    static const char* operatorChars;
3838    static const char operatorLevel[];
3839
3840    /* Called when we detect an internal problem. Does nothing in production.
3841     *
3842     */
3843    void internalError() {
3844        * (char*) 0 = 0;
3845    }
3846
3847    void assertImpl(bool isTrue, int line) {
3848        if (!isTrue) {
3849            LOGD("%d: assertion failed at line %s:%d.", mLineNumber, __FILE__, line);
3850            internalError();
3851        }
3852    }
3853
3854    bool isSymbol(tokenid_t t) {
3855        return t >= TOK_SYMBOL &&
3856            ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
3857    }
3858
3859    bool isSymbolOrKeyword(tokenid_t t) {
3860        return t >= TOK_KEYWORD &&
3861            ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
3862    }
3863
3864    VariableInfo* VI(tokenid_t t) {
3865        assert(isSymbol(t));
3866        VariableInfo* pV = mTokenTable[t].mpVariableInfo;
3867        if (pV && pV->tok != t) {
3868            internalError();
3869        }
3870        return pV;
3871    }
3872
3873    inline bool isDefined(tokenid_t t) {
3874        return t >= TOK_SYMBOL && VI(t) != 0;
3875    }
3876
3877    const char* nameof(tokenid_t t) {
3878        assert(isSymbolOrKeyword(t));
3879        return mTokenTable[t].pText;
3880    }
3881
3882    void pdef(int t) {
3883        mTokenString.append(t);
3884    }
3885
3886    void inp() {
3887        if (dptr) {
3888            ch = *dptr++;
3889            if (ch == 0) {
3890                dptr = 0;
3891                ch = dch;
3892            }
3893        } else {
3894            if (mbBumpLine) {
3895                mLineNumber++;
3896                mbBumpLine = false;
3897            }
3898            ch = file->getChar();
3899            if (ch == '\n') {
3900                mbBumpLine = true;
3901            }
3902        }
3903#if 0
3904        printf("ch='%c' 0x%x\n", ch, ch);
3905#endif
3906    }
3907
3908    int isid() {
3909        return isalnum(ch) | (ch == '_');
3910    }
3911
3912    int decodeHex(int c) {
3913        if (isdigit(c)) {
3914            c -= '0';
3915        } else if (c <= 'F') {
3916            c = c - 'A' + 10;
3917        } else {
3918            c =c - 'a' + 10;
3919        }
3920        return c;
3921    }
3922
3923    /* read a character constant, advances ch to after end of constant */
3924    int getq() {
3925        int val = ch;
3926        if (ch == '\\') {
3927            inp();
3928            if (isoctal(ch)) {
3929                // 1 to 3 octal characters.
3930                val = 0;
3931                for(int i = 0; i < 3; i++) {
3932                    if (isoctal(ch)) {
3933                        val = (val << 3) + ch - '0';
3934                        inp();
3935                    }
3936                }
3937                return val;
3938            } else if (ch == 'x' || ch == 'X') {
3939                // N hex chars
3940                inp();
3941                if (! isxdigit(ch)) {
3942                    error("'x' character escape requires at least one digit.");
3943                } else {
3944                    val = 0;
3945                    while (isxdigit(ch)) {
3946                        val = (val << 4) + decodeHex(ch);
3947                        inp();
3948                    }
3949                }
3950            } else {
3951                int val = ch;
3952                switch (ch) {
3953                    case 'a':
3954                        val = '\a';
3955                        break;
3956                    case 'b':
3957                        val = '\b';
3958                        break;
3959                    case 'f':
3960                        val = '\f';
3961                        break;
3962                    case 'n':
3963                        val = '\n';
3964                        break;
3965                    case 'r':
3966                        val = '\r';
3967                        break;
3968                    case 't':
3969                        val = '\t';
3970                        break;
3971                    case 'v':
3972                        val = '\v';
3973                        break;
3974                    case '\\':
3975                        val = '\\';
3976                        break;
3977                    case '\'':
3978                        val = '\'';
3979                        break;
3980                    case '"':
3981                        val = '"';
3982                        break;
3983                    case '?':
3984                        val = '?';
3985                        break;
3986                    default:
3987                        error("Undefined character escape %c", ch);
3988                        break;
3989                }
3990                inp();
3991                return val;
3992            }
3993        } else {
3994            inp();
3995        }
3996        return val;
3997    }
3998
3999    static bool isoctal(int ch) {
4000        return ch >= '0' && ch <= '7';
4001    }
4002
4003    bool acceptCh(int c) {
4004        bool result = c == ch;
4005        if (result) {
4006            pdef(ch);
4007            inp();
4008        }
4009        return result;
4010    }
4011
4012    bool acceptDigitsCh() {
4013        bool result = false;
4014        while (isdigit(ch)) {
4015            result = true;
4016            pdef(ch);
4017            inp();
4018        }
4019        return result;
4020    }
4021
4022    void parseFloat() {
4023        tok = TOK_NUM_DOUBLE;
4024        // mTokenString already has the integral part of the number.
4025        if(mTokenString.len() == 0) {
4026            mTokenString.append('0');
4027        }
4028        acceptCh('.');
4029        acceptDigitsCh();
4030        if (acceptCh('e') || acceptCh('E')) {
4031            acceptCh('-') || acceptCh('+');
4032            acceptDigitsCh();
4033        }
4034        if (ch == 'f' || ch == 'F') {
4035            tok = TOK_NUM_FLOAT;
4036            inp();
4037        } else if (ch == 'l' || ch == 'L') {
4038            inp();
4039            error("Long floating point constants not supported.");
4040        }
4041        char* pText = mTokenString.getUnwrapped();
4042        char* pEnd = pText + strlen(pText);
4043        char* pEndPtr = 0;
4044        errno = 0;
4045        if (tok == TOK_NUM_FLOAT) {
4046            tokd = strtof(pText, &pEndPtr);
4047        } else {
4048            tokd = strtod(pText, &pEndPtr);
4049        }
4050        if (errno || pEndPtr != pEnd) {
4051            error("Can't parse constant: %s", pText);
4052        }
4053        // fprintf(stderr, "float constant: %s (%d) %g\n", pText, tok, tokd);
4054    }
4055
4056    void next() {
4057        int l, a;
4058
4059        while (isspace(ch) | (ch == '#')) {
4060            if (ch == '#') {
4061                inp();
4062                next();
4063                if (tok == TOK_DEFINE) {
4064                    doDefine();
4065                } else if (tok == TOK_PRAGMA) {
4066                    doPragma();
4067                } else if (tok == TOK_LINE) {
4068                    doLine();
4069                } else {
4070                    error("Unsupported preprocessor directive \"%s\"",
4071                          mTokenString.getUnwrapped());
4072                }
4073            }
4074            inp();
4075        }
4076        tokl = 0;
4077        tok = ch;
4078        /* encode identifiers & numbers */
4079        if (isdigit(ch) || ch == '.') {
4080            // Start of a numeric constant. Could be integer, float, or
4081            // double, won't know until we look further.
4082            mTokenString.clear();
4083            pdef(ch);
4084            inp();
4085            if (tok == '.' && !isdigit(ch)) {
4086                goto done;
4087            }
4088            int base = 10;
4089            if (tok == '0') {
4090                if (ch == 'x' || ch == 'X') {
4091                    base = 16;
4092                    tok = TOK_NUM;
4093                    tokc = 0;
4094                    inp();
4095                    while ( isxdigit(ch) ) {
4096                        tokc = (tokc << 4) + decodeHex(ch);
4097                        inp();
4098                    }
4099                } else if (isoctal(ch)){
4100                    base = 8;
4101                    tok = TOK_NUM;
4102                    tokc = 0;
4103                    while ( isoctal(ch) ) {
4104                        tokc = (tokc << 3) + (ch - '0');
4105                        inp();
4106                    }
4107                }
4108            } else if (isdigit(tok)){
4109                acceptDigitsCh();
4110            }
4111            if (base == 10) {
4112                if (tok == '.' || ch == '.' || ch == 'e' || ch == 'E') {
4113                    parseFloat();
4114                } else {
4115                    // It's an integer constant
4116                    char* pText = mTokenString.getUnwrapped();
4117                    char* pEnd = pText + strlen(pText);
4118                    char* pEndPtr = 0;
4119                    errno = 0;
4120                    tokc = strtol(pText, &pEndPtr, base);
4121                    if (errno || pEndPtr != pEnd) {
4122                        error("Can't parse constant: %s %d %d", pText, base, errno);
4123                    }
4124                    tok = TOK_NUM;
4125                }
4126            }
4127        } else if (isid()) {
4128            mTokenString.clear();
4129            while (isid()) {
4130                pdef(ch);
4131                inp();
4132            }
4133            tok = mTokenTable.intern(mTokenString.getUnwrapped(), mTokenString.len());
4134            if (! mbSuppressMacroExpansion) {
4135                // Is this a macro?
4136                char* pMacroDefinition = mTokenTable[tok].mpMacroDefinition;
4137                if (pMacroDefinition) {
4138                    // Yes, it is a macro
4139                    dptr = pMacroDefinition;
4140                    dch = ch;
4141                    inp();
4142                    next();
4143                }
4144            }
4145        } else {
4146            inp();
4147            if (tok == '\'') {
4148                tok = TOK_NUM;
4149                tokc = getq();
4150                if (ch != '\'') {
4151                    error("Expected a ' character, got %c", ch);
4152                } else {
4153                  inp();
4154                }
4155            } else if ((tok == '/') & (ch == '*')) {
4156                inp();
4157                while (ch && ch != EOF) {
4158                    while (ch != '*' && ch != EOF)
4159                        inp();
4160                    inp();
4161                    if (ch == '/')
4162                        ch = 0;
4163                }
4164                if (ch == EOF) {
4165                    error("End of file inside comment.");
4166                }
4167                inp();
4168                next();
4169            } else if ((tok == '/') & (ch == '/')) {
4170                inp();
4171                while (ch && (ch != '\n') && (ch != EOF)) {
4172                    inp();
4173                }
4174                inp();
4175                next();
4176            } else if ((tok == '-') & (ch == '>')) {
4177                inp();
4178                tok = TOK_OP_ARROW;
4179            } else {
4180                const char* t = operatorChars;
4181                int opIndex = 0;
4182                while ((l = *t++) != 0) {
4183                    a = *t++;
4184                    tokl = operatorLevel[opIndex];
4185                    tokc = opIndex;
4186                    if ((l == tok) & ((a == ch) | (a == '@'))) {
4187#if 0
4188                        printf("%c%c -> tokl=%d tokc=0x%x\n",
4189                                l, a, tokl, tokc);
4190#endif
4191                        if (a == ch) {
4192                            inp();
4193                            tok = TOK_DUMMY; /* dummy token for double tokens */
4194                        }
4195                        /* check for op=, valid for * / % + - << >> & ^ | */
4196                        if (ch == '=' &&
4197                                ((tokl >= 1 && tokl <= 3)
4198                                        || (tokl >=6 && tokl <= 8)) ) {
4199                            inp();
4200                            tok = TOK_OP_ASSIGNMENT;
4201                        }
4202                        break;
4203                    }
4204                    opIndex++;
4205                }
4206                if (l == 0) {
4207                    tokl = 0;
4208                    tokc = 0;
4209                }
4210            }
4211        }
4212
4213    done: ;
4214#if 0
4215        {
4216            String buf;
4217            decodeToken(buf, tok, true);
4218            fprintf(stderr, "%s\n", buf.getUnwrapped());
4219        }
4220#endif
4221    }
4222
4223    void doDefine() {
4224        mbSuppressMacroExpansion = true;
4225        next();
4226        mbSuppressMacroExpansion = false;
4227        tokenid_t name = tok;
4228        String* pName = new String();
4229        if (ch == '(') {
4230            delete pName;
4231            error("Defines with arguments not supported");
4232            return;
4233        }
4234        while (isspace(ch)) {
4235            inp();
4236        }
4237        String value;
4238        bool appendToValue = true;
4239        while (ch != '\n' && ch != EOF) {
4240            // Check for '//' comments.
4241            if (appendToValue && ch == '/') {
4242                inp();
4243                if (ch == '/') {
4244                    appendToValue = false;
4245                } else {
4246                    value.append('/');
4247                }
4248            }
4249            if (appendToValue && ch != EOF) {
4250                value.append(ch);
4251            }
4252            inp();
4253        }
4254        char* pDefn = (char*)mGlobalArena.alloc(value.len() + 1);
4255        memcpy(pDefn, value.getUnwrapped(), value.len());
4256        pDefn[value.len()] = 0;
4257        mTokenTable[name].mpMacroDefinition = pDefn;
4258    }
4259
4260    void doPragma() {
4261        // # pragma name(val)
4262        int state = 0;
4263        while(ch != EOF && ch != '\n' && state < 10) {
4264            switch(state) {
4265                case 0:
4266                    if (isspace(ch)) {
4267                        inp();
4268                    } else {
4269                        state++;
4270                    }
4271                    break;
4272                case 1:
4273                    if (isalnum(ch)) {
4274                        mPragmas.append(ch);
4275                        inp();
4276                    } else if (ch == '(') {
4277                        mPragmas.append(0);
4278                        inp();
4279                        state++;
4280                    } else {
4281                        state = 11;
4282                    }
4283                    break;
4284                case 2:
4285                    if (isalnum(ch)) {
4286                        mPragmas.append(ch);
4287                        inp();
4288                    } else if (ch == ')') {
4289                        mPragmas.append(0);
4290                        inp();
4291                        state = 10;
4292                    } else {
4293                        state = 11;
4294                    }
4295                    break;
4296            }
4297        }
4298        if(state != 10) {
4299            error("Unexpected pragma syntax");
4300        }
4301        mPragmaStringCount += 2;
4302    }
4303
4304    void doLine() {
4305        // # line number { "filename "}
4306        next();
4307        if (tok != TOK_NUM) {
4308            error("Expected a line-number");
4309        } else {
4310            mLineNumber = tokc-1; // The end-of-line will increment it.
4311        }
4312        while(ch != EOF && ch != '\n') {
4313            inp();
4314        }
4315    }
4316
4317    virtual void verror(const char* fmt, va_list ap) {
4318        mErrorBuf.printf("%ld: ", mLineNumber);
4319        mErrorBuf.vprintf(fmt, ap);
4320        mErrorBuf.printf("\n");
4321    }
4322
4323    void skip(intptr_t c) {
4324        if (tok != c) {
4325            error("'%c' expected", c);
4326        }
4327        next();
4328    }
4329
4330    bool accept(intptr_t c) {
4331        if (tok == c) {
4332            next();
4333            return true;
4334        }
4335        return false;
4336    }
4337
4338    bool acceptStringLiteral() {
4339        if (tok == '"') {
4340            pGen->leaR0((int) glo, mkpCharPtr, ET_RVALUE);
4341            // This while loop merges multiple adjacent string constants.
4342            while (tok == '"') {
4343                while (ch != '"' && ch != EOF) {
4344                    *allocGlobalSpace(1,1) = getq();
4345                }
4346                if (ch != '"') {
4347                    error("Unterminated string constant.");
4348                }
4349                inp();
4350                next();
4351            }
4352            /* Null terminate */
4353            *glo = 0;
4354            /* align heap */
4355            allocGlobalSpace(1,(char*) (((intptr_t) glo + 4) & -4) - glo);
4356
4357            return true;
4358        }
4359        return false;
4360    }
4361
4362    void linkGlobal(tokenid_t t, bool isFunction) {
4363        VariableInfo* pVI = VI(t);
4364        void* n = NULL;
4365        if (mpSymbolLookupFn) {
4366            n = mpSymbolLookupFn(mpSymbolLookupContext, nameof(t));
4367        }
4368        if (pVI->pType == NULL) {
4369            if (isFunction) {
4370                pVI->pType = mkpIntFn;
4371            } else {
4372                pVI->pType = mkpInt;
4373            }
4374        }
4375        pVI->pAddress = n;
4376    }
4377
4378    void unaryOrAssignment() {
4379        unary();
4380        if (accept('=')) {
4381            checkLVal();
4382            pGen->pushR0();
4383            expr();
4384            pGen->forceR0RVal();
4385            pGen->storeR0ToTOS();
4386        } else if (tok == TOK_OP_ASSIGNMENT) {
4387            int t = tokc;
4388            next();
4389            checkLVal();
4390            pGen->pushR0();
4391            pGen->forceR0RVal();
4392            pGen->pushR0();
4393            expr();
4394            pGen->forceR0RVal();
4395            pGen->genOp(t);
4396            pGen->storeR0ToTOS();
4397        }
4398    }
4399
4400    /* Parse and evaluate a unary expression.
4401     */
4402    void unary() {
4403        tokenid_t t;
4404        intptr_t a;
4405        t = 0;
4406        if (acceptStringLiteral()) {
4407            // Nothing else to do.
4408        } else {
4409            int c = tokl;
4410            a = tokc;
4411            double ad = tokd;
4412            t = tok;
4413            next();
4414            if (t == TOK_NUM) {
4415                pGen->li(a);
4416            } else if (t == TOK_NUM_FLOAT) {
4417                // Align to 4-byte boundary
4418                glo = (char*) (((intptr_t) glo + 3) & -4);
4419                * (float*) glo = (float) ad;
4420                pGen->loadFloat((int) glo, mkpFloat);
4421                glo += 4;
4422            } else if (t == TOK_NUM_DOUBLE) {
4423                // Align to 8-byte boundary
4424                glo = (char*) (((intptr_t) glo + 7) & -8);
4425                * (double*) glo = ad;
4426                pGen->loadFloat((int) glo, mkpDouble);
4427                glo += 8;
4428            } else if (c == 2) {
4429                /* -, +, !, ~ */
4430                unary();
4431                pGen->forceR0RVal();
4432                if (t == '!')
4433                    pGen->gUnaryCmp(a);
4434                else if (t == '+') {
4435                    // ignore unary plus.
4436                } else {
4437                    pGen->genUnaryOp(a);
4438                }
4439            } else if (c == 11) {
4440                // pre increment / pre decrement
4441                unary();
4442                doIncDec(a == OP_INCREMENT, 0);
4443            }
4444            else if (t == '(') {
4445                // It's either a cast or an expression
4446                Type* pCast = acceptCastTypeDeclaration();
4447                if (pCast) {
4448                    skip(')');
4449                    unary();
4450                    pGen->forceR0RVal();
4451                    pGen->castR0(pCast);
4452                } else {
4453                    commaExpr();
4454                    skip(')');
4455                }
4456            } else if (t == '*') {
4457                /* This is a pointer dereference.
4458                 */
4459                unary();
4460                doPointer();
4461            } else if (t == '&') {
4462                unary();
4463                doAddressOf();
4464            } else if (t == EOF ) {
4465                error("Unexpected EOF.");
4466            } else if (t == ';') {
4467                error("Unexpected ';'");
4468            } else if (!checkSymbol(t)) {
4469                // Don't have to do anything special here, the error
4470                // message was printed by checkSymbol() above.
4471            } else {
4472                if (!isDefined(t)) {
4473                    mGlobals.add(t);
4474                    // printf("Adding new global function %s\n", nameof(t));
4475                }
4476                VariableInfo* pVI = VI(t);
4477                int n = (intptr_t) pVI->pAddress;
4478                /* forward reference: try our lookup function */
4479                if (!n) {
4480                    linkGlobal(t, tok == '(');
4481                    n = (intptr_t) pVI->pAddress;
4482                    if (!n && tok != '(') {
4483                        error("Undeclared variable %s\n", nameof(t));
4484                    }
4485                }
4486                if (tok != '(') {
4487                    /* variable or function name */
4488                    if (!n) {
4489                        linkGlobal(t, false);
4490                        n = (intptr_t) pVI->pAddress;
4491                        if (!n) {
4492                            error("Undeclared variable %s\n", nameof(t));
4493                        }
4494                    }
4495                }
4496                // load a variable
4497                Type* pVal;
4498                ExpressionType et;
4499                if (pVI->pType->tag == TY_ARRAY) {
4500                    pVal = pVI->pType;
4501                    et = ET_RVALUE;
4502                } else {
4503                    pVal = createPtrType(pVI->pType);
4504                    et = ET_LVALUE;
4505                }
4506                if (n) {
4507                    int tag = pVal->pHead->tag;
4508                    if (tag == TY_FUNC) {
4509                        et = ET_RVALUE;
4510                    }
4511                    pGen->leaR0(n, pVal, et);
4512                } else {
4513                    pVI->pForward = (void*) pGen->leaForward(
4514                            (int) pVI->pForward, pVal);
4515                }
4516            }
4517        }
4518
4519        /* Now handle postfix operators */
4520        for(;;) {
4521            if (tokl == 11) {
4522                // post inc / post dec
4523                doIncDec(tokc == OP_INCREMENT, true);
4524                next();
4525            } else if (accept('[')) {
4526                // Array reference
4527                pGen->forceR0RVal();
4528                pGen->pushR0();
4529                commaExpr();
4530                pGen->forceR0RVal();
4531                pGen->genOp(OP_PLUS);
4532                doPointer();
4533                skip(']');
4534            } else if (accept('.')) {
4535                // struct element
4536                pGen->forceR0RVal();
4537                Type* pStruct = pGen->getR0Type();
4538                if (pStruct->tag == TY_STRUCT) {
4539                    doStructMember(pStruct, true);
4540                } else {
4541                    error("expected a struct value to the left of '.'");
4542                }
4543            } else if (accept(TOK_OP_ARROW)) {
4544                pGen->forceR0RVal();
4545                Type* pPtr = pGen->getR0Type();
4546                if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
4547                    pGen->loadR0FromR0();
4548                    doStructMember(pPtr->pHead, false);
4549                } else {
4550                    error("Expected a pointer to a struct to the left of '->'");
4551                }
4552            } else  if (accept('(')) {
4553                /* function call */
4554                Type* pDecl = NULL;
4555                VariableInfo* pVI = NULL;
4556                Type* pFn = pGen->getR0Type();
4557                assert(pFn->tag == TY_POINTER);
4558                assert(pFn->pHead->tag == TY_FUNC);
4559                pDecl = pFn->pHead;
4560                pGen->pushR0();
4561                Type* pArgList = pDecl->pTail;
4562                bool varArgs = pArgList == NULL;
4563                /* push args and invert order */
4564                a = pGen->beginFunctionCallArguments();
4565                int l = 0;
4566                int argCount = 0;
4567                while (tok != ')' && tok != EOF) {
4568                    if (! varArgs && !pArgList) {
4569                        error("Unexpected argument.");
4570                    }
4571                    expr();
4572                    pGen->forceR0RVal();
4573                    Type* pTargetType;
4574                    if (pArgList) {
4575                        pTargetType = pArgList->pHead;
4576                        pArgList = pArgList->pTail;
4577                    } else {
4578                        // This is a ... function, just pass arguments in their
4579                        // natural type.
4580                        pTargetType = pGen->getR0Type();
4581                        if (pTargetType->tag == TY_FLOAT) {
4582                            pTargetType = mkpDouble;
4583                        } else if (pTargetType->tag == TY_ARRAY) {
4584                            // Pass arrays by pointer.
4585                            pTargetType = pTargetType->pTail;
4586                        }
4587                    }
4588                    if (pTargetType->tag == TY_VOID) {
4589                        error("Can't pass void value for argument %d",
4590                              argCount + 1);
4591                    } else {
4592                        l += pGen->storeR0ToArg(l, pTargetType);
4593                    }
4594                    if (accept(',')) {
4595                        // fine
4596                    } else if ( tok != ')') {
4597                        error("Expected ',' or ')'");
4598                    }
4599                    argCount += 1;
4600                }
4601                if (! varArgs && pArgList) {
4602                    error("Expected more argument(s). Saw %d", argCount);
4603                }
4604                pGen->endFunctionCallArguments(pDecl, a, l);
4605                skip(')');
4606                pGen->callIndirect(l, pDecl);
4607                pGen->adjustStackAfterCall(pDecl, l, true);
4608            } else {
4609                break;
4610            }
4611        }
4612    }
4613
4614    void doStructMember(Type* pStruct, bool isDot) {
4615        Type* pStructElement = lookupStructMember(pStruct, tok);
4616        if (pStructElement) {
4617            next();
4618            pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
4619        } else {
4620            String buf;
4621            decodeToken(buf, tok, true);
4622            error("Expected a struct member to the right of '%s', got %s",
4623                    isDot ? "." : "->", buf.getUnwrapped());
4624        }
4625    }
4626
4627    void doIncDec(int isInc, int isPost) {
4628        // R0 already has the lval
4629        checkLVal();
4630        int lit = isInc ? 1 : -1;
4631        pGen->pushR0();
4632        pGen->loadR0FromR0();
4633        int tag = pGen->getR0Type()->tag;
4634        if (!(tag == TY_INT || tag == TY_SHORT || tag == TY_CHAR ||
4635                tag == TY_POINTER)) {
4636            error("++/-- illegal for this type. %d", tag);
4637        }
4638        if (isPost) {
4639            pGen->over();
4640            pGen->pushR0();
4641            pGen->li(lit);
4642            pGen->genOp(OP_PLUS);
4643            pGen->storeR0ToTOS();
4644            pGen->popR0();
4645        } else {
4646            pGen->pushR0();
4647            pGen->li(lit);
4648            pGen->genOp(OP_PLUS);
4649            pGen->over();
4650            pGen->storeR0ToTOS();
4651            pGen->popR0();
4652        }
4653    }
4654
4655    void doPointer() {
4656        pGen->forceR0RVal();
4657        Type* pR0Type = pGen->getR0Type();
4658        if (pR0Type->tag != TY_POINTER) {
4659            error("Expected a pointer type.");
4660        } else {
4661            if (pR0Type->pHead->tag != TY_FUNC) {
4662                pGen->setR0ExpressionType(ET_LVALUE);
4663            }
4664        }
4665    }
4666
4667    void doAddressOf() {
4668        Type* pR0 = pGen->getR0Type();
4669        bool isFuncPtr = pR0->tag == TY_POINTER && pR0->pHead->tag == TY_FUNC;
4670        if ((! isFuncPtr) && pGen->getR0ExpressionType() != ET_LVALUE) {
4671            error("Expected an lvalue");
4672        }
4673        Type* pR0Type = pGen->getR0Type();
4674        pGen->setR0ExpressionType(ET_RVALUE);
4675    }
4676
4677    /* Recursive descent parser for binary operations.
4678     */
4679    void binaryOp(int level) {
4680        intptr_t t, a;
4681        t = 0;
4682        if (level-- == 1)
4683            unaryOrAssignment();
4684        else {
4685            binaryOp(level);
4686            a = 0;
4687            while (level == tokl) {
4688                t = tokc;
4689                next();
4690                pGen->forceR0RVal();
4691                if (level > 8) {
4692                    a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */
4693                    binaryOp(level);
4694                } else {
4695                    pGen->pushR0();
4696                    binaryOp(level);
4697                    // Check for syntax error.
4698                    if (pGen->getR0Type() == NULL) {
4699                        // We failed to parse a right-hand argument.
4700                        // Push a dummy value so we don't fail
4701                        pGen->li(0);
4702                    }
4703                    pGen->forceR0RVal();
4704                    if ((level == 4) | (level == 5)) {
4705                        pGen->gcmp(t);
4706                    } else {
4707                        pGen->genOp(t);
4708                    }
4709                }
4710            }
4711            /* && and || output code generation */
4712            if (a && level > 8) {
4713                pGen->forceR0RVal();
4714                a = pGen->gtst(t == OP_LOGICAL_OR, a);
4715                pGen->li(t != OP_LOGICAL_OR);
4716                int b = pGen->gjmp(0);
4717                pGen->gsym(a);
4718                pGen->li(t == OP_LOGICAL_OR);
4719                pGen->gsym(b);
4720            }
4721        }
4722    }
4723
4724    void commaExpr() {
4725        for(;;) {
4726            expr();
4727            if (!accept(',')) {
4728                break;
4729            }
4730        }
4731    }
4732
4733    void expr() {
4734        binaryOp(11);
4735    }
4736
4737    int test_expr() {
4738        commaExpr();
4739        pGen->forceR0RVal();
4740        return pGen->gtst(0, 0);
4741    }
4742
4743    void block(intptr_t l, bool outermostFunctionBlock) {
4744        intptr_t a, n, t;
4745
4746        Type* pBaseType;
4747        if ((pBaseType = acceptPrimitiveType())) {
4748            /* declarations */
4749            localDeclarations(pBaseType);
4750        } else if (tok == TOK_IF) {
4751            next();
4752            skip('(');
4753            a = test_expr();
4754            skip(')');
4755            block(l, false);
4756            if (tok == TOK_ELSE) {
4757                next();
4758                n = pGen->gjmp(0); /* jmp */
4759                pGen->gsym(a);
4760                block(l, false);
4761                pGen->gsym(n); /* patch else jmp */
4762            } else {
4763                pGen->gsym(a); /* patch if test */
4764            }
4765        } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) {
4766            t = tok;
4767            next();
4768            skip('(');
4769            if (t == TOK_WHILE) {
4770                n = codeBuf.getPC(); // top of loop, target of "next" iteration
4771                a = test_expr();
4772            } else {
4773                if (tok != ';')
4774                    commaExpr();
4775                skip(';');
4776                n = codeBuf.getPC();
4777                a = 0;
4778                if (tok != ';')
4779                    a = test_expr();
4780                skip(';');
4781                if (tok != ')') {
4782                    t = pGen->gjmp(0);
4783                    commaExpr();
4784                    pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset());
4785                    pGen->gsym(t);
4786                    n = t + 4;
4787                }
4788            }
4789            skip(')');
4790            block((intptr_t) &a, false);
4791            pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
4792            pGen->gsym(a);
4793        } else if (tok == '{') {
4794            if (! outermostFunctionBlock) {
4795                mLocals.pushLevel();
4796            }
4797            next();
4798            while (tok != '}' && tok != EOF)
4799                block(l, false);
4800            skip('}');
4801            if (! outermostFunctionBlock) {
4802                mLocals.popLevel();
4803            }
4804        } else {
4805            if (accept(TOK_RETURN)) {
4806                if (tok != ';') {
4807                    commaExpr();
4808                    pGen->forceR0RVal();
4809                    if (pReturnType->tag == TY_VOID) {
4810                        error("Must not return a value from a void function");
4811                    } else {
4812                        pGen->convertR0(pReturnType);
4813                    }
4814                } else {
4815                    if (pReturnType->tag != TY_VOID) {
4816                        error("Must specify a value here");
4817                    }
4818                }
4819                rsym = pGen->gjmp(rsym); /* jmp */
4820            } else if (accept(TOK_BREAK)) {
4821                *(int *) l = pGen->gjmp(*(int *) l);
4822            } else if (tok != ';')
4823                commaExpr();
4824            skip(';');
4825        }
4826    }
4827
4828    static bool typeEqual(Type* a, Type* b) {
4829        if (a == b) {
4830            return true;
4831        }
4832        if (a == NULL || b == NULL) {
4833            return false;
4834        }
4835        TypeTag at = a->tag;
4836        if (at != b->tag) {
4837            return false;
4838        }
4839        if (at == TY_POINTER) {
4840            return typeEqual(a->pHead, b->pHead);
4841        } else if (at == TY_ARRAY) {
4842            return a->length == b->length && typeEqual(a->pHead, b->pHead);
4843        } else if (at == TY_FUNC || at == TY_PARAM) {
4844            return typeEqual(a->pHead, b->pHead)
4845                && typeEqual(a->pTail, b->pTail);
4846        } else if (at == TY_STRUCT) {
4847            return a->pHead == b->pHead;
4848        }
4849        return true;
4850    }
4851
4852    Type* createType(TypeTag tag, Type* pHead, Type* pTail) {
4853        assert(tag >= TY_INT && tag <= TY_PARAM);
4854        Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type));
4855        memset(pType, 0, sizeof(*pType));
4856        pType->tag = tag;
4857        pType->pHead = pHead;
4858        pType->pTail = pTail;
4859        return pType;
4860    }
4861
4862    Type* createPtrType(Type* pType) {
4863        return createType(TY_POINTER, pType, NULL);
4864    }
4865
4866    /**
4867     * Try to print a type in declaration order
4868     */
4869    void decodeType(String& buffer, Type* pType) {
4870        buffer.clear();
4871        if (pType == NULL) {
4872            buffer.appendCStr("null");
4873            return;
4874        }
4875        decodeTypeImp(buffer, pType);
4876    }
4877
4878    void decodeTypeImp(String& buffer, Type* pType) {
4879        decodeTypeImpPrefix(buffer, pType);
4880        decodeId(buffer, pType->id);
4881        decodeTypeImpPostfix(buffer, pType);
4882    }
4883
4884    void decodeId(String& buffer, tokenid_t id) {
4885        if (id) {
4886            String temp;
4887            decodeToken(temp, id, false);
4888            buffer.append(temp);
4889        }
4890    }
4891
4892    void decodeTypeImpPrefix(String& buffer, Type* pType) {
4893        TypeTag tag = pType->tag;
4894
4895        if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
4896            switch (tag) {
4897                case TY_INT:
4898                    buffer.appendCStr("int");
4899                    break;
4900                case TY_SHORT:
4901                    buffer.appendCStr("short");
4902                    break;
4903                case TY_CHAR:
4904                    buffer.appendCStr("char");
4905                    break;
4906                case TY_VOID:
4907                    buffer.appendCStr("void");
4908                    break;
4909                case TY_FLOAT:
4910                    buffer.appendCStr("float");
4911                    break;
4912                case TY_DOUBLE:
4913                    buffer.appendCStr("double");
4914                    break;
4915                case TY_STRUCT:
4916                {
4917                    bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
4918                    buffer.appendCStr(isStruct ? "struct" : "union");
4919                    if (pType->pHead && pType->pHead->structTag) {
4920                        buffer.append(' ');
4921                        decodeId(buffer, pType->pHead->structTag);
4922                    }
4923                }
4924                    break;
4925                default:
4926                    break;
4927            }
4928            buffer.append(' ');
4929        }
4930
4931        switch (tag) {
4932            case TY_INT:
4933                break;
4934            case TY_SHORT:
4935                break;
4936            case TY_CHAR:
4937                break;
4938            case TY_VOID:
4939                 break;
4940            case TY_FLOAT:
4941                 break;
4942            case TY_DOUBLE:
4943                break;
4944            case TY_POINTER:
4945                decodeTypeImpPrefix(buffer, pType->pHead);
4946                if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4947                    buffer.append('(');
4948                }
4949                buffer.append('*');
4950                break;
4951            case TY_ARRAY:
4952                decodeTypeImpPrefix(buffer, pType->pHead);
4953                break;
4954            case TY_STRUCT:
4955                break;
4956            case TY_FUNC:
4957                decodeTypeImp(buffer, pType->pHead);
4958                break;
4959            case TY_PARAM:
4960                decodeTypeImp(buffer, pType->pHead);
4961                break;
4962            default:
4963                String temp;
4964                temp.printf("Unknown tag %d", pType->tag);
4965                buffer.append(temp);
4966                break;
4967        }
4968    }
4969
4970    void decodeTypeImpPostfix(String& buffer, Type* pType) {
4971        TypeTag tag = pType->tag;
4972
4973        switch(tag) {
4974            case TY_POINTER:
4975                if(pType->pHead && pType->pHead->tag == TY_FUNC) {
4976                    buffer.append(')');
4977                }
4978                decodeTypeImpPostfix(buffer, pType->pHead);
4979                break;
4980            case TY_ARRAY:
4981                {
4982                    String temp;
4983                    temp.printf("[%d]", pType->length);
4984                    buffer.append(temp);
4985                }
4986                break;
4987            case TY_STRUCT:
4988                if (pType->pHead->length >= 0) {
4989                    buffer.appendCStr(" {");
4990                    for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
4991                        decodeTypeImp(buffer, pArg->pHead);
4992                        buffer.appendCStr(";");
4993                    }
4994                    buffer.append('}');
4995                }
4996                break;
4997            case TY_FUNC:
4998                buffer.append('(');
4999                for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
5000                    decodeTypeImp(buffer, pArg);
5001                    if (pArg->pTail) {
5002                        buffer.appendCStr(", ");
5003                    }
5004                }
5005                buffer.append(')');
5006                break;
5007            default:
5008                break;
5009        }
5010    }
5011
5012    void printType(Type* pType) {
5013        String buffer;
5014        decodeType(buffer, pType);
5015        fprintf(stderr, "%s\n", buffer.getUnwrapped());
5016    }
5017
5018    Type* acceptPrimitiveType() {
5019        Type* pType;
5020        if (tok == TOK_INT) {
5021            pType = mkpInt;
5022        } else if (tok == TOK_SHORT) {
5023            pType = mkpShort;
5024        } else if (tok == TOK_CHAR) {
5025            pType = mkpChar;
5026        } else if (tok == TOK_VOID) {
5027            pType = mkpVoid;
5028        } else if (tok == TOK_FLOAT) {
5029            pType = mkpFloat;
5030        } else if (tok == TOK_DOUBLE) {
5031            pType = mkpDouble;
5032        } else if (tok == TOK_STRUCT || tok == TOK_UNION) {
5033            return acceptStruct();
5034        } else {
5035            return NULL;
5036        }
5037        next();
5038        return pType;
5039    }
5040
5041    Type* acceptStruct() {
5042        assert(tok == TOK_STRUCT || tok == TOK_UNION);
5043        bool isStruct = tok == TOK_STRUCT;
5044        next();
5045        tokenid_t structTag = acceptSymbol();
5046        bool isDeclaration = accept('{');
5047        bool fail = false;
5048
5049        Type* pStructType = createType(TY_STRUCT, NULL, NULL);
5050        if (structTag) {
5051            Token* pToken = &mTokenTable[structTag];
5052            VariableInfo* pStructInfo = pToken->mpStructInfo;
5053            bool needToDeclare = !pStructInfo;
5054            if (pStructInfo) {
5055                if (isDeclaration) {
5056                    if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
5057                        if (pStructInfo->pType->pHead->length == -1) {
5058                            // we're filling in a forward declaration.
5059                            needToDeclare = false;
5060                        } else {
5061                            error("A struct with the same name is already defined at this level.");
5062                            fail = true;
5063                        }
5064                    } else {
5065                        needToDeclare = true;
5066                    }
5067                }
5068                if (!fail) {
5069                     assert(pStructInfo->isStructTag);
5070                     pStructType->pHead = pStructInfo->pType;
5071                     pStructType->pTail = pStructType->pHead->pTail;
5072                }
5073            }
5074
5075            if (needToDeclare) {
5076                // This is a new struct name
5077                pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
5078                pStructType = createType(TY_STRUCT, NULL, NULL);
5079                pStructType->structTag = structTag;
5080                pStructType->pHead = pStructType;
5081                if (! isDeclaration) {
5082                    // A forward declaration
5083                    pStructType->length = -1;
5084                }
5085                pToken->mpStructInfo->pType = pStructType;
5086            }
5087        } else {
5088            // An anonymous struct
5089            pStructType->pHead = pStructType;
5090        }
5091
5092        if (isDeclaration) {
5093            size_t offset = 0;
5094            size_t structSize = 0;
5095            size_t structAlignment = 0;
5096            Type** pParamHolder = & pStructType->pHead->pTail;
5097            while (tok != '}' && tok != EOF) {
5098                Type* pPrimitiveType = expectPrimitiveType();
5099                if (pPrimitiveType) {
5100                    while (tok != ';' && tok != EOF) {
5101                        Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
5102                        if (!pItem) {
5103                            break;
5104                        }
5105                        if (lookupStructMember(pStructType, pItem->id)) {
5106                            String buf;
5107                            decodeToken(buf, pItem->id, false);
5108                            error("Duplicate struct member %s", buf.getUnwrapped());
5109                        }
5110                        Type* pStructElement = createType(TY_PARAM, pItem, NULL);
5111                        size_t alignment = pGen->alignmentOf(pItem);
5112                        if (alignment > structAlignment) {
5113                            structAlignment = alignment;
5114                        }
5115                        size_t alignmentMask = alignment - 1;
5116                        offset = (offset + alignmentMask) & ~alignmentMask;
5117                        pStructElement->length = offset;
5118                        size_t size = pGen->sizeOf(pItem);
5119                        if (isStruct) {
5120                            offset += size;
5121                            structSize = offset;
5122                        } else {
5123                            if (size >= structSize) {
5124                                structSize = size;
5125                            }
5126                        }
5127                        *pParamHolder = pStructElement;
5128                        pParamHolder = &pStructElement->pTail;
5129                        accept(',');
5130                    }
5131                    skip(';');
5132                } else {
5133                    // Some sort of syntax error, skip token and keep trying
5134                    next();
5135                }
5136            }
5137            if (!fail) {
5138                pStructType->pHead->length = structSize;
5139                pStructType->pHead->alignment = structAlignment | (isStruct << 31);
5140            }
5141            skip('}');
5142        }
5143        if (fail) {
5144            pStructType = NULL;
5145        }
5146        return pStructType;
5147    }
5148
5149    Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
5150        for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
5151            if (pStructElement->pHead->id == memberId) {
5152                return pStructElement;
5153            }
5154        }
5155        return NULL;
5156    }
5157
5158    Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
5159        tokenid_t declName = 0;
5160        bool reportFailure = false;
5161        pType = acceptDecl2(pType, declName, nameAllowed,
5162                                  nameRequired, reportFailure);
5163        if (declName) {
5164            // Clone the parent type so we can set a unique ID
5165            Type* pOldType = pType;
5166            pType = createType(pType->tag, pType->pHead, pType->pTail);
5167            *pType = *pOldType;
5168            pType->id = declName;
5169        } else if (nameRequired) {
5170            error("Expected a variable name");
5171        }
5172#if 0
5173        fprintf(stderr, "Parsed a declaration:       ");
5174        printType(pType);
5175#endif
5176        if (reportFailure) {
5177            return NULL;
5178        }
5179        return pType;
5180    }
5181
5182    Type* expectDeclaration(Type* pBaseType) {
5183        bool nameRequired = pBaseType->tag != TY_STRUCT;
5184        Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
5185        if (! pType) {
5186            error("Expected a declaration");
5187        }
5188        return pType;
5189    }
5190
5191    /* Used for accepting types that appear in casts */
5192    Type* acceptCastTypeDeclaration() {
5193        Type* pType = acceptPrimitiveType();
5194        if (pType) {
5195            pType = acceptDeclaration(pType, false, false);
5196        }
5197        return pType;
5198    }
5199
5200    Type* expectCastTypeDeclaration() {
5201        Type* pType = acceptCastTypeDeclaration();
5202        if (! pType) {
5203            error("Expected a declaration");
5204        }
5205        return pType;
5206    }
5207
5208    Type* acceptDecl2(Type* pType, tokenid_t& declName,
5209                      bool nameAllowed, bool nameRequired,
5210                      bool& reportFailure) {
5211        while (accept('*')) {
5212            pType = createType(TY_POINTER, pType, NULL);
5213        }
5214        pType = acceptDecl3(pType, declName, nameAllowed, nameRequired,
5215                            reportFailure);
5216        return pType;
5217    }
5218
5219    Type* acceptDecl3(Type* pType, tokenid_t& declName,
5220                      bool nameAllowed, bool nameRequired,
5221                      bool& reportFailure) {
5222        // direct-dcl :
5223        //   name
5224        //  (dcl)
5225        //   direct-dcl()
5226        //   direct-dcl[]
5227        Type* pNewHead = NULL;
5228        if (accept('(')) {
5229            pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
5230                                nameRequired, reportFailure);
5231            skip(')');
5232        } else if ((declName = acceptSymbol()) != 0) {
5233            if (nameAllowed == false && declName) {
5234                error("Symbol %s not allowed here", nameof(declName));
5235                reportFailure = true;
5236            }
5237        } else if (nameRequired && ! declName) {
5238            String temp;
5239            decodeToken(temp, tok, true);
5240            error("Expected name. Got %s", temp.getUnwrapped());
5241            reportFailure = true;
5242        }
5243        for(;;) {
5244            if (accept('(')) {
5245                // Function declaration
5246                Type* pTail = acceptArgs(nameAllowed);
5247                pType = createType(TY_FUNC, pType, pTail);
5248                skip(')');
5249            } if (accept('[')) {
5250                if (tok != ']') {
5251                    if (tok != TOK_NUM || tokc <= 0) {
5252                        error("Expected positive integer constant");
5253                    } else {
5254                        Type* pDecayType = createPtrType(pType);
5255                        pType = createType(TY_ARRAY, pType, pDecayType);
5256                        pType->length = tokc;
5257                    }
5258                    next();
5259                }
5260                skip(']');
5261            } else {
5262                break;
5263            }
5264        }
5265
5266        if (pNewHead) {
5267            Type* pA = pNewHead;
5268            while (pA->pHead) {
5269                pA = pA->pHead;
5270            }
5271            pA->pHead = pType;
5272            pType = pNewHead;
5273        }
5274        return pType;
5275    }
5276
5277    Type* acceptArgs(bool nameAllowed) {
5278        Type* pHead = NULL;
5279        Type* pTail = NULL;
5280        for(;;) {
5281            Type* pBaseArg = acceptPrimitiveType();
5282            if (pBaseArg) {
5283                Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false);
5284                if (pArg) {
5285                    Type* pParam = createType(TY_PARAM, pArg, NULL);
5286                    if (!pHead) {
5287                        pHead = pParam;
5288                        pTail = pParam;
5289                    } else {
5290                        pTail->pTail = pParam;
5291                        pTail = pParam;
5292                    }
5293                }
5294            }
5295            if (! accept(',')) {
5296                break;
5297            }
5298        }
5299        return pHead;
5300    }
5301
5302    Type* expectPrimitiveType() {
5303        Type* pType = acceptPrimitiveType();
5304        if (!pType) {
5305            String buf;
5306            decodeToken(buf, tok, true);
5307            error("Expected a type, got %s", buf.getUnwrapped());
5308        }
5309        return pType;
5310    }
5311
5312    void checkLVal() {
5313        if (pGen->getR0ExpressionType() != ET_LVALUE) {
5314            error("Expected an lvalue");
5315        }
5316    }
5317
5318    void addGlobalSymbol(Type* pDecl) {
5319        tokenid_t t = pDecl->id;
5320        VariableInfo* pVI = VI(t);
5321        if(pVI && pVI->pAddress) {
5322            reportDuplicate(t);
5323        }
5324        mGlobals.add(pDecl);
5325    }
5326
5327    void reportDuplicate(tokenid_t t) {
5328        error("Duplicate definition of %s", nameof(t));
5329    }
5330
5331    void addLocalSymbol(Type* pDecl) {
5332        tokenid_t t = pDecl->id;
5333        if (mLocals.isDefinedAtCurrentLevel(t)) {
5334            reportDuplicate(t);
5335        }
5336        mLocals.add(pDecl);
5337    }
5338
5339    bool checkUndeclaredStruct(Type* pBaseType) {
5340        if (pBaseType->tag == TY_STRUCT && pBaseType->length < 0) {
5341            String temp;
5342            decodeToken(temp, pBaseType->structTag, false);
5343            error("Undeclared struct %s", temp.getUnwrapped());
5344            return true;
5345        }
5346        return false;
5347    }
5348
5349    void localDeclarations(Type* pBaseType) {
5350        intptr_t a;
5351
5352        while (pBaseType) {
5353            while (tok != ';' && tok != EOF) {
5354                Type* pDecl = expectDeclaration(pBaseType);
5355                if (!pDecl) {
5356                    break;
5357                }
5358                if (!pDecl->id) {
5359                    break;
5360                }
5361                if (checkUndeclaredStruct(pDecl)) {
5362                    break;
5363                }
5364                int variableAddress = 0;
5365                addLocalSymbol(pDecl);
5366                size_t alignment = pGen->alignmentOf(pDecl);
5367                assert(alignment > 0);
5368                size_t alignmentMask = ~ (alignment - 1);
5369                size_t sizeOf = pGen->sizeOf(pDecl);
5370                assert(sizeOf > 0);
5371                loc = (loc + alignment - 1) & alignmentMask;
5372                size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
5373                loc = loc + alignedSize;
5374                variableAddress = -loc;
5375                VI(pDecl->id)->pAddress = (void*) variableAddress;
5376                if (accept('=')) {
5377                    /* assignment */
5378                    pGen->leaR0(variableAddress, createPtrType(pDecl), ET_LVALUE);
5379                    pGen->pushR0();
5380                    expr();
5381                    pGen->forceR0RVal();
5382                    pGen->storeR0ToTOS();
5383                }
5384                if (tok == ',')
5385                    next();
5386            }
5387            skip(';');
5388            pBaseType = acceptPrimitiveType();
5389        }
5390    }
5391
5392    bool checkSymbol() {
5393        return checkSymbol(tok);
5394    }
5395
5396    void decodeToken(String& buffer, tokenid_t token, bool quote) {
5397        if (token == EOF ) {
5398            buffer.printf("EOF");
5399        } else if (token == TOK_NUM) {
5400            buffer.printf("numeric constant");
5401        } else if (token >= 0 && token < 256) {
5402            if (token < 32) {
5403                buffer.printf("'\\x%02x'", token);
5404            } else {
5405                buffer.printf("'%c'", token);
5406            }
5407        } else {
5408            if (quote) {
5409                if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
5410                    buffer.printf("keyword \"%s\"", nameof(token));
5411                } else {
5412                    buffer.printf("symbol \"%s\"", nameof(token));
5413                }
5414            } else {
5415                buffer.printf("%s", nameof(token));
5416            }
5417        }
5418    }
5419
5420    void printToken(tokenid_t token) {
5421        String buffer;
5422        decodeToken(buffer, token, true);
5423        fprintf(stderr, "%s\n", buffer.getUnwrapped());
5424    }
5425
5426    bool checkSymbol(tokenid_t token) {
5427        bool result = token >= TOK_SYMBOL;
5428        if (!result) {
5429            String temp;
5430            decodeToken(temp, token, true);
5431            error("Expected symbol. Got %s", temp.getUnwrapped());
5432        }
5433        return result;
5434    }
5435
5436    tokenid_t acceptSymbol() {
5437        tokenid_t result = 0;
5438        if (tok >= TOK_SYMBOL) {
5439            result = tok;
5440            next();
5441        }
5442        return result;
5443    }
5444
5445    void globalDeclarations() {
5446        mpCurrentSymbolStack = &mGlobals;
5447        while (tok != EOF) {
5448            Type* pBaseType = expectPrimitiveType();
5449            if (!pBaseType) {
5450                break;
5451            }
5452            Type* pDecl = expectDeclaration(pBaseType);
5453            if (!pDecl) {
5454                break;
5455            }
5456            if (!pDecl->id) {
5457                skip(';');
5458                continue;
5459            }
5460
5461            if (checkUndeclaredStruct(pDecl)) {
5462                skip(';');
5463                continue;
5464            }
5465
5466            if (! isDefined(pDecl->id)) {
5467                addGlobalSymbol(pDecl);
5468            }
5469            VariableInfo* name = VI(pDecl->id);
5470            if (name && name->pAddress) {
5471                error("Already defined global %s", nameof(pDecl->id));
5472            }
5473            if (pDecl->tag < TY_FUNC) {
5474                // it's a variable declaration
5475                for(;;) {
5476                    if (name && !name->pAddress) {
5477                        name->pAddress = (int*) allocGlobalSpace(
5478                                                   pGen->alignmentOf(name->pType),
5479                                                   pGen->sizeOf(name->pType));
5480                    }
5481                    if (accept('=')) {
5482                        if (tok == TOK_NUM) {
5483                            if (name) {
5484                                * (int*) name->pAddress = tokc;
5485                            }
5486                            next();
5487                        } else {
5488                            error("Expected an integer constant");
5489                        }
5490                    }
5491                    if (!accept(',')) {
5492                        break;
5493                    }
5494                    pDecl = expectDeclaration(pBaseType);
5495                    if (!pDecl) {
5496                        break;
5497                    }
5498                    if (! isDefined(pDecl->id)) {
5499                        addGlobalSymbol(pDecl);
5500                    }
5501                    name = VI(pDecl->id);
5502                }
5503                skip(';');
5504            } else {
5505                // Function declaration
5506                if (accept(';')) {
5507                    // forward declaration.
5508                } else if (tok != '{') {
5509                    error("expected '{'");
5510                } else {
5511                    mpCurrentArena = &mLocalArena;
5512                    mpCurrentSymbolStack = &mLocals;
5513                    if (name) {
5514                        /* patch forward references */
5515                        pGen->resolveForward((int) name->pForward);
5516                        /* put function address */
5517                        name->pAddress = (void*) codeBuf.getPC();
5518                    }
5519                    // Calculate stack offsets for parameters
5520                    mLocals.pushLevel();
5521                    intptr_t a = 8;
5522                    int argCount = 0;
5523                    for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
5524                        Type* pArg = pP->pHead;
5525                        if (pArg->id) {
5526                            addLocalSymbol(pArg);
5527                        }
5528                        /* read param name and compute offset */
5529                        Type* pPassingType = passingType(pArg);
5530                        size_t alignment = pGen->alignmentOf(pPassingType);
5531                        a = (a + alignment - 1) & ~ (alignment-1);
5532                        if (pArg->id) {
5533                            VI(pArg->id)->pAddress = (void*) a;
5534                        }
5535                        a = a + pGen->sizeOf(pPassingType);
5536                        argCount++;
5537                    }
5538                    rsym = loc = 0;
5539                    pReturnType = pDecl->pHead;
5540                    a = pGen->functionEntry(pDecl);
5541                    block(0, true);
5542                    pGen->gsym(rsym);
5543                    pGen->functionExit(pDecl, a, loc);
5544                    mLocals.popLevel();
5545                    mpCurrentArena = &mGlobalArena;
5546                    mpCurrentSymbolStack = &mGlobals;
5547                }
5548            }
5549        }
5550    }
5551
5552    Type* passingType(Type* pType) {
5553        switch (pType->tag) {
5554        case TY_CHAR:
5555        case TY_SHORT:
5556            return mkpInt;
5557        default:
5558            return pType;
5559        }
5560    }
5561
5562    char* allocGlobalSpace(size_t alignment, size_t bytes) {
5563        size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
5564        size_t end = base + bytes;
5565        if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
5566            error("Global space exhausted");
5567            assert(false);
5568            return NULL;
5569        }
5570        char* result = (char*) base;
5571        glo = (char*) end;
5572        return result;
5573    }
5574
5575    void cleanup() {
5576        if (pGlobalBase != 0) {
5577            free(pGlobalBase);
5578            pGlobalBase = 0;
5579        }
5580        if (pGen) {
5581            delete pGen;
5582            pGen = 0;
5583        }
5584        if (file) {
5585            delete file;
5586            file = 0;
5587        }
5588    }
5589
5590    // One-time initialization, when class is constructed.
5591    void init() {
5592        mpSymbolLookupFn = 0;
5593        mpSymbolLookupContext = 0;
5594    }
5595
5596    void clear() {
5597        tok = 0;
5598        tokc = 0;
5599        tokl = 0;
5600        ch = 0;
5601        rsym = 0;
5602        loc = 0;
5603        glo = 0;
5604        dptr = 0;
5605        dch = 0;
5606        file = 0;
5607        pGlobalBase = 0;
5608        pGen = 0;
5609        mPragmaStringCount = 0;
5610        mCompileResult = 0;
5611        mLineNumber = 1;
5612        mbBumpLine = false;
5613        mbSuppressMacroExpansion = false;
5614    }
5615
5616    void setArchitecture(const char* architecture) {
5617        delete pGen;
5618        pGen = 0;
5619
5620        if (architecture != NULL) {
5621#ifdef PROVIDE_ARM_CODEGEN
5622            if (! pGen && strcmp(architecture, "arm") == 0) {
5623                pGen = new ARMCodeGenerator();
5624            }
5625#endif
5626#ifdef PROVIDE_X86_CODEGEN
5627            if (! pGen && strcmp(architecture, "x86") == 0) {
5628                pGen = new X86CodeGenerator();
5629            }
5630#endif
5631            if (!pGen ) {
5632                error("Unknown architecture %s\n", architecture);
5633            }
5634        }
5635
5636        if (pGen == NULL) {
5637#if defined(DEFAULT_ARM_CODEGEN)
5638            pGen = new ARMCodeGenerator();
5639#elif defined(DEFAULT_X86_CODEGEN)
5640            pGen = new X86CodeGenerator();
5641#endif
5642        }
5643        if (pGen == NULL) {
5644            error("No code generator defined.");
5645        } else {
5646            pGen->setErrorSink(this);
5647            pGen->setTypes(mkpInt);
5648        }
5649    }
5650
5651public:
5652    struct args {
5653        args() {
5654            architecture = 0;
5655        }
5656        const char* architecture;
5657    };
5658
5659    Compiler() {
5660        init();
5661        clear();
5662    }
5663
5664    ~Compiler() {
5665        cleanup();
5666    }
5667
5668    void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5669        mpSymbolLookupFn = pFn;
5670        mpSymbolLookupContext = pContext;
5671    }
5672
5673    int compile(const char* text, size_t textLength) {
5674        int result;
5675
5676        mpCurrentArena = &mGlobalArena;
5677        createPrimitiveTypes();
5678        cleanup();
5679        clear();
5680        mTokenTable.setArena(&mGlobalArena);
5681        mGlobals.setArena(&mGlobalArena);
5682        mGlobals.setTokenTable(&mTokenTable);
5683        mLocals.setArena(&mLocalArena);
5684        mLocals.setTokenTable(&mTokenTable);
5685
5686        internKeywords();
5687        codeBuf.init(ALLOC_SIZE);
5688        setArchitecture(NULL);
5689        if (!pGen) {
5690            return -1;
5691        }
5692#ifdef PROVIDE_TRACE_CODEGEN
5693            pGen = new TraceCodeGenerator(pGen);
5694#endif
5695            pGen->setErrorSink(this);
5696        pGen->init(&codeBuf);
5697        file = new TextInputStream(text, textLength);
5698        pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
5699        glo = pGlobalBase;
5700        inp();
5701        next();
5702        globalDeclarations();
5703        checkForUndefinedForwardReferences();
5704        result = pGen->finishCompile();
5705        if (result == 0) {
5706            if (mErrorBuf.len()) {
5707                result = -2;
5708            }
5709        }
5710        mCompileResult = result;
5711        return result;
5712    }
5713
5714    void createPrimitiveTypes() {
5715        mkpInt = createType(TY_INT, NULL, NULL);
5716        mkpShort = createType(TY_SHORT, NULL, NULL);
5717        mkpChar = createType(TY_CHAR, NULL, NULL);
5718        mkpVoid = createType(TY_VOID, NULL, NULL);
5719        mkpFloat = createType(TY_FLOAT, NULL, NULL);
5720        mkpDouble = createType(TY_DOUBLE, NULL, NULL);
5721        mkpIntFn =  createType(TY_FUNC, mkpInt, NULL);
5722        mkpIntPtr = createPtrType(mkpInt);
5723        mkpCharPtr = createPtrType(mkpChar);
5724        mkpFloatPtr = createPtrType(mkpFloat);
5725        mkpDoublePtr = createPtrType(mkpDouble);
5726        mkpPtrIntFn = createPtrType(mkpIntFn);
5727    }
5728
5729    void checkForUndefinedForwardReferences() {
5730        mGlobals.forEach(static_ufrcFn, this);
5731    }
5732
5733    static bool static_ufrcFn(VariableInfo* value, void* context) {
5734        Compiler* pCompiler = (Compiler*) context;
5735        return pCompiler->undefinedForwardReferenceCheck(value);
5736    }
5737
5738    bool undefinedForwardReferenceCheck(VariableInfo* value) {
5739        if (!value->pAddress && value->pForward) {
5740            error("Undefined forward reference: %s",
5741                  mTokenTable[value->tok].pText);
5742        }
5743        return true;
5744    }
5745
5746    int dump(FILE* out) {
5747        fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
5748        return 0;
5749    }
5750
5751    int disassemble(FILE* out) {
5752        return pGen->disassemble(out);
5753    }
5754
5755    /* Look through the symbol table to find a symbol.
5756     * If found, return its value.
5757     */
5758    void* lookup(const char* name) {
5759        if (mCompileResult == 0) {
5760            tokenid_t tok = mTokenTable.intern(name, strlen(name));
5761            VariableInfo* pVariableInfo = VI(tok);
5762            if (pVariableInfo) {
5763                return pVariableInfo->pAddress;
5764            }
5765        }
5766        return NULL;
5767    }
5768
5769    void getPragmas(ACCsizei* actualStringCount,
5770                    ACCsizei maxStringCount, ACCchar** strings) {
5771        int stringCount = mPragmaStringCount;
5772        if (actualStringCount) {
5773            *actualStringCount = stringCount;
5774        }
5775        if (stringCount > maxStringCount) {
5776            stringCount = maxStringCount;
5777        }
5778        if (strings) {
5779            char* pPragmas = mPragmas.getUnwrapped();
5780            while (stringCount-- > 0) {
5781                *strings++ = pPragmas;
5782                pPragmas += strlen(pPragmas) + 1;
5783            }
5784        }
5785    }
5786
5787    char* getErrorMessage() {
5788        return mErrorBuf.getUnwrapped();
5789    }
5790
5791};
5792
5793const char* Compiler::operatorChars =
5794    "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@";
5795
5796const char Compiler::operatorLevel[] =
5797    {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4,
5798            5, 5, /* ==, != */
5799            9, 10, /* &&, || */
5800            6, 7, 8, /* & ^ | */
5801            2, 2 /* ~ ! */
5802            };
5803
5804#ifdef PROVIDE_ARM_CODEGEN
5805FILE* Compiler::ARMCodeGenerator::disasmOut;
5806#endif
5807
5808#ifdef PROVIDE_X86_CODEGEN
5809const int Compiler::X86CodeGenerator::operatorHelper[] = {
5810        0x1,     // ++
5811        0xff,    // --
5812        0xc1af0f, // *
5813        0xf9f79991, // /
5814        0xf9f79991, // % (With manual assist to swap results)
5815        0xc801, // +
5816        0xd8f7c829, // -
5817        0xe0d391, // <<
5818        0xf8d391, // >>
5819        0xe, // <=
5820        0xd, // >=
5821        0xc, // <
5822        0xf, // >
5823        0x4, // ==
5824        0x5, // !=
5825        0x0, // &&
5826        0x1, // ||
5827        0xc821, // &
5828        0xc831, // ^
5829        0xc809, // |
5830        0xd0f7, // ~
5831        0x4     // !
5832};
5833#endif
5834
5835struct ACCscript {
5836    ACCscript() {
5837        text = 0;
5838        textLength = 0;
5839        accError = ACC_NO_ERROR;
5840    }
5841
5842    ~ACCscript() {
5843        delete text;
5844    }
5845
5846    void registerSymbolCallback(ACCSymbolLookupFn pFn, ACCvoid* pContext) {
5847        compiler.registerSymbolCallback(pFn, pContext);
5848    }
5849
5850    void setError(ACCenum error) {
5851        if (accError == ACC_NO_ERROR && error != ACC_NO_ERROR) {
5852            accError = error;
5853        }
5854    }
5855
5856    ACCenum getError() {
5857        ACCenum result = accError;
5858        accError = ACC_NO_ERROR;
5859        return result;
5860    }
5861
5862    Compiler compiler;
5863    char* text;
5864    int textLength;
5865    ACCenum accError;
5866};
5867
5868
5869extern "C"
5870ACCscript* accCreateScript() {
5871    return new ACCscript();
5872}
5873
5874extern "C"
5875ACCenum accGetError( ACCscript* script ) {
5876    return script->getError();
5877}
5878
5879extern "C"
5880void accDeleteScript(ACCscript* script) {
5881    delete script;
5882}
5883
5884extern "C"
5885void accRegisterSymbolCallback(ACCscript* script, ACCSymbolLookupFn pFn,
5886                               ACCvoid* pContext) {
5887    script->registerSymbolCallback(pFn, pContext);
5888}
5889
5890extern "C"
5891void accScriptSource(ACCscript* script,
5892    ACCsizei count,
5893    const ACCchar ** string,
5894    const ACCint * length) {
5895    int totalLength = 0;
5896    for(int i = 0; i < count; i++) {
5897        int len = -1;
5898        const ACCchar* s = string[i];
5899        if (length) {
5900            len = length[i];
5901        }
5902        if (len < 0) {
5903            len = strlen(s);
5904        }
5905        totalLength += len;
5906    }
5907    delete script->text;
5908    char* text = new char[totalLength + 1];
5909    script->text = text;
5910    script->textLength = totalLength;
5911    char* dest = text;
5912    for(int i = 0; i < count; i++) {
5913        int len = -1;
5914        const ACCchar* s = string[i];
5915        if (length) {
5916            len = length[i];
5917        }
5918        if (len < 0) {
5919            len = strlen(s);
5920        }
5921        memcpy(dest, s, len);
5922        dest += len;
5923    }
5924    text[totalLength] = '\0';
5925
5926#ifdef DEBUG_SAVE_INPUT_TO_FILE
5927    int counter;
5928    char path[PATH_MAX];
5929    for (counter = 0; counter < 4096; counter++) {
5930        sprintf(path, DEBUG_DUMP_PATTERN, counter);
5931        if(access(path, F_OK) != 0) {
5932            break;
5933        }
5934    }
5935    if (counter < 4096) {
5936        FILE* fd = fopen(path, "w");
5937        if (fd) {
5938            fwrite(text, totalLength, 1, fd);
5939            fclose(fd);
5940        }
5941    }
5942#endif
5943}
5944
5945extern "C"
5946void accCompileScript(ACCscript* script) {
5947    int result = script->compiler.compile(script->text, script->textLength);
5948    if (result) {
5949        script->setError(ACC_INVALID_OPERATION);
5950    }
5951}
5952
5953extern "C"
5954void accGetScriptiv(ACCscript* script,
5955    ACCenum pname,
5956    ACCint * params) {
5957    switch (pname) {
5958        case ACC_INFO_LOG_LENGTH:
5959            *params = 0;
5960            break;
5961    }
5962}
5963
5964extern "C"
5965void accGetScriptInfoLog(ACCscript* script,
5966    ACCsizei maxLength,
5967    ACCsizei * length,
5968    ACCchar * infoLog) {
5969    char* message = script->compiler.getErrorMessage();
5970    int messageLength = strlen(message) + 1;
5971    if (length) {
5972        *length = messageLength;
5973    }
5974    if (infoLog && maxLength > 0) {
5975        int trimmedLength = maxLength < messageLength ?
5976                maxLength : messageLength;
5977        memcpy(infoLog, message, trimmedLength);
5978        infoLog[trimmedLength] = 0;
5979    }
5980}
5981
5982extern "C"
5983void accGetScriptLabel(ACCscript* script, const ACCchar * name,
5984                       ACCvoid ** address) {
5985    void* value = script->compiler.lookup(name);
5986    if (value) {
5987        *address = value;
5988    } else {
5989        script->setError(ACC_INVALID_VALUE);
5990    }
5991}
5992
5993extern "C"
5994void accGetPragmas(ACCscript* script, ACCsizei* actualStringCount,
5995                   ACCsizei maxStringCount, ACCchar** strings){
5996    script->compiler.getPragmas(actualStringCount, maxStringCount, strings);
5997}
5998
5999extern "C"
6000void accDisassemble(ACCscript* script) {
6001    script->compiler.disassemble(stderr);
6002}
6003
6004
6005} // namespace acc
6006
6007