#define PE_UNARY_TERM1          0
#define PE_UNARY_TERM2          1
#define PE_MAYBE_MODIFIERS      2
#define PE_UNARY_MODIFIERS      3
#define PE_DEREFERENCE          4
#define PE_CHECK_BINARY_OPS1    5
#define PE_CHECK_BINARY_OPS2    6
#define PE_DO_UNARY_OP          7
#define PE_DO_BINARY_OP         8
#define PE_POP_HIGHER           9
#define PE_PUSH_LOWER           10
#define PE_POP_ALL1             11
#define PE_POP_ALL2             12

CIntermediateCode *ParseAddOp(CCompCtrl *cc, I64 stack_op, CHashClass *tmpc)
{
    CIntermediateCode   *tmpi = cc->coc.coc_head.last;
    Bool                 div_sizeof = FALSE;

    switch (stack_op.u16[0])
    {
        case IC_ADD:
            if (tmpc->ptr_stars_count && !tmpi->ic_class->ptr_stars_count && tmpi->ic_class->raw_type != RT_F64)
            {
                ICAdd(cc, IC_SIZEOF, 1, cmp.internal_types[RT_I64]);
                ICAdd(cc, IC_MUL, 0, cmp.internal_types[RT_I64]);
            }
            break;

        case IC_SUB:
            if (tmpc->ptr_stars_count && tmpi->ic_class->raw_type != RT_F64)
            {
                if (!tmpi->ic_class->ptr_stars_count)
                {
                    ICAdd(cc, IC_SIZEOF, 1, cmp.internal_types[RT_I64]);
                    ICAdd(cc, IC_MUL, 0, cmp.internal_types[RT_I64]);
                }
                else
                    div_sizeof = TRUE;
            }
            break;

        case IC_AND_AND:
        case IC_OR_OR:
            ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
            break;

        case IC_ADD_EQU:
        case IC_SUB_EQU:
            if (tmpc->ptr_stars_count)
            {
                ICAdd(cc, IC_SIZEOF, 1, cmp.internal_types[RT_I64]);
                ICAdd(cc, IC_MUL, 0, cmp.internal_types[RT_I64]);
            }
            break;
    }
    tmpi = ICAdd(cc, stack_op, 0, tmpc);
    if (stack_op.u8[3] & ECF_HAS_PUSH_CMP)
    {
        tmpi->ic_flags |= ICF_POP_CMP;
        ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
        ICAdd(cc, IC_AND_AND, 0, cmp.internal_types[RT_I64], ICF_POP_CMP);
    }
    if (div_sizeof)
    {
        tmpc--;
        if (tmpc->size != 1)
        {
            ICAdd(cc, IC_IMM_I64, tmpc->size, cmp.internal_types[RT_I64]);
            ICAdd(cc, IC_DIV, 0, cmp.internal_types[RT_I64]);
            tmpc = cmp.internal_types[RT_I64];
        }
    }

    return tmpi;
}

