U0 ParsePush(CParseStack *ps,I64 val)
{
        ps->stack[++ps->ptr] = val;
}

I64 ParsePop(CParseStack *ps)
{
        return ps->stack[ps->ptr--];
}

U0 ParsePush2(CParseStack *ps, I64 val)
{
        ps->stack2[++ps->ptr2] = val;
}

I64 ParsePop2(CParseStack *ps)
{
        return ps->stack2[ps->ptr2--];
}

U0 ParsePopDeref(CParseStack *ps)
{
        I64                     i = ParsePop(ps);
        CHashClass *tmpc = ParsePop(ps);

        if (i.u16[0] != IC_DEREF)
        {
                ParsePush(ps, tmpc);
                ParsePush(ps, i);
        }
}

I64 ParseKeyWord(CCompCtrl *cc)
{//Convert cur token to KEYWORD or -1.
        CHashGeneric *tmph;

        if (cc->token == TK_IDENT &&(tmph = cc->hash_entry) && tmph->type & HTT_KEYWORD)
                return tmph->user_data0;
        else
                return -1;
}

CHashClass *ParseClassNew()
{/*Ptrs to classes are handled by
allocating 5 structures for each
new class and representing a pointer
to a class by advancing 1 struct forward
for one * and two forward for two **.
*/
        I64                     i;
        CHashClass *res = CAlloc(sizeof(CHashClass) * (PTR_STARS_NUM + 1), Fs->code_heap), *tmpc = res;

        for (i = 0; i <= PTR_STARS_NUM; i++)
        {
                tmpc->type = HTT_CLASS;
                tmpc->raw_type = RT_PTR;
                tmpc->size = sizeof(U8 *);
                tmpc->ptr_stars_count = i;
                tmpc++;
        }
        res->last_in_member_list = &res->member_list_and_root;
        res->size = 0;

        return res;
}

CHashFun *ParseFunNew()
{
        I64                      i;
        CHashFun        *res = CAlloc(sizeof(CHashFun) * (PTR_STARS_NUM + 1), Fs->code_heap), *tmpf = res;

        for (i = 0; i <= PTR_STARS_NUM; i++)
        {
                tmpf->type = HTT_FUN;
                tmpf->raw_type = RT_PTR;
                tmpf->size = sizeof(U8 *);
                tmpf->ptr_stars_count = i;
                tmpf++;
        }
        res->last_in_member_list = &res->member_list_and_root;
        res->size = 0;

        return res;
}

CIntermediateCode *ICAdd(CCompCtrl *cc, I64 opcode_and_precedence, I64 arg, CHashClass *c, I64 flags=0)
{
        CIntermediateCode *tmpi = MAlloc(sizeof(CIntermediateCode));

        tmpi->ic_code = opcode_and_precedence.u16[0];
        tmpi->ic_precedence = opcode_and_precedence.u16[1];
        tmpi->ic_data = arg;
        tmpi->ic_class = c;
        if (cc->pass_trace)
        {
                Bts(&cc->flags, CCf_PASS_TRACE_PRESENT);
                flags |= ICF_PASS_TRACE;
        }
        if (cc->lock_count)
                flags |= ICF_LOCK;
        tmpi->ic_flags = flags;
        tmpi->ic_line = cc->last_line_num;
        QueueInsert(tmpi, cc->coc.coc_head.last);
        return tmpi;
}

U0 COCInit(CCompCtrl *cc)
{
        CCodeCtrl *tmpcbh = &cc->coc;

        QueueInit(&tmpcbh->coc_head.next);
        QueueInit(&tmpcbh->coc_next_misc);
        tmpcbh->coc_head.ic_code = IC_END;
}

U0 COCPush(CCompCtrl *cc)
{
        CCodeCtrl *tmpcbh = MAlloc(sizeof(CCodeCtrl));

        MemCopy(tmpcbh, &cc->coc, sizeof(CCodeCtrl));
        cc->coc.coc_next = tmpcbh;
}

CCompCtrl *COCPopNoFree(CCompCtrl *cc)
{
        CCodeCtrl *tmpcbh = cc->coc.coc_next;

        MemCopy(&cc->coc, tmpcbh, sizeof(CCodeCtrl));

        return tmpcbh;
}