U0 ParseExpression2(CCompCtrl *cc, I64 *_max_prec, CParseStack *ps)
{
    I64                  i, cur_op, stack_op, state,
                         max_prec = PREC_NULL, unary_pre_prec, paren_prec, unary_post_prec, left_prec = PREC_MAX;
    CIntermediateCode   *tmpi;
    CHashClass          *tmpc;
    CMemberList         *local_var;
    CArrayDim           *tmpad = NULL;

    goto pe_unary_term1;
    while (TRUE)
    {
        switch [state]
        {
            case PE_UNARY_TERM1:
pe_unary_term1:
                unary_pre_prec = PREC_NULL;
                unary_post_prec = PREC_NULL;
                cc->flags &= ~(CCF_PAREN + CCF_PREINC + CCF_PREDEC + CCF_POSTINC + CCF_POSTDEC + CCF_FUN_EXP);

            case PE_UNARY_TERM2:
                state = ParseUnaryTerm(cc, ps, &local_var, &tmpad, &max_prec, &unary_pre_prec, &paren_prec);
                break;

            case PE_UNARY_MODIFIERS:
                state = ParseUnaryModifier(cc, ps, &local_var, &tmpad, &unary_post_prec);
                break;

            case PE_MAYBE_MODIFIERS:
                if (cc->token == '(')
                { //Typecast or fun_ptr
                    cc->flags |= CCF_RAX;
                    state = ParseUnaryModifier(cc, ps, &local_var, &tmpad, &unary_post_prec);
                }
                else
                    goto pe_check_binary_ops1;
                break;

            case PE_DEREFERENCE:
                if (!(cc->flags & (CCF_PREINC | CCF_PREDEC | CCF_POSTINC | CCF_POSTDEC)))
                    i = IC_DEREF + PREC_UNARY_PRE << 16;
                else
                {
                    if (cc->flags & CCF_POSTINC)
                        i = IC__PP + PREC_UNARY_POST << 16;
                    else if (cc->flags & CCF_POSTDEC)
                        i = IC__MM + PREC_UNARY_POST << 16;
                    else if (cc->flags & CCF_PREDEC)
                        i = IC_MM_ + PREC_UNARY_PRE << 16;
                    else
                        i = IC_PP_+PREC_UNARY_PRE << 16;
                    cc->flags &= ~(CCF_PREINC | CCF_PREDEC | CCF_POSTINC | CCF_POSTDEC);
                }
                tmpi = cc->coc.coc_head.last;
                if (cc->flags & (CCF_RAX | CCF_ARRAY))
                {
                    if (tmpi->ic_code == IC_DEREF)
                        tmpi->ic_code = i;
                }
                else
                {
                    tmpc = OptClassFwd(tmpi->ic_class - 1);
                    ICAdd(cc, i, 0, tmpc);
                }

            case PE_CHECK_BINARY_OPS1:
pe_check_binary_ops1:
                if (paren_prec)
                {
                    if (unary_pre_prec || unary_post_prec)
                    {
                        if (paren_prec <= unary_pre_prec && !unary_post_prec)
                            ParenWarning(cc);
                        paren_prec = PREC_NULL;
                    }
                    else if (paren_prec <= PREC_UNARY_PRE + ASSOC_MASK)
                        ParenWarning(cc);
                }
                cur_op = cmp.binary_ops[cc->token];


            case PE_CHECK_BINARY_OPS2:
pe_check_binary_ops2:
                stack_op = ParsePop(ps);
                tmpc = ParsePop(ps);
                if (!(0 < stack_op.u8[2] <= PREC_UNARY_PRE + ASSOC_MASK))
                    goto pe_do_binary_op;

            case PE_DO_UNARY_OP:
                if (cur_op.u16[0] == IC_POWER && stack_op.u16[0] == IC_UNARY_MINUS)
                {
                    Lex(cc); //skip ` op
                    left_prec = cur_op.i8[2];
                    ParsePush(ps, tmpc);
                    ParsePush(ps, stack_op);
                    ParsePush(ps, cc->coc.coc_head.last->ic_class);
                    ParsePush(ps, cur_op);
                    goto pe_unary_term1;
                }
                else
                {
                    tmpi = cc->coc.coc_head.last;
                    tmpc = tmpi->ic_class;
                    if (stack_op.u16[0] == IC_DEREF && tmpc->ptr_stars_count)
                        tmpc--;
                    else if (stack_op.u16[0] == IC_ADDR)
                    {
                        cc->abs_counts.c_addres++;
                        if (intermediate_code_table[tmpi->ic_code].type == IST_DEREF)
                            OptFree(tmpi);
                        tmpc++;
                    }
                    tmpc = OptClassFwd(tmpc);
                    if (stack_op)
                        ICAdd(cc, stack_op, 0, tmpc);
                    goto pe_check_binary_ops2;
                }

            case PE_DO_BINARY_OP:
pe_do_binary_op:
                ParsePush(ps, tmpc);
                ParsePush(ps, stack_op);
                if (!cur_op)
                    goto pe_pop_all1;

                switch (cur_op.u16[0])
                {
                    case IC_ADD:
                    case IC_SUB:
                        tmpi = cc->coc.coc_head.last;
                        if (!tmpi->ic_class->ptr_stars_count && tmpi->ic_class->raw_type != RT_F64)
                        {
                            ICAdd(cc, IC_SIZEOF, 1, cmp.internal_types[RT_I64]);
                            ICAdd(cc, IC_MUL, 0, cmp.internal_types[RT_I64]);
                        }
                        break;

                    case IC_AND_AND:
                    case IC_OR_OR:
                        ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
                        break;
                }
                if (cc->flags & CCF_FUN_EXP)
                {
                    ps->ptr2--;
                    cc->flags &= ~CCF_FUN_EXP;
                }
                Lex(cc); //skip op
                if (paren_prec > PREC_UNARY_PRE + ASSOC_MASK &&
                        paren_prec & ~ASSOC_MASK < left_prec & ~ASSOC_MASK + paren_prec & ASSOCF_RIGHT &&
                        paren_prec & ~ASSOC_MASK < cur_op.u8[2] & ~ASSOC_MASK + !(paren_prec & ASSOCF_RIGHT))
                    ParenWarning(cc);
                if (cur_op.u8[2] > max_prec)
                    max_prec = cur_op.u8[2];
                left_prec = cur_op.u8[2];
                if (intermediate_code_table[cur_op.u16[0]].type == IST_ASSIGN)
                {
                    tmpi = cc->coc.coc_head.last;
                    tmpc = OptClassFwd(tmpi->ic_class);
                    if (intermediate_code_table[tmpi->ic_code].type != IST_DEREF || !tmpc->ptr_stars_count &&
                            !Bt(&tmpc->flags, Cf_INTERNAL_TYPE))
                        LexExcept(cc, "Invalid lval at ");
                    tmpi->ic_code = IC_NOP1; //Important for setting class (pretty sure)
                    cur_op.u8[2] = PREC_ASSIGN | ASSOCF_RIGHT;
                }

            case PE_POP_HIGHER:
pe_pop_higher:
                stack_op = ParsePop(ps); //pop ops of higher prec
                tmpc = ParsePop(ps);
                if (!stack_op)
                    goto pe_push_lower;
                else if (cur_op.u8[2] & ~ASSOC_MASK == stack_op.u8[2] & ~ASSOC_MASK)
                {
                    if (cur_op.u8[2] & ASSOCF_RIGHT)
                        goto pe_push_lower;
                }
                else if (cur_op.u8[2] & ~ASSOC_MASK <= stack_op.u8[2] & ~ASSOC_MASK)
                    goto pe_push_lower;

                tmpi = ParseAddOp(cc, stack_op, tmpc);

                if (intermediate_code_table[cur_op.u16[0]].type   == IST_CMP &&
                    intermediate_code_table[stack_op.u16[0]].type == IST_CMP)
                {
                    tmpi->ic_flags |= ICF_PUSH_CMP;
                    ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
                    ICAdd(cc, IC_PUSH_CMP, 0, tmpc);
                    cur_op.u8[3] |= ECF_HAS_PUSH_CMP;
                }
                else if (cur_op.u16[0] == IC_AND_AND || cur_op.u16[0] == IC_OR_OR)
                    ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
                goto pe_pop_higher;

            case PE_PUSH_LOWER:
pe_push_lower:
                ParsePush(ps, tmpc);
                ParsePush(ps, stack_op);
                ParsePush(ps, cc->coc.coc_head.last->ic_class);
                ParsePush(ps, cur_op);
                goto pe_unary_term1;

            case PE_POP_ALL1:
pe_pop_all1:
                if (paren_prec > PREC_UNARY_PRE + ASSOC_MASK && 
                        paren_prec & ~ASSOC_MASK <= left_prec & ~ASSOC_MASK -
                        paren_prec & ASSOCF_LEFT - left_prec & ASSOCF_LEFT)
                    ParenWarning(cc);

            case PE_POP_ALL2:
pe_pop_all2:
                stack_op = ParsePop(ps);
                tmpc = ParsePop(ps);
                if (!stack_op.u16[0])
                    goto pe_done;
                ParseAddOp(cc, stack_op, tmpc);
                goto pe_pop_all2;
        }
    }
pe_done:
    if (_max_prec)
        *_max_prec = max_prec;
}

Bool ParseExpression(CCompCtrl *cc, I64 *_max_prec, Bool end_exp, CParseStack *_ps=NULL)
{
    Bool         res = TRUE;
    I64          old_flags = cc->flags;
    CParseStack *ps;

    if (_ps)
        ps = _ps;
    else
    {
        ps = MAlloc(sizeof(CParseStack));
        ps->ptr = 0;
        ps->ptr2 = 0;
    }
    ParsePush(ps, 0); //terminate
    ParsePush(ps, 0); //terminate
    try
//try catch causes noreg vars in function
        ParseExpression2(cc, _max_prec, ps);
    catch
    {
        if (Fs->except_ch == 'Compiler')
        {
            res = FALSE;
            Fs->catch_except = TRUE;
        }
    }
    if (!_ps)
    {
        if (ps->ptr)
            LexExcept(cc, "Compiler Parse Error at ");
        Free(ps);
    }
    if (res)
    {
        if (end_exp)
            ICAdd(cc, IC_END_EXP, 0, 0, ICF_RES_NOT_USED);
        if (cc->coc.coc_head.last->ic_class == cmp.internal_types[RT_U0])
            LexWarn(cc, "U0 Expression ");
    }
    cc->flags |= old_flags & (CCF_PREINC | CCF_PREDEC);

    return res;
}