U0 COCPop(CCompCtrl *cc)
{
        Free(COCPopNoFree(cc));
}

U0 COCAppend(CCompCtrl *cc, CCodeCtrl *tmpcbh)
{
        if (tmpcbh->coc_head.next != &cc->coc.coc_head.next)
        {
                cc->coc.coc_head.last->next = tmpcbh->coc_head.next;
                tmpcbh->coc_head.next->last = cc->coc.coc_head.last;
                cc->coc.coc_head.last = tmpcbh->coc_head.last;
                tmpcbh->coc_head.last->next = &cc->coc.coc_head.next;
        }
        if (tmpcbh->coc_next_misc != &cc->coc.coc_next_misc)
        {
                cc->coc.coc_last_misc->next = tmpcbh->coc_next_misc;
                tmpcbh->coc_next_misc->last = cc->coc.coc_last_misc;
                cc->coc.coc_last_misc = tmpcbh->coc_last_misc;
                tmpcbh->coc_last_misc->next = &cc->coc.coc_next_misc;
        }
        Free(tmpcbh);
}

CCodeMisc *COCMiscNew(CCompCtrl *cc, I64 ty)
{
        CCodeMisc *res = CAlloc(sizeof(CCodeMisc));

        res->addr = INVALID_PTR;
        res->type = ty;
        QueueInsert(res, cc->coc.coc_last_misc);

        return res;
}

CCodeMisc *COCGoToLabelFind(CCompCtrl *cc, U8 *name)
{
        CCodeMisc *cm = cc->coc.coc_next_misc;

        while (cm != &cc->coc.coc_next_misc)
        {
                if ((cm->type == CMT_GOTO_LABEL || cm->type == CMT_ASM_LABEL) && !StrCompare(cm->str, name))
                        return cm;
                cm = cm->next;
        }

        return NULL;
}

I64 COCFloatConstFind(CCompCtrl *cc, F64 d)
{
        I64                      i;
        CCodeMisc       *cm = cc->coc.coc_next_misc;

        while (cm != &cc->coc.coc_next_misc)
        {
                if (cm->type == CMT_FLOAT_CONSTS)
                {
                        for (i = 0; i < cm->num_consts; i++)
                                if (cm->float_consts[i] == d)
                                        return cm->addr + i * sizeof(F64);
                        if (cm->num_consts < CM_CONSTS_NUM)
                        {
                                cm->float_consts[cm->num_consts++] = d;
                                return cm->addr + i * sizeof(F64);
                        }
                }
                cm = cm->next;
        }
        cm = COCMiscNew(cc, CMT_FLOAT_CONSTS);
        cm->float_consts = MAlloc(CM_CONSTS_NUM * sizeof(F64));
        cm->float_consts[cm->num_consts++] = d;

        return cm->addr;
}

U0 COCDel(CCompCtrl *cc, CCodeCtrl *coc)
{
        CCodeMisc       *cm, *cm1;
        U8                      *undef = NULL;

        QueueDel(&coc->coc_head.next);
        cm = coc->coc_next_misc;
        while (cm != &coc->coc_next_misc)
        {
                cm1 = cm->next;
                switch (cm->type)
                {
                        case CMT_GOTO_LABEL:
                        case CMT_ASM_LABEL:
                                if (!(cm->flags & CMF_DEFINED))
                                {
                                        undef = cm->str;
                                        cm->str = NULL;
                                }
                                else if (!cm->use_count)
                                {
                                        PrintWarn("Unused label %s\n", cm->str);
                                        LexWarn(cc, "Unused label at ");
                                }
                                break;

                        case CMT_JMP_TABLE:
                                Free(cm->jmp_table);
                                break;

                        case CMT_FLOAT_CONSTS:
                                Free(cm->float_consts);
                                break;

                        case CMT_ARRAY_DIM:
                                LinkedListDel(cm->dim);
                                break;

                        case CMT_HASH_ENTRY:
                                HashDel(cm->h);
                                break;
                }
                Free(cm->str);
                Free(cm);
                cm = cm1;
        }
        if (undef)
        {
                PrintErr("Undefined goto label %s\n", undef);
                Free(undef);
                LexExcept(cc, "Undefined goto label at ");
        }
}