U0 ParseSizeOf(CCompCtrl *cc)
{
    CHashClass  *tmpc;
    CMemberList *tmpm;
    CDebugInfo  *debug_info;
    I64          i;

    if (cc->token != TK_IDENT)
        LexExcept(cc, "Invalid class at ");
    if (tmpm = cc->local_var_entry)
    {
        tmpc = tmpm->member_class;
        i = tmpc->size * tmpm->dim.total_count;
        if (Lex(cc) == '.')
            goto pu_sizeof_member;
    }
    else
    {
        if (!(tmpc = cc->hash_entry) ||
                !(tmpc->type & (HTT_CLASS | HTT_INTERNAL_TYPE | HTT_GLOBAL_VAR | HTT_FUN | HTT_EXPORT_SYS_SYM)))
            LexExcept(cc, "Invalid class at ");
        if (tmpc->type & (HTT_FUN | HTT_EXPORT_SYS_SYM))
        {
            if (!(debug_info = tmpc(CHashFun *)->debug_info))
                LexExcept(cc, "Size not defined at ");
            i = debug_info->body[debug_info->max_line + 1 - debug_info->min_line] - debug_info->body[0];
            Lex(cc);
        }
        else
        {
            i = tmpc->size;
            while (Lex(cc) == '.')
            {
pu_sizeof_member:
                if (!(tmpc->type & (HTT_CLASS | HTT_GLOBAL_VAR)))
                    LexExcept(cc, "Invalid class at ");
                else if (tmpc->type & HTT_GLOBAL_VAR)
                    tmpc = tmpc(CHashGlobalVar *)->var_class;
                if (Lex(cc) != TK_IDENT || !(tmpm = MemberFind(cc->cur_str, tmpc)))
                    LexExcept(cc, "Invalid member at ");
                else if (cc->local_var_entry)
                    cc->local_var_entry->use_count--;
                tmpc = tmpm->member_class;
//Probably others like this:
                #assert offset(CHashClass.size) == offset(CHashGlobalVar.size)
                i = tmpc->size * tmpm->dim.total_count;
            }
        }
    }
    if (cc->token == '*')
    {
        while (Lex(cc) == '*');
        i = sizeof(U8 *);
    }
    ICAdd(cc, IC_IMM_I64, i, cmp.internal_types[RT_I64]);
}

U0 ParseOffsetOf(CCompCtrl *cc)
{
    CHashClass  *tmpc;
    CMemberList *tmpm;
    I64          i;

    if (cc->token != TK_IDENT)
        LexExcept(cc, "Invalid class at ");
    if (tmpm = cc->local_var_entry)
        tmpc = tmpm->member_class;
    else
    {
        tmpc = cc->hash_entry;
        if (!tmpc || !(tmpc->type & (HTT_CLASS | HTT_GLOBAL_VAR)))
            LexExcept(cc, "Invalid class at ");
        else if (tmpc->type & HTT_GLOBAL_VAR)
            tmpc = tmpc(CHashGlobalVar *)->var_class;
    }
    if (Lex(cc) != '.')
        LexExcept(cc, "Expecting '.' at ");
    i = 0;
    do
    {
        if (Lex(cc) != TK_IDENT || !(tmpm = MemberFind(cc->cur_str, tmpc)))
            LexExcept(cc, "Invalid member at ");
        else if (cc->local_var_entry)
            cc->local_var_entry->use_count--;
        i += tmpm->offset;
        tmpc = tmpm->member_class;
    }
    while (Lex(cc) == '.');

    ICAdd(cc, IC_IMM_I64, i, cmp.internal_types[RT_I64]);
}