U0 COCHeaderPut(CCompCtrl *cc, I64 pass, Bool put)
{
        CIntermediateCode *tmpi;

        if (Bt(&cc->flags, CCf_PASS_TRACE_PRESENT))
        {
                if (put)
                {
                        if (Bt(&cc->saved_pass_trace, pass - 1))
                        {
                                "$IV,1$Pass %d:$IV,0$\n", pass - 1;
                                tmpi = cc->coc.coc_head.next;
                                while (tmpi->ic_code)
                                {
                                        if (tmpi->ic_flags & ICF_PASS_TRACE)
                                                ICPut(cc, tmpi);
                                        tmpi = tmpi->next;
                                }
                        }
                }
                else if (Bt(&cc->saved_pass_trace, pass))
                        "$IV,1$Pass %d:$IV,0$\n", pass;
        }
        cc->pass = pass;
}

U8 *COCCompile(CCompCtrl *cc, I64 *_code_size, CDebugInfo **_debug, I64 *_type)
{
        U8                      *res;
        CCodeMisc       *lb;
        I64                      i, code_size, last_code_size;

        COptReg reg_offsets[REG_REGS_NUM];
        if (_debug)
                *_debug = NULL;
        cc->pass = 0;
        COCHeaderPut(cc, 1, TRUE);
        OptPass012(cc);
        COCHeaderPut(cc, 2, TRUE);
        OptPass012(cc);
        COCHeaderPut(cc, 3, TRUE);
        OptPass3(cc, reg_offsets);
        COCHeaderPut(cc, 4, TRUE);
        OptPass4(cc, reg_offsets, _type);
        COCHeaderPut(cc, 5, TRUE);
        OptPass5(cc);
        COCHeaderPut(cc, 6, TRUE);
        OptPass6(cc);
        COCHeaderPut(cc, 7, TRUE);

        lb = cc->coc.coc_next_misc;
        while (lb != &cc->coc.coc_next_misc)
        {
                if (lb->type == CMT_JMP_TABLE)
                {
                        for (i = 0; i < lb->range; i++)
                                lb->jmp_table[i] = OptLabelFwd(lb->jmp_table[i]);
                        lb->default = OptLabelFwd(lb->default);
                }
                lb = lb->next;
        }

        COCHeaderPut(cc, 7, FALSE);
        OptPass789A(cc, reg_offsets, NULL, NULL);
        COCHeaderPut(cc, 8, FALSE);
        OptPass789A(cc, reg_offsets, NULL, NULL);
        COCHeaderPut(cc, 9, FALSE);
        code_size = OptPass789A(cc, reg_offsets, NULL, NULL);
        do
        {
                last_code_size = code_size;
                COCHeaderPut(cc, 9, FALSE);
                code_size = OptPass789A(cc, reg_offsets, NULL, NULL);
                if (code_size > last_code_size)
                {
                        "Pass:9 Code Size\n";
                        LexExcept(cc, "Compiler Optimization Error at ");
                }
        }
        while (code_size < last_code_size);

        if (cc->flags & CCF_AOT_COMPILE)
                res = MAlloc(code_size);
        else
        {
                res = MAlloc(code_size, Fs->code_heap);
                if (cc->htc.fun)
                        Fs->last_fun = cc->htc.fun;
        }
        COCHeaderPut(cc, 10, FALSE);
        code_size = OptPass789A(cc, reg_offsets, res, _debug);

        COCDel(cc, &cc->coc);
        if (Bt(&cc->opts, OPTf_TRACE))
        {
                if (cc->flags & CCF_AOT_COMPILE)
                {
                        if (cc->aotc->seg_size == 16)
                                Un(res, code_size, 16);
                        else if (cc->aotc->seg_size == 64)
                                Un(res, code_size, 64);
                        else
                                Un(res, code_size, 32);
                }
                else
                        Un(res,code_size, 64);
        }
        if (_code_size)
                *_code_size = code_size;
        cc->saved_pass_trace = cc->pass_trace;

        return res;
}