I64 ParseFunCall(CCompCtrl *cc, CParseStack *ps, Bool indirect, CHashFun *tmpf)
{
    I64                  i, argc_count, default_val;
    Bool                 is_first_arg = TRUE, needs_right_paren, is_print, is_putchars, is_template_fun;
    CHashClass          *tmpc2, *last_class = NULL;
    CMemberList         *tmpm;
    CCodeCtrl           *tmpcbh, *tmpcbh1;
    CCodeMisc           *cm;
    CIntermediateCode   *tmpi;

    if (!tmpf)
    {
        if (cc->token == TK_CHAR_CONST)
        {
            if (!(tmpf = HashFind("PutChars", cc->htc.hash_table_list, HTT_FUN)))
                LexExcept(cc, "Missing header for Print() and PutChars() at ");
            if (!cc->cur_i64) //empty char signals PutChars with variable
                Lex(cc);
            is_print = FALSE;
            is_putchars = TRUE;
        }
        else
        {
            if (!(tmpf = HashFind("Print", cc->htc.hash_table_list, HTT_FUN)))
                LexExcept(cc, "Missing header for Print() and PutChars() at ");
            if (!*cc->cur_str) //empty string signals Print with variable format_str
                Lex(cc);
            is_putchars = FALSE;
            is_print = TRUE;
        }
    }
    else
    {
        is_print = FALSE;
        is_putchars = FALSE;
    }

    if (Bt(&tmpf->flags, Ff_INTERNAL) && IC_SQR <= tmpf->exe_addr <= IC_ATAN)
        is_template_fun = TRUE;
    else
        is_template_fun = FALSE;

    if (indirect)
    {
        if (!(cc->flags & (CCF_RAX | CCF_ARRAY)))
            ICAdd(cc, IC_DEREF, 0, cmp.internal_types[RT_PTR]);
        cc->coc.coc_head.last->ic_class = cmp.internal_types[RT_PTR];
        ICAdd(cc, IC_RAX_SET, 0, cmp.internal_types[RT_PTR]);
        ICAdd(cc, IC_NOP2, 1, cmp.internal_types[RT_PTR]); //balance the books
    }
    COCPush(cc);
    tmpcbh = cc->coc.coc_next;
    cc->coc.coc_next = NULL;
    i = tmpf->arg_count;
    tmpm = tmpf->member_list_and_root;
    argc_count = 0;
    if (cc->token == '(')
    {
        Lex(cc);
        needs_right_paren = TRUE;
    }
    else
        needs_right_paren = FALSE;
    while (i--)
    {
        COCInit(cc);
        if (!is_first_arg)
        {
            if (is_print)
            {
                if (cc->token == ',')
                    Lex(cc);
                else if (cc->token != ';')
                    LexExcept(cc, "Expecting ',' at ");
            }
            else
            {
                if (needs_right_paren)
                {
                    if (cc->token == ',')
                        Lex(cc);
                    else if (cc->token != ')')
                        LexExcept(cc, "Expecting ',' at ");
                }
            }
        }
        if (tmpm->flags & MLF_DEFAULT_AVAILABLE && (cc->token == ')' || cc->token == ',' || !needs_right_paren))
        {
            default_val = tmpm->default_val;
            if (tmpm->flags & MLF_LASTCLASS && last_class)
                default_val = (last_class - last_class->ptr_stars_count)->str;
            if (tmpm->flags & (MLF_STR_DEFAULT_AVAILABLE | MLF_LASTCLASS) && cc->flags & CCF_AOT_COMPILE)
            {
                cm = COCMiscNew(cc, CMT_STR_CONST);
                ICAdd(cc, IC_STR_CONST, cm, cmp.internal_types[RT_U8] + 1);
                cm->st_len = StrLen(default_val) + 1;
                cm->str = StrNew(default_val);
                cc->flags |= CCF_HAS_MISC_DATA;
            }
            else
                ICAdd(cc, IC_IMM_I64, default_val, tmpm->member_class);
        }
        else
        {
            if (!ParseExpression(cc, NULL, FALSE, ps))
                throw('Compiler');
            else
            {
                COCPush(cc);
                cc->pass = 0;
                OptPass012(cc);
                cc->pass = 1;
                tmpi = OptPass012(cc);
                COCPop(cc);
                last_class = OptClassFwd(tmpi->ic_class);
                tmpc2 = OptClassFwd(tmpm->member_class);
                if (tmpc2->raw_type == RT_F64 && !tmpm->dim.next && last_class->raw_type != RT_F64)
                    tmpi->ic_flags |= ICF_RES_TO_F64;
                else
                    if (tmpc2->raw_type != RT_F64 && last_class->raw_type == RT_F64)
                        tmpi->ic_flags |= ICF_RES_TO_INT;
            }
        }
        COCPush(cc);
        is_first_arg = FALSE;
        tmpm = tmpm->next;
    }
    if (tmpm && tmpm->flags & MLF_DOT_DOT_DOT)
    {
        COCInit(cc);
        tmpi = ICAdd(cc, IC_IMM_I64, 0, tmpm->member_class);
        COCPush(cc);
        if (is_print)
        {
            if (cc->token != ';')
            {
                do
                {
                    if (!is_first_arg)
                    {
                        if (cc->token == ',')
                            Lex(cc);
                        else
                            LexExcept(cc, "Expecting ',' at ");
                    }
                    COCInit(cc);
                    if (!ParseExpression(cc, NULL, FALSE, ps))
                        throw('Compiler');
                    COCPush(cc);
                    is_first_arg = FALSE;
                    argc_count++;
                }
                while (cc->token == ',');
            }
        }
        else if (needs_right_paren)
        {
            if (cc->token != ')')
            {
                do
                {
                    if (!is_first_arg)
                    {
                        if (cc->token == ',')
                            Lex(cc);
                        else
                            LexExcept(cc, "Expecting ',' at ");
                    }
                    COCInit(cc);
                    if (!ParseExpression(cc, NULL, FALSE, ps))
                        throw('Compiler');
                    COCPush(cc);
                    is_first_arg = FALSE;
                    argc_count++;
                }
                while (cc->token == ',');
            }
        }
        tmpi->ic_data = argc_count++; //++ so add_esp latter works
    }
    if (needs_right_paren)
    {
        if (cc->token == ')')
            Lex(cc);
        else
            LexExcept(cc, "Missing ')' at ");
    }
    tmpcbh1 = tmpcbh->coc_next;
    tmpcbh->coc_next = cc->coc.coc_next;
    cc->coc.coc_next = tmpcbh;
    COCPop(cc);
    tmpcbh = cc->coc.coc_next;
    cc->coc.coc_next = tmpcbh1;
    if (!is_template_fun)
        ICAdd(cc, IC_CALL_START, tmpf, 0);
    if (indirect)
        ICAdd(cc, IC_PUSH_REGS, 1 << REG_RAX, tmpf->return_class);
    while (tmpcbh)
    {
        tmpcbh1 = tmpcbh->coc_next;
        COCAppend(cc, tmpcbh);
        if (!Bt(&tmpf->flags, Ff_INTERNAL))
            cc->coc.coc_head.last->ic_flags |= ICF_PUSH_RES;
        tmpcbh = tmpcbh1;
    }
    if (Bt(&tmpf->flags, Ff_INTERNAL))
        ICAdd(cc, tmpf->exe_addr, 0, tmpf->return_class);
    else
    {
        if (indirect)
            ICAdd(cc, IC_CALL_INDIRECT, (argc_count + tmpf->arg_count) << 3, tmpf->return_class);
        else if (Bt(&tmpf->flags, Cf_EXTERN))
        {
            cc->abs_counts.externs++;
            if (cc->flags & CCF_AOT_COMPILE)
            {
                if (tmpf->type & HTF_IMPORT)
                    ICAdd(cc, IC_CALL_IMPORT, tmpf, tmpf->return_class);
                else
                    ICAdd(cc, IC_CALL_EXTERN, tmpf, tmpf->return_class);
            }
            else
                ICAdd(cc, IC_CALL_INDIRECT2, &tmpf->exe_addr, tmpf->return_class);
        }
        else
            ICAdd(cc, IC_CALL, tmpf->exe_addr, tmpf->return_class);
        if ((Bt(&tmpf->flags, Ff_RET1) || Bt(&tmpf->flags, Ff_ARGPOP)) && !Bt(&tmpf->flags, Ff_NOARGPOP))
        {
            if (indirect)
            {
                ICAdd(cc, IC_ADD_RSP1, (argc_count + tmpf->arg_count) << 3, tmpf->return_class);
                ICAdd(cc, IC_ADD_RSP, 8, tmpf->return_class);
            }
            else
                ICAdd(cc, IC_ADD_RSP1, (argc_count + tmpf->arg_count) << 3, tmpf->return_class);
        }
        else
        {
            if (indirect)
                argc_count++;
            ICAdd(cc, IC_ADD_RSP, (argc_count + tmpf->arg_count) << 3, tmpf->return_class);
        }
    }
    if (!is_template_fun)
        ICAdd(cc, IC_CALL_END, tmpf, tmpf->return_class);
    if (is_print || is_putchars)
        ICAdd(cc, IC_END_EXP, 0, 0, ICF_RES_NOT_USED);
    cc->flags = (cc->flags | CCF_RAX) & ~(CCF_ARRAY | CCF_FUN_EXP);

    return PE_UNARY_MODIFIERS;
}

I64 ParseUnaryTerm(CCompCtrl *cc, CParseStack *ps, CMemberList **_local_var, CArrayDim **_tmpad,
                   I64 *max_prec, I64 *unary_pre_prec, I64 *paren_prec)
{
    I64              i, j;
    CHashExport     *tmpex;
    CHashClass      *tmpc;
    CHashFun        *tmpf;
    CHashGlobalVar  *tmpg;
    CMemberList     *tmpm;
    CAsmUndefHash   *tmpauh;
    CCodeMisc       *cm;
    Bool             paren_warn;

    *_local_var = NULL;
    *paren_prec = PREC_NULL;
    switch (cc->token)
    {
        start:
            if (PREC_UNARY_PRE > *max_prec)
                *max_prec = PREC_UNARY_PRE;
            *unary_pre_prec = PREC_UNARY_PRE;
            start:
                case '~': i = IC_COM;           break;
                case '!': i = IC_NOT;           break;
                case '-': i = IC_UNARY_MINUS;   break;
                case '*': i = IC_DEREF;         break;
            end:
                Lex(cc); //Skip op
                break;

            case '&':
                if (Lex(cc) == TK_IDENT)
                {
                    if (tmpc = cc->hash_entry)
                    {
                        if (tmpc->type & HTT_FUN)
                        {
                            tmpf = tmpc;
                            if (!Bt(&tmpf->flags, Ff_INTERNAL))
                            {
                                if (Bt(&tmpf->flags, Cf_EXTERN))
                                {
                                    if (cc->flags & CCF_AOT_COMPILE)
                                    {
                                        if (cc->flags & CCF_ASM_EXPRESSIONS)
                                        {
                                            if (tmpex = HashFind(tmpf->str, cc->htc.hash_table_list, HTT_EXPORT_SYS_SYM))
                                                goto pu_export_sys_sym;
                                            else
                                                goto pu_new_sys_sym;
                                        }
                                        LexExcept(cc, "Can't take addr of extern fun");
                                    }
                                    cc->abs_counts.externs++;
                                    ICAdd(cc, IC_IMM_I64, &tmpf->exe_addr, cmp.internal_types[RT_PTR]);
                                    ICAdd(cc, IC_DEREF, 0, cmp.internal_types[RT_PTR]);
                                }
                                else
                                {
                                    if (cc->flags & CCF_AOT_COMPILE)
                                    {
                                        ICAdd(cc, IC_ABS_ADDR, tmpf->exe_addr, cmp.internal_types[RT_PTR]);
                                        if (cc->flags & CCF_ASM_EXPRESSIONS)
                                            cc->abs_counts.abs_addres++;
                                    }
                                    else
                                        ICAdd(cc, IC_IMM_I64, tmpf->exe_addr, cmp.internal_types[RT_PTR]);
                                }
                                cc->abs_counts.c_addres++;
                                Lex(cc);
                                return PE_MAYBE_MODIFIERS;
                            }
                        }
                        else if (tmpc->type & HTT_EXPORT_SYS_SYM)
                        {
                            tmpex = tmpc;
                            if (cc->flags & CCF_ASM_EXPRESSIONS && !(cc->flags & CCF_AOT_COMPILE) && tmpex->type & HTF_IMM)
                            {
                                cc->abs_counts.c_addres++;
                                ICAdd(cc, IC_IMM_I64, tmpex->val, cmp.internal_types[RT_PTR]);
                                Lex(cc);
                                return PE_MAYBE_MODIFIERS;
                            }
                            else
                                goto pu_export_sys_sym;
                        }
                    }
                    else if (cc->flags & CCF_ASM_EXPRESSIONS && !cc->local_var_entry)
                        goto pu_ident_but_not_local_var;
                }
                i = IC_ADDR;
                break;
        end:
            ParsePush(ps, tmpc);
            ParsePush(ps, PREC_UNARY_PRE << 16 + i);
            return PE_UNARY_TERM2;

        start:
            case TK_I64:
            case TK_CHAR_CONST:
            case TK_INS_BIN_SIZE:
                if (cc->cur_i64 < 0)
                    ICAdd(cc, IC_IMM_I64, cc->cur_i64, cmp.internal_types[RT_U64]);
                else
                    ICAdd(cc, IC_IMM_I64, cc->cur_i64, cmp.internal_types[RT_I64]);
                Lex(cc);
                break;

            case TK_F64:
                ICAdd(cc, IC_IMM_F64, cc->cur_f64(I64), cmp.internal_types[RT_F64]);
                Lex(cc);
                break;

            case TK_STR:
                cm = COCMiscNew(cc, CMT_STR_CONST);
                ICAdd(cc, IC_STR_CONST, cm, cmp.internal_types[RT_U8] + 1);
                cm->str = LexExtStr(cc, &cm->st_len);
                cc->flags |= CCF_HAS_MISC_DATA;
                break;

            case TK_INS_BIN:
                cm = COCMiscNew(cc, CMT_STR_CONST);
                ICAdd(cc, IC_STR_CONST, cm, cmp.internal_types[RT_U8] + 1);
                cm->str = cc->cur_str;
                cm->st_len = cc->cur_str_len;
                cc->cur_str = NULL;
                cc->flags |= CCF_HAS_MISC_DATA;
                Lex(cc);
                break;

            case '$':
                if (cc->flags & CCF_ASM_EXPRESSIONS)
                {
                    cc->abs_counts.abs_addres++;
                    if (cc->flags  &CCF_AOT_COMPILE)
                        ICAdd(cc, IC_ABS_ADDR, cc->aotc->rip, cmp.internal_types[RT_PTR]);
                    else
                        ICAdd(cc, IC_IMM_I64, cc->aotc->rip, cmp.internal_types[RT_PTR]);
                }
                else
                {
                    if (cc->flags & CCF_CLASS_DOL_OFFSET)
                        ICAdd(cc, IC_IMM_I64, cc->class_dol_offset, cmp.internal_types[RT_I64]);
                    else
                        ICAdd(cc, IC_RIP, 0, cmp.internal_types[RT_PTR]);
                }
                Lex(cc);
                break;
        end:
            if (PREC_TERM > *max_prec)
                *max_prec = PREC_TERM;
            return PE_MAYBE_MODIFIERS;

        case '(':
            if (Lex(cc) == TK_IDENT && cc->hash_entry && cc->hash_entry->type & (HTT_CLASS | HTT_INTERNAL_TYPE))
                LexExcept(cc, "Use ZealOS postfix typecasting at ");
            else
            {
                if (PREC_TERM > *max_prec)
                    *max_prec = PREC_TERM;
                if (cc->lex_include_stack->flags & LFSF_DEFINE)
                    paren_warn = FALSE;
                else
                    paren_warn = TRUE;
                if (!ParseExpression(cc, paren_prec, FALSE, ps))
                    throw('Compiler');
                if (!paren_warn)
                    *paren_prec = PREC_NULL;
                if (cc->token != ')')
                    LexExcept(cc, "Missing ')' at ");
                Lex(cc); //skip )
                cc->flags = cc->flags & ~CCF_ARRAY | CCF_RAX | CCF_PAREN;
                return PE_UNARY_MODIFIERS;
            }

        start:
            case '+':   break;
            case TK_PLUS_PLUS:   cc->flags |= CCF_PREINC;   break;
            case TK_MINUS_MINUS: cc->flags |= CCF_PREDEC;   break;
        end:
            if (PREC_UNARY_PRE > *max_prec)
                *max_prec = PREC_UNARY_PRE;
            *unary_pre_prec = PREC_UNARY_PRE;
            Lex(cc);
            return PE_UNARY_TERM2;

        case TK_IDENT:
            if (tmpm = cc->local_var_entry)
            {
                if (PREC_TERM > *max_prec)
                    *max_prec = PREC_TERM;
                cc->flags &= ~(CCF_RAX | CCF_ARRAY | CCF_FUN_EXP);
                tmpc = tmpm->member_class + 1;
                if (tmpm->flags & MLF_FUN && !(cc->flags & CCF_ASM_EXPRESSIONS))
                {
                    ParsePopDeref(ps);
                    cc->flags |= CCF_FUN_EXP;
                    ParsePush2(ps, tmpm->fun_ptr - tmpm->fun_ptr->ptr_stars_count);
                }
                if (tmpm->dim.next)
                {
                    *_tmpad = tmpm->dim.next;
                    cc->flags |= CCF_ARRAY;
                }
                if (tmpm->flags & MLF_STATIC)
                {
                    if (cc->flags & CCF_AOT_COMPILE)
                    {
                        //  if (tmpg->flags&GVF_DATA_HEAP) //TODO
                        //      ICAdd(cc,IC_HEAP_GLOBAL,tmpm->static_data,tmpc);
                        //  else
                        ICAdd(cc, IC_ABS_ADDR, tmpm->static_data_rip, tmpc);
                    }
                    else
                        ICAdd(cc, IC_IMM_I64, tmpm->static_data, tmpc);
                }
                else
                {
                    if (cc->flags & CCF_ASM_EXPRESSIONS)
                    {
                        i = ParsePop(ps);
                        ps->ptr--;
                        if (i.u16[0] != IC_ADDR)
                            LexExcept(cc, "Expecting '&' at ");
                        ICAdd(cc, IC_IMM_I64, tmpm->offset, cmp.internal_types[RT_PTR]);
                        *_local_var = tmpm;
                        Lex(cc);
                        return PE_MAYBE_MODIFIERS;
                    }
                    else
                    {
                        if (tmpm->dim.next && tmpm->offset > 0 && StrCompare(tmpm->str, "argv"))
                        {
                            tmpc++;
                            cc->flags &= ~CCF_ARRAY;
                        }
                        ICAdd(cc, IC_RBP, 0, tmpc);
                        ICAdd(cc, IC_IMM_I64, tmpm->offset, tmpc);
                        ICAdd(cc, IC_ADD, 0, tmpc);
                    }
                }
                Lex(cc); //skip var name
                *_local_var = tmpm;
                return PE_UNARY_MODIFIERS;
            }
pu_ident_but_not_local_var:
            if (!(tmpex = cc->hash_entry))
            {
                if (!(cc->flags & CCF_ASM_EXPRESSIONS))
                    LexExcept(cc, "Invalid lval at ");
                tmpc = NULL;
pu_new_sys_sym:
                tmpex = CAlloc(sizeof(CHashExport), Fs->code_heap);
                tmpex->str = cc->cur_str;
                cc->cur_str = NULL;
                if (!cc->htc.local_var_list && *tmpex->str == '@' && tmpex->str[1] == '@')
                {
                    tmpex->type = HTT_EXPORT_SYS_SYM | HTF_UNRESOLVED | HTF_LOCAL;
                    HashAdd(tmpex, cc->htc.local_hash_table);
                }
                else
                {
                    tmpex->type = HTT_EXPORT_SYS_SYM | HTF_UNRESOLVED;
                    if (tmpc)
                        HashAddAfter(tmpex, tmpc, cc->htc.global_hash_table);
                    else
                        HashAdd(tmpex, cc->htc.global_hash_table);
                }
            }
            switch (Bsf(tmpex->type))
            {
                case HTt_EXPORT_SYS_SYM:
pu_export_sys_sym:
                    if (PREC_TERM > *max_prec)
                        *max_prec = PREC_TERM;
                    if (!(tmpex->type & (HTF_IMM | HTF_IMPORT)))
                        cc->abs_counts.abs_addres++;
                    if (tmpex->type & HTF_UNRESOLVED)
                    {
                        if (!(cc->flags & CCF_ASM_EXPRESSIONS))
                            LexExcept(cc, "Illegal forward ref at ");
                        tmpauh = MAlloc(sizeof(CAsmUndefHash));
                        tmpauh->hash = tmpex;
                        tmpauh->next = cc->asm_undef_hash;
                        cc->asm_undef_hash = tmpauh;
                        if (tmpex->type & HTF_LOCAL)
                            cc->flags |= CCF_UNRESOLVED | CCF_LOCAL;
                        else
                            cc->flags |= CCF_UNRESOLVED;
                        ICAdd(cc, IC_IMM_I64, &tmpex->val, cmp.internal_types[RT_PTR], ICF_NO_RIP);
                        ICAdd(cc, IC_DEREF, 0, cmp.internal_types[RT_PTR]);
                    }
                    else
                    {
                        if (cc->flags & CCF_AOT_COMPILE && !(tmpex->type & HTF_IMM))
                            ICAdd(cc, IC_ABS_ADDR, tmpex->val, cmp.internal_types[RT_PTR]);
                        else
                        {
                            if (tmpex->type & HTF_IMM)
                                cc->abs_counts.c_addres++;
                            ICAdd(cc, IC_IMM_I64, tmpex->val, cmp.internal_types[RT_PTR]);
                        }
                    }
                    Lex(cc);
                    return PE_MAYBE_MODIFIERS;

                case HTt_FUN:
                    if (PREC_TERM > *max_prec)
                        *max_prec = PREC_TERM;
                    Lex(cc);    //skip fun name
                    return ParseFunCall(cc, ps, FALSE, tmpex);

                case HTt_GLOBAL_VAR:
                    if (PREC_TERM > *max_prec)
                        *max_prec = PREC_TERM;
                    tmpg = tmpex;
                    tmpc = tmpg->var_class + 1;
                    cc->flags &= ~(CCF_RAX | CCF_ARRAY | CCF_FUN_EXP);
                    if (tmpg->flags & GVF_ARRAY)
                    {
                        *_tmpad = tmpg->dim.next;
                        cc->flags |= CCF_ARRAY;
                    }
                    if (cc->flags & CCF_AOT_COMPILE)
                    {
                        if (tmpg->flags & GVF_EXTERN) //TODO
                            LexExcept(cc, "Feature not implemented ");
                        else
                        {
                            if (tmpg->flags & GVF_IMPORT)
                                ICAdd(cc, IC_ADDR_IMPORT, tmpg, tmpc);
                            else
                            {
                                if (tmpg->flags & GVF_DATA_HEAP)
                                    ICAdd(cc, IC_HEAP_GLOBAL, tmpg->heap_global, tmpc);
                                else
                                    ICAdd(cc, IC_ABS_ADDR, tmpg->data_addr_rip, tmpc);
                            }
                        }
                    }
                    else
                    {
                        if (tmpg->flags & GVF_EXTERN)
                        {
                            cc->abs_counts.externs++;
                            ICAdd(cc, IC_IMM_I64, &tmpg->data_addr, tmpc);
                            ICAdd(cc, IC_DEREF, 0, tmpc);
                        }
                        else
                            ICAdd(cc, IC_IMM_I64, tmpg->data_addr, tmpc);
                    }
                    Lex(cc);
                    if (tmpg->flags & GVF_FUN)
                    {
                        ParsePopDeref(ps);
                        cc->flags |= CCF_FUN_EXP;
                        ParsePush2(ps, tmpg->fun_ptr - tmpg->fun_ptr->ptr_stars_count);
                    }
                    return PE_UNARY_MODIFIERS;

                case HTt_CLASS:
                    ParseOffsetOf(cc);
                    return PE_MAYBE_MODIFIERS;

                case HTt_KEYWORD:
                    switch (tmpex(CHashGeneric *)->user_data0)
                    {
                        case KW_SIZEOF:
                            if (PREC_TERM > *max_prec)
                                *max_prec = PREC_TERM;
                            j = 0;
                            while (Lex(cc) == '(')
                                j++;
                            ParseSizeOf(cc);
                            while (j--)
                            {
                                if (cc->token != ')')
                                    LexExcept(cc, "Missing ')' at ");
                                Lex(cc);
                            }
                            return PE_MAYBE_MODIFIERS;

                        case KW_OFFSET:
                            if (PREC_TERM > *max_prec)
                                *max_prec = PREC_TERM;
                            j = 0;
                            while (Lex(cc) == '(')
                                j++;
                            ParseOffsetOf(cc);
                            while (j--)
                            {
                                if (cc->token != ')')
                                    LexExcept(cc, "Missing ')' at ");
                                Lex(cc);
                            }
                            return PE_MAYBE_MODIFIERS;

                        case KW_DEFINED:
                            if (PREC_TERM > *max_prec)
                                *max_prec = PREC_TERM;
                            j = 0;
                            while (Lex(cc) == '(')
                                j++;
                            if (cc->token == TK_IDENT && (cc->hash_entry || cc->local_var_entry))
                                ICAdd(cc, IC_IMM_I64, TRUE, cmp.internal_types[RT_I64]);
                            else
                                ICAdd(cc, IC_IMM_I64, FALSE, cmp.internal_types[RT_I64]);
                            Lex(cc);
                            while (j--)
                            {
                                if (cc->token != ')')
                                    LexExcept(cc, "Missing ')' at ");
                                Lex(cc);
                            }
                            return PE_MAYBE_MODIFIERS;
                    }
            }
    }
    LexExcept(cc, "Missing expression at ");
}

I64 ParseUnaryModifier(CCompCtrl *cc, CParseStack *ps, CMemberList **_local_var, CArrayDim **_tmpad, I64 *unary_post_prec)
{
    CHashClass          *tmpc, *tmpc1;
    CHashFun            *fun_ptr;
    CMemberList         *tmpm = *_local_var;
    CIntermediateCode   *tmpi, *tmpi1;
    CArrayDim           *tmpad1, tmpad2;
    CCodeMisc           *cm;
    I64                  mode, old_flags;
    Bool                 was_paren = Btr(&cc->flags, CCf_PAREN);

    *_local_var = NULL;
    switch (cc->token)
    {
        case '.':
            if (tmpm)
                tmpm->reg = REG_NONE;
            goto um_join;

        case TK_DEREFERENCE:
            tmpi = cc->coc.coc_head.last;
            if (!(cc->flags & (CCF_RAX | CCF_ARRAY)))
                ICAdd(cc, IC_DEREF + PREC_UNARY_PRE << 16, 0, tmpi->ic_class - 1);
            else
                tmpi->ic_class--;

                um_join:
            if (!*unary_post_prec)
                *unary_post_prec = PREC_TERM;
            tmpc = cc->coc.coc_head.last->ic_class;
            if ((!tmpc->ptr_stars_count || cc->flags & CCF_ARRAY) && cc->token == '.')
                LexExcept(cc, "Must be address, not value ");
            if (!(cc->flags & CCF_RAX))
                tmpc--;
            if (!(tmpc->type & HTT_CLASS))
                LexExcept(cc, "Invalid class at ");
            if (Lex(cc) != TK_IDENT || !(tmpm = MemberFind(cc->cur_str, tmpc)))
                LexExcept(cc, "Invalid member at ");
            else if (cc->local_var_entry)
                cc->local_var_entry->use_count--;
            Lex(cc);    //skip member name
            tmpc1 = tmpm->member_class + 1;
            ICAdd(cc, IC_IMM_I64, tmpm->offset, tmpc1);
            cc->flags &= ~(CCF_RAX | CCF_ARRAY | CCF_FUN_EXP);
            if (tmpm->dim.next)
            {
                *_tmpad = tmpm->dim.next;
                cc->flags |= CCF_ARRAY;
            }
            if (tmpm->flags & MLF_FUN)
            {
                ParsePopDeref(ps);
                ParsePush2(ps, tmpm->fun_ptr - tmpm->fun_ptr->ptr_stars_count);
                cc->flags |= CCF_FUN_EXP;
            }
            ICAdd(cc, IC_ADD, 0, tmpc1);
            return PE_UNARY_MODIFIERS;

        case '(':
            if (cc->flags & CCF_FUN_EXP)
            {
                if (!*unary_post_prec)
                    *unary_post_prec = PREC_TERM;
                return ParseFunCall(cc, ps, TRUE, ParsePop2(ps));
            }
            if (!*unary_post_prec)
                *unary_post_prec = PREC_TERM;
            if (Lex(cc) != TK_IDENT)
                LexExcept(cc, "Invalid class at ");
            if (Btr(&cc->flags, CCf_FUN_EXP))
                ps->ptr2--;
            cc->flags &= ~CCF_ARRAY;
            tmpc = cc->hash_entry;
            Lex(cc);
            mode = PRS0_TYPECAST | PRS1_NULL;
            tmpc = ParseType(cc, &tmpc, &mode, NULL, NULL, &fun_ptr, NULL, &tmpad2, 0);
            if (fun_ptr)
            {
                ParsePopDeref(ps);
                Bts(&cc->flags, CCf_FUN_EXP);
                ParsePush2(ps, fun_ptr);
                cm=COCMiscNew(cc, CMT_HASH_ENTRY);
                cm->h = fun_ptr;
            }
            if (*_tmpad = tmpad2.next)
            {
                cc->flags |= CCF_ARRAY;
                tmpc++;
                cm = COCMiscNew(cc, CMT_ARRAY_DIM);
                cm->dim = *_tmpad;
            }
            if (!(cc->flags & (CCF_RAX | CCF_ARRAY)))
                tmpc++;
            tmpi = cc->coc.coc_head.last;
            tmpi->ic_class = tmpc;
            ICAdd(cc, IC_HOLYC_TYPECAST, was_paren, tmpc);
            if (cc->token != ')')
                LexExcept(cc, "Missing ')' at ");
            Lex(cc);
            return PE_UNARY_MODIFIERS;

        case '[':
            if (!*unary_post_prec)
                *unary_post_prec = PREC_TERM;
            Lex(cc);
            tmpc = OptClassFwd(cc->coc.coc_head.last->ic_class);
            if (!tmpc->ptr_stars_count)
                LexExcept(cc, "Not array or ptr ");
            if (!(cc->flags & (CCF_ARRAY | CCF_RAX)))
            {
                tmpc = OptClassFwd(tmpc - 1);
                if (!tmpc->ptr_stars_count)
                    LexExcept(cc, "Not array or ptr ");
                ICAdd(cc, IC_DEREF + PREC_UNARY_PRE << 16, 0, tmpc);
            }
            tmpc1 = tmpc - 1;
            if (tmpad1 = *_tmpad)
            {
                ICAdd(cc, IC_IMM_I64, tmpad1->total_count * tmpc1->size, tmpc);
                if (*_tmpad = tmpad1->next)
                {
                    old_flags = cc->flags;
                    if (!ParseExpression(cc, NULL, FALSE, ps))
                        throw('Compiler');
                    cc->flags = cc->flags & ~CCF_FUN_EXP | old_flags & CCF_FUN_EXP;
                    if (cc->token != ']')
                        LexExcept(cc, "Missing ']' at ");
                    Lex(cc); //skip ]
                    tmpi1 = cc->coc.coc_head.last;
                    tmpi1->ic_flags |= ICF_RES_TO_INT;
                    ICAdd(cc, IC_MUL, 0, tmpc);
                    ICAdd(cc, IC_ADD, 0, tmpc);
                    cc->flags |= CCF_RAX;
                    return PE_UNARY_MODIFIERS;
                }
            }
            else
                ICAdd(cc, IC_IMM_I64, tmpc1->size, tmpc);
            old_flags = cc->flags;
            if (!ParseExpression(cc, NULL, FALSE, ps))
                throw('Compiler');
            cc->flags = cc->flags & ~CCF_FUN_EXP | old_flags & CCF_FUN_EXP;
            if (cc->token != ']')
                LexExcept(cc,"Missing ']' at ");
            Lex(cc); //skip ]
            tmpi1 = cc->coc.coc_head.last;
            tmpi1->ic_flags |= ICF_RES_TO_INT;
            ICAdd(cc, IC_MUL, 0, tmpc);
            ICAdd(cc, IC_ADD, 0, tmpc);
            cc->flags &= ~(CCF_RAX | CCF_ARRAY);
            return PE_UNARY_MODIFIERS;
        start:
            case TK_PLUS_PLUS:
                cc->flags |= CCF_POSTINC;
                break;

            case TK_MINUS_MINUS:
                cc->flags |= CCF_POSTDEC;
                break;
        end:
            if (!*unary_post_prec)
                *unary_post_prec = PREC_UNARY_POST;
            Lex(cc);
            return PE_DEREFERENCE;
    }

    return PE_DEREFERENCE;
}

U8 *LexExpression2Bin(CCompCtrl *cc, I64 *_type=NULL)
{//Compile cc expression. You call the code.
    U8  *res;
    I64  size;
    Bool old_trace = Btr(&cc->flags, CCf_PASS_TRACE_PRESENT);

    COCPush(cc);
    COCInit(cc);
    if (ParseExpression(cc, NULL, FALSE))
    {
        ICAdd(cc, IC_RETURN_VAL, 0, 0);
        ICAdd(cc, IC_RET, 0, 0);
        res = COCCompile(cc, &size, NULL, _type);
    }
    else
        res = NULL;
    COCPop(cc);
    BEqual(&cc->flags, CCf_PASS_TRACE_PRESENT, old_trace);

    return res;
}

Bool IsLexExpression2Bin(CCompCtrl *cc, U8 **_machine_code)
{//Compile cc expression to bin. Return error status.
    return ToBool(*_machine_code = LexExpression2Bin(cc));
}

I64 LexExpressionI64(CCompCtrl *cc)
{//Compile cc expression, forcing to I64 and eval.
    U8 *machine_code;
    I64 res, type;

    if (machine_code = LexExpression2Bin(cc, &type))
    {
        res = Call(machine_code);
        Free(machine_code);
        if (type == RT_F64)
            res = ToI64(res(F64));
    }
    else
        res = 0;

    return res;
}

F64 LexExpressionF64(CCompCtrl *cc)
{//Compile cc expression, forcing to F64 and eval.
    U8 *machine_code;
    I64 res, type;

    if (machine_code = LexExpression2Bin(cc, &type))
    {
        res = Call(machine_code);
        Free(machine_code);
        if (type != RT_F64)
            res(F64) = ToF64(res);
    }
    else
        res = 0;

    return res(F64);
}

I64 LexExpression(CCompCtrl *cc)
{//Compile cc expression and eval.  Might be I64 or F64.
    U8 *machine_code;
    I64 res;

    if (machine_code = LexExpression2Bin(cc))
    {
        res = Call(machine_code);
        Free(machine_code);
    }
    else
        res = 0;

    return res;
}