Bool ParseAsmImm(CCompCtrl *cc, CAsmArg *arg)
{
    if (arg->imm_or_off_present)
        LexExcept(cc, "Already one immediate at ");
    arg->imm_or_off_present = TRUE;
    arg->num.local_asm_undef_hash = NULL;
    arg->num.global_asm_undef_hash = NULL;
    cc->asm_undef_hash = NULL;
    cc->abs_counts = 0;
    cc->flags &= ~(CCF_UNRESOLVED + CCF_LOCAL);
    if (!IsLexExpression2Bin(cc, &arg->num.machine_code))
        LexSkipEol(cc);
    else
    {
        if (cc->abs_counts.externs)
            LexExcept(cc, "Extern Not Allowed at ");
        if (cc->flags & CCF_UNRESOLVED)
        {
            if (cc->flags & CCF_LOCAL)
                arg->num.local_asm_undef_hash = cc->asm_undef_hash;
            else
                arg->num.global_asm_undef_hash = cc->asm_undef_hash;

            cc->asm_undef_hash = NULL;
        } 
        else
        {
            arg->num.i = Call(arg->num.machine_code);
            arg->num.global_asm_undef_hash = cc->asm_undef_hash;
            cc->asm_undef_hash = NULL;
            Free(arg->num.machine_code);
            arg->num.machine_code = NULL;
        }
    }
    return TRUE;
}

U0 ParseAsmArg(CCompCtrl *cc, CAsmArg *arg, Bool rel)
{
    CHashGeneric *tmph, *tmph1;
    CHashReg     *tmpr;

    MemSet(arg, 0, sizeof(CAsmArg));
    arg->seg  = REG_NONE;
    arg->reg1 = REG_NONE;
    arg->reg2 = REG_NONE;
    arg->scale = 1;
    while (TRUE)
    {
        if (cc->token == TK_IDENT)
        {
            if (tmph = cc->hash_entry)
            {
                if (tmph->type & HTG_TYPE_MASK == HTT_REG)
                {
                    tmpr = tmph;
                    arg->reg1_type = tmpr->reg_type;
                    switch (tmpr->reg_type)
                    {
                        start:
                            case REGT_R8:
                                arg->size = 1;
                                break;

                            case REGT_R16:
                                arg->size = 2;
                                break;

                            case REGT_R32:
                                arg->size = 4;
                                break;

                            case REGT_R64:
                            case REGT_FSTACK:
                            case REGT_MM:
                                arg->size = 8;
                                break;

                            case REGT_XMM:
                                arg->size = 16;
                                break;
                        end:
                            arg->reg1 = tmpr->reg_num;
                            Lex(cc);
                            return;

                        case REGT_SEG:
                            arg->seg = tmpr->reg_num;
                            if (Lex(cc) != ':')
                            {
                                arg->just_seg = TRUE;
                                return;
                            }
                            else
                                Lex(cc); //skip ":"
                            break;
                    }
                }
                else
                {
                    if ((tmph->type & HTG_TYPE_MASK == HTT_CLASS || tmph->type & HTG_TYPE_MASK == HTT_INTERNAL_TYPE) &&
                            (tmph1 = HashFind(cc->cur_str, cmp.asm_hash, HTT_ASM_KEYWORD)))
                        tmph = tmph1;
                    if (tmph->type & HTG_TYPE_MASK == HTT_ASM_KEYWORD)
                    {
                        switch (tmph->user_data0)
                        {
                            case AKW_I8:
                            case AKW_U8:
                                arg->size = 1;
                                break;

                            case AKW_I16:
                            case AKW_U16:
                                arg->size = 2;
                                break;

                            case AKW_I32:
                            case AKW_U32:
                                arg->size = 4;
                                break;

                            case AKW_I64:
                            case AKW_U64:
                                arg->size = 8;
                                break;

                            default:
                                LexExcept(cc, "syntax error at ");
                        }
                        Lex(cc); //skip keyword
                    }
                    else
                        goto pa_asm_direct_imm;
                }
            }
            else
            {
pa_asm_direct_imm:
                ParseAsmImm(cc, arg);
                arg->num.abs_counts = cc->abs_counts;
                if (arg->size <= 1 && !rel && arg->num.abs_counts & 1)
                {
                    if (cc->aotc->seg_size == 16)
                        arg->size = 2;
                    else
                        arg->size = 4;
                }
                if (cc->token != '[')
                    return;
            }
        }
        else if (cc->token == '[')
        {
            arg->indirect = TRUE;
            Lex(cc); // skip [
            while (cc->token && cc->token != ']')
            {
                if (cc->token == TK_IDENT)
                {
                    if (tmph = cc->hash_entry)
                    {
                        if (tmph->type & HTG_TYPE_MASK == HTT_REG && REGT_R16 <= tmph(CHashReg *)->reg_type <= REGT_R64)
                        {
                            tmpr = tmph;
                            arg->reg2_type = tmpr->reg_type;
                            if (arg->reg1 == REG_NONE)
                            {
                                if (tmpr->reg_num & 7 == REG_RSP)
                                {
                                    arg->reg1 = 4;
                                    arg->reg2 = tmpr->reg_num;
                                }
                                else
                                    arg->reg1 = tmpr->reg_num;
                            }
                            else
                                arg->reg2 = tmpr->reg_num;
                            Lex(cc);
                        }
                        else
                            goto pa_asm_indirect_imm;
                    }
                    else
                        goto pa_asm_indirect_imm;
                }
                else if (cc->token == '*')
                {
                    Lex(cc);
                    if (cc->token != TK_I64)
                        LexExcept(cc, "Expecting scale factor at ");
                    arg->scale = cc->cur_i64;
                    Lex(cc); //skip scale
                    if (arg->reg2 != REG_NONE)
                    {
                        SwapI64(&arg->reg1, &arg->reg2);
                        SwapI64(&arg->reg1_type, &arg->reg2_type);
                    }
                }
                else if (cc->token == '+')
                {
                    Lex(cc); //skip '+'
                }
                else
                {
pa_asm_indirect_imm:
                    ParseAsmImm(cc, arg);
                    arg->num.abs_counts = cc->abs_counts;
                }
            }
            if (cc->token != ']')
                LexExcept(cc, "Missing ']' at ");
            Lex(cc); //skip ]
            return;
        }
        else
            goto pa_asm_direct_imm;
    }
}

#define XMM_IND_MASK    (1 << ARGT_XMM0 | 1 << ARGT_XMM128 | 1 << ARGT_XMM32 | 1 << ARGT_XMM64)
#define XMM_MASK        (1 << ARGT_XMM)
#define XMM_ALL_MASK    (XMM_IND_MASK | XMM_MASK)

I64 AsmMakeArgMask(CCompCtrl *cc, CAsmArg *arg)
{
    CAOTCtrl    *aotc = cc->aotc;
    I64          res;

    if (arg->just_seg)
    {
        switch (arg->seg)
        {
            case 0:
                res = 1 << ARGT_ES | 1 << ARGT_SREG;
                break;

            case 1:
                res = 1 << ARGT_CS | 1 << ARGT_SREG;
                break;

            case 2:
                res = 1 << ARGT_SS | 1 << ARGT_SREG;
                break;

            case 3:
                res = 1 << ARGT_DS | 1 << ARGT_SREG;
                break;

            case 4:
                res = 1 << ARGT_FS | 1 << ARGT_SREG;
                break;

            case 5:
                res = 1 << ARGT_GS | 1 << ARGT_SREG;
                break;
        }
        goto mm_done;
    }
    if (arg->reg1_type == REGT_FSTACK)
    {
        if (arg->reg1)
            res = 1 << ARGT_STI;
        else
            res = 1 << ARGT_ST0 | 1 << ARGT_STI;
        goto mm_done;
    }
    res = cmp.size_arg_mask[arg->size];
    if (aotc->seg_size == 64)
        res &= 0xFF0FFFFFFF | XMM_ALL_MASK;

    if (arg->reg1 != REG_NONE && arg->imm_or_off_present && !arg->num.i &&
            !arg->num.global_asm_undef_hash && !arg->num.local_asm_undef_hash)
        arg->imm_or_off_present = FALSE;    //Zero displacement

    if (arg->reg2 != REG_NONE || arg->scale != 1)
    {
        res &= 0x0000FF0000;
        goto mm_done;
    }

    if (arg->indirect)
    {
        if (arg->imm_or_off_present)
            res &= 0x00FFFF0000 | XMM_IND_MASK;
        else
            res &= 0x000FFF0000 | XMM_IND_MASK;
    }
    else
    {
        if (arg->imm_or_off_present)
            res &= 0x000F000FFE | XMM_ALL_MASK;
        else
            res &= 0x3F0FFFF000 | XMM_ALL_MASK;
    }
    if (arg->seg != REG_NONE)
        res &= 0x00FFFF0000 | XMM_ALL_MASK;
    if (arg->reg1 == REG_NONE)
    {
        if (arg->indirect)
            res &= 0x00FFFF0000 | XMM_IND_MASK;
        else if (arg->num.i < 0)
        {
            if (arg->num.i >= I8_MIN)
                res &= 0x8FE;
            else if (arg->num.i >= I16_MIN)
                res &= 0x8EE;
            else if (arg->num.i >= I32_MIN)
                res &= 0x8CE;
            else
                res &= 0x88E;
        }
        else
        {
            if (arg->num.i <= I8_MAX)
                res &= 0xFFE;
            else if (arg->num.i <= U8_MAX)
                res &= 0xFEE;
            else if (arg->num.i <= I16_MAX)
                res &= 0xEEE;
            else if (arg->num.i <= U16_MAX)
                res &= 0xECE;
            else if (arg->num.i <= I32_MAX)
                res &= 0xCCE;
            else if (arg->num.i <= U32_MAX)
                res &= 0xC8E;
            else
                res &= 0x88E;
        }
    }
    else
    {
        res &= 0x3F00FFF000 | XMM_ALL_MASK;
        if (!arg->indirect) //M8-M64
            res &= 0xFFFF0FFFFF | XMM_ALL_MASK;
    }
    switch (arg->reg1)
    {
        case REG_RAX:
            res &= ~0x3000000000;
            break;

        case REG_RCX:
            res &= ~0x2F00000000;
            break;

        case REG_RDX:
            res &= ~0x1F00000000;
            break;

        default:
            res &= ~0x3F00000000;
    }
mm_done:
    return res;
}

Bool AsmStoreNum(CCompCtrl *cc, CAsmNum2 *num2, I64 count, Bool U8_avail)
{
    CAOTCtrl    *aotc = cc->aotc;
    I64          i;
    CAOTAbsAddr *tmpa;

    if (!num2->imm_flag)
        num2->num.i -= num2->rel;
    for (i = 0; i < count; i++)
    {
        if (num2->U8_count == 1)
        {
            if (num2->num.local_asm_undef_hash || num2->num.global_asm_undef_hash)
                AsmUnresolvedAdd(cc, num2->num.machine_code, IET_REL_I8 + num2->imm_flag, aotc->rip, num2->rel,
                    num2->num.local_asm_undef_hash, num2->num.global_asm_undef_hash,
                    cc->lex_include_stack->line_num, U8_avail);
            else if (!num2->imm_flag && !(I8_MIN <= num2->num.i <= I8_MAX))
                LexExcept(cc,"Branch out of range at ");
            if (num2->imm_flag)
            {
                if (num2->num.abs_counts.abs_address & 1)
                {
                    tmpa = CAlloc(sizeof(CAOTAbsAddr));
                    tmpa->next = aotc->abss;
                    aotc->abss = tmpa;
                    tmpa->rip = aotc->rip;
                    tmpa->type = AAT_ADD_U8;
                }
            }
            else
            {
                if (num2->num.abs_counts.c_address & 1)
                {
                    tmpa = CAlloc(sizeof(CAOTAbsAddr));
                    tmpa->next = aotc->abss;
                    aotc->abss = tmpa;
                    tmpa->rip = aotc->rip;
                    tmpa->type = AAT_SUB_U8;
                }
            }
            AOTStoreCodeU8(cc, num2->num.i);
        }
        else
        {
            if (num2->U8_count == 2)
            {
                if (num2->num.local_asm_undef_hash || num2->num.global_asm_undef_hash)
                    AsmUnresolvedAdd(cc, num2->num.machine_code, IET_REL_I16 + num2->imm_flag, aotc->rip, num2->rel,
                        num2->num.local_asm_undef_hash, num2->num.global_asm_undef_hash,
                        cc->lex_include_stack->line_num, U8_avail);
                else if (!num2->imm_flag && !(I16_MIN <= num2->num.i <= I16_MAX))
                    LexExcept(cc,"Branch out of range at ");
                if (num2->imm_flag)
                {
                    if (num2->num.abs_counts.abs_address & 1)
                    {
                        tmpa = CAlloc(sizeof(CAOTAbsAddr));
                        tmpa->next = aotc->abss;
                        aotc->abss = tmpa;
                        tmpa->rip = aotc->rip;
                        tmpa->type = AAT_ADD_U16;
                    }
                }
                else
                {
                    if (num2->num.abs_counts.c_address & 1)
                    {
                        tmpa = CAlloc(sizeof(CAOTAbsAddr));
                        tmpa->next = aotc->abss;
                        aotc->abss = tmpa;
                        tmpa->rip = aotc->rip;
                        tmpa->type = AAT_SUB_U16;
                    }
                }
                AOTStoreCodeU8(cc, num2->num.i.u8[0]);
                AOTStoreCodeU8(cc, num2->num.i.u8[1]);
            }
            else if (num2->U8_count == 4)
            {
                if (num2->num.local_asm_undef_hash || num2->num.global_asm_undef_hash)
                    AsmUnresolvedAdd(cc, num2->num.machine_code, IET_REL_I32 + num2->imm_flag, aotc->rip, num2->rel,
                        num2->num.local_asm_undef_hash, num2->num.global_asm_undef_hash,
                        cc->lex_include_stack->line_num, U8_avail);
                else if (!num2->imm_flag && !(I32_MIN <= num2->num.i <= I32_MAX))
                    LexExcept(cc,"Branch out of range at ");
                if (num2->imm_flag)
                {
                    if (num2->num.abs_counts.abs_address & 1)
                    {
                        tmpa = CAlloc(sizeof(CAOTAbsAddr));
                        tmpa->next = aotc->abss;
                        aotc->abss = tmpa;
                        tmpa->rip = aotc->rip;
                        tmpa->type = AAT_ADD_U32;
                    }
                }
                else
                {
                    if (num2->num.abs_counts.c_address & 1)
                    {
                        tmpa = CAlloc(sizeof(CAOTAbsAddr));
                        tmpa->next = aotc->abss;
                        aotc->abss = tmpa;
                        tmpa->rip = aotc->rip;
                        tmpa->type = AAT_SUB_U32;
                    }
                }
                AOTStoreCodeU32(cc, num2->num.i);
            }
            else if (num2->U8_count == 8)
            {
                if (num2->num.local_asm_undef_hash || num2->num.global_asm_undef_hash)
                    AsmUnresolvedAdd(cc, num2->num.machine_code, IET_REL_I64 + num2->imm_flag, aotc->rip, num2->rel,
                        num2->num.local_asm_undef_hash, num2->num.global_asm_undef_hash,
                        cc->lex_include_stack->line_num, U8_avail);
                if (num2->imm_flag)
                {
                    if (num2->num.abs_counts.abs_address & 1)
                    {
                        tmpa = CAlloc(sizeof(CAOTAbsAddr));
                        tmpa->next = aotc->abss;
                        aotc->abss = tmpa;
                        tmpa->rip = aotc->rip;
                        tmpa->type = AAT_ADD_U64;
                    }
                }
                else
                {
                    if (num2->num.abs_counts.c_address & 1)
                    {
                        tmpa = CAlloc(sizeof(CAOTAbsAddr));
                        tmpa->next = aotc->abss;
                        aotc->abss = tmpa;
                        tmpa->rip = aotc->rip;
                        tmpa->type = AAT_SUB_U64;
                    }
                }
                AOTStoreCodeU64(cc, num2->num.i);
            }
            if (U8_avail && !num2->num.local_asm_undef_hash && !num2->num.global_asm_undef_hash &&
                !num2->imm_flag && -124 <= num2->num.i <= 123)
            {
                LexWarn(cc, "could use I8 displacement at ");
                return FALSE;
            }
        }
    }

    return TRUE;
}

U8 asm_seg_prefixes[6] = {0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65};

Bool ParseAsmInst(CCompCtrl *cc, CHashOpcode *tmpo, I64 argcount)
{
    CAOTCtrl    *aotc = cc->aotc;
    I64          i, j, arg1, arg2, arg3, om, seg, arg1mask, arg2mask, arg3mask;
    CAsmArg     *tmpa1, *tmpa2, *tmpa3;
    Bool         ModrM_complete, U8_avail = FALSE, found_second_possible = FALSE, isXMM, isXMM1, isXMM2;
    CInst       *tmpins;
    CAsmIns      cur, best;

    best.U8_count = 255;
    if (argcount > 0)
        arg1mask = AsmMakeArgMask(cc, &aotc->arg1);
    else
        arg1mask = 1;

    if (argcount > 1)
        arg2mask = AsmMakeArgMask(cc, &aotc->arg2);
    else
        arg2mask = 1;

    if (argcount > 2)
        arg3mask = AsmMakeArgMask(cc, &aotc->arg3);
    else
        arg3mask = 1;

    for (i = 0; i < tmpo->inst_entry_count; i++)
    {
        tmpins = &tmpo->ins[i];

        if (tmpins->arg1 == ARGT_REL8 || tmpins->arg2 == ARGT_REL8)
            U8_avail = TRUE;

        if (Bt(&arg1mask, tmpins->arg1) && Bt(&arg2mask, tmpins->arg2) &&
            (!(tmpins->flags & IEF_NOT_IN_64_BIT) || aotc->seg_size != 64))
        {
            MemSet(&cur, 0, sizeof(CAsmIns));
            cur.tmpins = tmpins;
            ModrM_complete = FALSE;
            cur.is_default = ToBool(tmpins->flags & IEF_DEFAULT);
            if (aotc->seg_size == 64)
            {
                if (tmpins->flags & IEF_48_REX)
                    cur.REX = 0x48;
                else
                    cur.REX = 0x40;
            }
            cur.disp.imm_flag   = TRUE;
            cur.imm.imm_flag    = TRUE;
            om      = tmpins->opcode_modifier;
            arg1    = tmpins->arg1;
            arg2    = tmpins->arg2;
            arg3    = tmpins->arg3;
            tmpa1   = &aotc->arg1;
            tmpa2   = &aotc->arg2;
            tmpa3   = &aotc->arg3;
            cur.last_opcode_U8  = tmpins->opcode[tmpins->opcode_count - 1];

            isXMM1 = ARGT_XMM <= arg1 <= ARGT_XMM0;
            isXMM2 = ARGT_XMM <= arg2 <= ARGT_XMM0;
            isXMM = isXMM1 || isXMM2;

            if (tmpins->slash_val < 8)
            {
                cur.ModrM |= tmpins->slash_val << 3;
                cur.has_ModrM = TRUE;
            }

            if (aotc->seg_size == 16 && tmpins->flags & IEF_OP_SIZE32 || aotc->seg_size != 16 && tmpins->flags & IEF_OP_SIZE16)
                cur.has_operand_prefix = TRUE;

            if (om == OM_IB)
                cur.imm.U8_count = 1;
            else if (om == OM_IW)
                cur.imm.U8_count = 2;
            else if (om == OM_ID)
                cur.imm.U8_count = 4;

            if (om == OM_CB)
            {
                cur.imm.U8_count = 1;
                cur.imm.imm_flag = FALSE;
            }
            else if (om == OM_CW)
            {
                cur.imm.U8_count = 2;
                cur.imm.imm_flag = FALSE;
            }
            else if (om == OM_CD)
            {
                cur.imm.U8_count = 4;
                cur.imm.imm_flag = FALSE;
            }

            if (argcount == 1)
            {
                if (best.U8_count != 255 && !found_second_possible && !best.is_default)
                {
                    found_second_possible = TRUE;
                    if (!aotc->arg1.size)
                        PrintWarn("no size specified at %s,%04d\n",
                                    cc->lex_include_stack->full_name,
                                    cc->lex_include_stack->line_num - 1);
                }
                if (tmpins->flags & IEF_PLUS_OPCODE)
                {
                    if (tmpins->slash_val == SV_R_REG)
                    {
                        cur.last_opcode_U8 |= tmpa1->reg1 & 7;
                        if (tmpa1->reg1 & 15 > 7)
                            cur.REX |= 1;
                        if (tmpa1->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                            cur.has_REX = TRUE;
                    }
                    else
                    {//SV_I_REG
                        if (tmpa1->reg1_type == REGT_FSTACK)
                            cur.last_opcode_U8 += tmpa1->reg1;
                    }
                }
                if (arg1 == ARGT_R64 || arg1 == ARGT_RM64 || arg1 == ARGT_M64)
                    cur.REX |= 8;
                if (ARGT_RM8 <= arg1 <= ARGT_RM64 || ARGT_M8 <= arg1 <= ARGT_M64)
                {
                    if (aotc->seg_size == 16)
                        cur.has_addr_prefix = TRUE;

                    cur.has_ModrM = TRUE;
                    if (tmpa1->imm_or_off_present && tmpa1->indirect && tmpa1->reg1 == REG_NONE)
                    {
                        cur.ModrM = cur.ModrM + 5;
                        MemCopy(&cur.disp.num, &tmpa1->num, sizeof(CAsmNum));
                        cur.disp.U8_count = 4;
                        if (aotc->seg_size == 64)
                            cur.disp.imm_flag = FALSE;
                    }
                    else
                    {
                        if (tmpa1->reg2 == REG_NONE && tmpa1->scale == 1)
                        {
                            cur.ModrM |= tmpa1->reg1 & 7;
                            if (tmpa1->reg1 & 15 > 7)
                                cur.REX |= 1;
                            if (tmpa1->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                cur.has_REX = TRUE;
                        }
                        else
                        {
                            cur.ModrM |= 4;
                            cur.has_SIB = TRUE;
                            if (tmpa1->scale == 1)
                                cur.SIB = 0;
                            else if (tmpa1->scale == 2)
                                cur.SIB = 0x40;
                            else if (tmpa1->scale == 4)
                                cur.SIB = 0x80;
                            else if (tmpa1->scale == 8)
                                cur.SIB = 0xC0;
                            if (tmpa1->reg2 == REG_NONE)
                            {
                                ModrM_complete = TRUE;
                                cur.SIB |= (tmpa1->reg1 & 7) << 3 + REG_RBP;
                                if (tmpa1->reg1 & 15 > 7)
                                    cur.REX |= 2;
                                if (tmpa1->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                    cur.has_REX = TRUE;
                                MemCopy(&cur.disp.num, &tmpa1->num, sizeof(CAsmNum));
                                cur.disp.U8_count = 4;
                            }
                            else
                            {
                                cur.SIB |= (tmpa1->reg1 & 7) << 3 + tmpa1->reg2 & 7;
                                if (tmpa1->reg1 & 15 > 7)
                                    cur.REX |= 2;
                                if (tmpa1->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                    cur.has_REX = TRUE;
                                if (tmpa1->reg2 & 15 > 7)
                                    cur.REX |= 1;
                                if (tmpa1->reg2 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                    cur.has_REX = TRUE;
                                if (tmpa1->reg2&7 == REG_RBP && !tmpa1->imm_or_off_present && tmpa1->indirect)
                                {
                                    cur.ModrM |= 0x40;
                                    cur.disp.U8_count = 1;
                                    ModrM_complete = TRUE;
                                }
                            }
                        }
                        if (!ModrM_complete)
                        {
                            if (tmpa1->imm_or_off_present)
                            {
                                MemCopy(&cur.disp.num, &tmpa1->num, sizeof(CAsmNum));
                                if (!cur.disp.num.machine_code && I8_MIN <= cur.disp.num.i <= I8_MAX)
                                {
                                    cur.ModrM |= 0x40;
                                    cur.disp.U8_count = 1;
                                }
                                else if (aotc->seg_size == 16)
                                {
                                    cur.ModrM |= 0x80;
                                    cur.disp.U8_count = 2;
                                }
                                else
                                {
                                    cur.ModrM |= 0x80;
                                    cur.disp.U8_count = 4;
                                }
                            }
                            else if (!tmpa1->indirect)
                            {
                                cur.has_addr_prefix = FALSE;
                                cur.ModrM |= 0xC0;
                            }
                            else
                            {
                                if (tmpa1->reg1 & 7 == REG_RBP)
                                {
                                    cur.ModrM |= 0x40;
                                    cur.disp.U8_count = 1;
                                }
                            }
                        }
                    }
                }
                else if (ARGT_REL8  <= arg1 <= ARGT_REL32 ||
                         ARGT_IMM8  <= arg1 <= ARGT_IMM64 ||
                         ARGT_UIMM8 <= arg1 <= ARGT_UIMM64)
                {
                    if (arg1 == ARGT_IMM64 || arg2 == ARGT_UIMM64)
                        cur.REX |= 8;
                    MemCopy(&cur.imm.num, &tmpa1->num, sizeof(CAsmNum));
                }
            }
            else if (argcount >= 2)
            {
                if (best.U8_count != 255 && !found_second_possible && !best.is_default)
                {
                    found_second_possible = TRUE;
                    if (!aotc->arg1.size && !aotc->arg2.size)
                        PrintWarn("no size specified at %s,%04d\n",
                                    cc->lex_include_stack->full_name,
                                    cc->lex_include_stack->line_num - 1);
                }
                if (tmpins->flags & IEF_PLUS_OPCODE)
                {
                    if (tmpins->slash_val == SV_R_REG)
                    {
                        if (ARGT_AL <= arg1 <= ARGT_RAX)
                        {
                            cur.last_opcode_U8 |= tmpa2->reg1 & 7;
                            if (tmpa2->reg1 & 15 > 7)
                                cur.REX |= 1;
                            if (tmpa2->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                cur.has_REX = TRUE;
                        }
                        else
                        {
                            cur.last_opcode_U8 |= tmpa1->reg1 & 7;
                            if (tmpa1->reg1 & 15 > 7)
                                cur.REX |= 1;
                            if (tmpa1->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                cur.has_REX = TRUE;
                        }
                    }
                    else
                    {//SV_I_REG
                        if (tmpa1->reg1_type == REGT_FSTACK)
                            cur.last_opcode_U8 |= tmpa1->reg1;
                        if (tmpa2->reg1_type == REGT_FSTACK)
                            cur.last_opcode_U8 |= tmpa2->reg1;
                    }
                }
                if (arg1 == ARGT_RM64 || arg2 == ARGT_RM64 ||
                    arg1 == ARGT_M64  || arg2 == ARGT_M64 ||
                    arg1 == ARGT_R64  || arg2 == ARGT_R64)

                    cur.REX |= 8;
                if (isXMM ||
                    ARGT_RM8 <= arg1 <= ARGT_RM64 ||
                    ARGT_RM8 <= arg2 <= ARGT_RM64 ||
                    ARGT_M8  <= arg1 <= ARGT_M64  ||
                    ARGT_M8  <= arg2 <= ARGT_M64)
                {
                    if (aotc->seg_size == 16)
                        cur.has_addr_prefix = TRUE;
                    cur.has_ModrM = TRUE;
                    if (ARGT_RM8    <= arg2 <= ARGT_RM64 ||
                        ARGT_M8     <= arg2 <= ARGT_M64  ||
                        ARGT_XMM32  <= arg2 <= ARGT_XMM0)
                    {
                        tmpa1 = &aotc->arg2;
                        tmpa2 = &aotc->arg1;
                    }
                    if (tmpins->slash_val == SV_R_REG)
                    {
                        if (tmpa2->just_seg)
                            cur.ModrM |= tmpa2->seg << 3;
                        else
                        {
                            if (tmpa2->reg1 == REG_NONE)
                            {
                                cur.ModrM |= (tmpa1->reg1 & 7) << 3;
                                if (tmpa1->reg1 & 15 > 7)
                                    cur.REX |= 4;
                                if (!isXMM1 && tmpa1->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                    cur.has_REX = TRUE;
                            }
                            else
                            {
                                cur.ModrM |= (tmpa2->reg1 & 7) << 3;
                                if (tmpa2->reg1 & 15 > 7)
                                    cur.REX |= 4;
                                if (!isXMM2 && tmpa2->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                    cur.has_REX = TRUE;
                            }
                        }
                    }
                    if (tmpa1->reg2 == REG_NONE && tmpa1->scale == 1)
                    {
                        if (tmpa1->reg1 != REG_NONE)
                        {
                            cur.ModrM |= tmpa1->reg1 & 7;
                            if (tmpa1->reg1 & 15 > 7)
                                cur.REX |= 1;
                            if (tmpa1->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                cur.has_REX = TRUE;
                        }
                    }
                    else
                    {
                        cur.ModrM |= 4;
                        cur.has_SIB = TRUE;
                        if (tmpa1->scale == 1)
                            cur.SIB = 0;
                        else if (tmpa1->scale == 2)
                            cur.SIB = 0x40;
                        else if (tmpa1->scale == 4)
                            cur.SIB = 0x80;
                        else if (tmpa1->scale == 8)
                            cur.SIB = 0xC0;
                        if (tmpa1->reg2 == REG_NONE)
                        {
                            ModrM_complete = TRUE;
                            cur.SIB |= (tmpa1->reg1 & 7) << 3 + 5;
                            if (tmpa1->reg1 & 15 > 7)
                                cur.REX |= 2;
                            if (tmpa1->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                cur.has_REX = TRUE;
                            MemCopy(&cur.disp.num, &tmpa1->num, sizeof(CAsmNum));
                            cur.disp.U8_count = 4;
                        }
                        else
                        {
                            cur.SIB |= (tmpa1->reg1 & 7) << 3 + tmpa1->reg2 & 7;
                            if (tmpa1->reg1 & 15 > 7)
                                cur.REX |= 2;
                            if (tmpa1->reg1 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                cur.has_REX = TRUE;
                            if (tmpa1->reg2 & 15 > 7)
                                cur.REX |= 1;
                            if (tmpa1->reg2 >= 20) //RBPu8, RSPu8, RSIu8, RDIu8?
                                cur.has_REX = TRUE;
                            if (tmpa1->reg2 & 7 == REG_RBP && !tmpa1->imm_or_off_present && tmpa1->indirect)
                            {
                                cur.ModrM |= 0x40;
                                cur.disp.U8_count = 1;
                                ModrM_complete = TRUE;
                            }
                        }
                    }
                    if (!ModrM_complete)
                    {
                        if (tmpa1->imm_or_off_present && tmpa1->indirect && tmpa1->reg1 == REG_NONE)
                        {
                            cur.ModrM = cur.ModrM & 0xF8 + 5;
                            if (isXMM2)
                                cur.ModrM &= 0xFE;
                            MemCopy(&cur.disp.num, &tmpa1->num, sizeof(CAsmNum));
                            cur.disp.U8_count = 4;
                            if (aotc->seg_size == 64)
                                cur.disp.imm_flag = FALSE;
                        }
                        else
                        {
                            if (tmpa1->imm_or_off_present)
                            {
                                MemCopy(&cur.disp.num, &tmpa1->num, sizeof(CAsmNum));
                                if (!cur.disp.num.machine_code && I8_MIN <= cur.disp.num.i <= I8_MAX)
                                {
                                    cur.ModrM |= 0x40;
                                    cur.disp.U8_count = 1;
                                }
                                else if (aotc->seg_size == 16)
                                {
                                    cur.ModrM |= 0x80;
                                    cur.disp.U8_count = 2;
                                }
                                else
                                {
                                    cur.ModrM |= 0x80;
                                    cur.disp.U8_count = 4;
                                }
                            }
                            else if (!tmpa1->indirect)
                            {
                                cur.has_addr_prefix = FALSE;
                                cur.ModrM |= 0xC0;
                            }
                            else
                            {
                                if (tmpa1->reg1 & 7 == REG_RBP)
                                {
                                    cur.ModrM |= 0x40;
                                    cur.disp.U8_count = 1;
                                }
                            }
                        }
                    }

                    // registers in ModrM U8 are swapped for SSE instructions
                    if (isXMM && tmpa1->reg1 == ARGT_XMM && tmpa2->reg1 == ARGT_XMM)
                        cur.ModrM = cur.ModrM & 0xC0 | (cur.ModrM & 3) << 3 | (cur.ModrM & 3 << 3) >> 3;

                }
                else if (ARGT_MOFFS8 <= arg1 <= ARGT_MOFFS64)
                {
                    MemCopy(&cur.disp.num, &tmpa1->num, sizeof(CAsmNum));
                    if (aotc->seg_size == 16)
                        cur.disp.U8_count = 2;
                    else
                        cur.disp.U8_count = 4;
                    cur.has_addr_prefix = FALSE;
                }
                else if (ARGT_MOFFS8 <= arg2 <= ARGT_MOFFS64)
                {
                    MemCopy(&cur.disp.num, &tmpa2->num, sizeof(CAsmNum));
                    if (aotc->seg_size == 16)
                        cur.disp.U8_count = 2;
                    else
                        cur.disp.U8_count = 4;
                    cur.has_addr_prefix = FALSE;
                }
                else if (ARGT_IMM8  <= arg1 <= ARGT_IMM64 ||
                         ARGT_UIMM8 <= arg1 <= ARGT_UIMM64)
                {
                    MemCopy(&cur.imm.num, &tmpa1->num, sizeof(CAsmNum));
                    if (arg1 == ARGT_IMM8 || arg1 == ARGT_UIMM8)
                        cur.imm.U8_count = 1;
                    else if (arg1 == ARGT_IMM16 || arg1 == ARGT_UIMM16)
                        cur.imm.U8_count = 2;
                    else if (arg1 == ARGT_IMM32 || arg1 == ARGT_UIMM32)
                        cur.imm.U8_count = 4;
                    else
                    {
                        cur.imm.U8_count = 8;
                        cur.REX |= 8;
                    }
                }
                if (ARGT_IMM8  <= arg2 <= ARGT_IMM64 ||
                    ARGT_UIMM8 <= arg2 <= ARGT_UIMM64)
                {
                    MemCopy(&cur.imm.num, &tmpa2->num, sizeof(CAsmNum));
                    if (arg2 == ARGT_IMM8 || arg2 == ARGT_UIMM8)
                        cur.imm.U8_count = 1;
                    else if (arg2 == ARGT_IMM16 || arg2 == ARGT_UIMM16)
                        cur.imm.U8_count = 2;
                    else if (arg2 == ARGT_IMM32 || arg2 == ARGT_UIMM32)
                    {
                        cur.imm.U8_count = 4;
                        if (tmpins->flags & IEF_REX_ONLY_R8_R15 && arg2 == ARGT_UIMM32)
                            cur.REX &= ~8;
                    }
                    else
                    {
                        cur.imm.U8_count = 8;
                        cur.REX |= 8;
                    }
                }
                if (argcount > 2 && (arg3 == ARGT_IMM8 || arg3 == ARGT_UIMM8))
                { // SSE 3 operand RMI encoding
                    MemCopy(&cur.imm.num, &tmpa3->num, sizeof(CAsmNum));
                    if (arg3 == ARGT_IMM8 || arg3 == ARGT_UIMM8)
                        cur.imm.U8_count = 1;
                }
            }
            cur.U8_count = tmpins->opcode_count + cur.disp.U8_count + cur.imm.U8_count;
            if (cur.has_ModrM)
                cur.U8_count++;
            if (cur.has_SIB)
                cur.U8_count++;
            if (aotc->seg_size == 64 && cur.REX & 0x40 == 0x40 && (cur.REX != 0x40 || cur.has_REX) &&
                    (cur.REX & 7 || !(tmpins->flags & IEF_REX_ONLY_R8_R15 ||
                    tmpins->flags & IEF_REX_XOR_LIKE && tmpa1->reg1 == tmpa2->reg1 && cur.ModrM & 0xC0 == 0xC0)))
                cur.U8_count++;
            if (cur.U8_count < best.U8_count && !(tmpins->flags & IEF_DONT_SWITCH_MODES &&
                    (cur.has_addr_prefix || cur.has_operand_prefix)))
                MemCopy(&best, &cur, sizeof(CAsmIns));
        }
    }
    if (best.U8_count < 255)
    {
        tmpins = best.tmpins;
        seg = REG_NONE;
        if (argcount > 1 && aotc->arg2.seg != REG_NONE && !aotc->arg2.just_seg)
            seg = aotc->arg2.seg;
        else if (argcount > 0 && aotc->arg1.seg != REG_NONE && !aotc->arg1.just_seg)
            seg = aotc->arg1.seg;
        if (seg != REG_NONE)
            AOTStoreCodeU8(cc, asm_seg_prefixes[seg]);
        if (best.has_operand_prefix)
            AOTStoreCodeU8(cc, OC_OP_SIZE_PREFIX); //Operand size override
        if (best.has_addr_prefix || aotc->seg_size == 16 && cur.has_SIB)
            AOTStoreCodeU8(cc, OC_ADDR_SIZE_PREFIX); //Operand size override
        if (aotc->seg_size == 64 && best.REX & 0x40 == 0x40 && (best.REX != 0x40 || best.has_REX) &&
                (best.REX & 7 || !(tmpins->flags & IEF_REX_ONLY_R8_R15 ||
                tmpins->flags & IEF_REX_XOR_LIKE && tmpa1->reg1 == tmpa2->reg1 && best.ModrM & 0xC0 == 0xC0)) &&
                !(isXMM && (tmpins->opcode[0] == 0x66 || tmpins->opcode[0] == 0xF3 || tmpins->opcode[0] == 0xF2)))//SSE kludge
            AOTStoreCodeU8(cc, best.REX);
        for (j = 0; j < tmpins->opcode_count - 1; j++)
            AOTStoreCodeU8(cc, tmpins->opcode[j]);
        AOTStoreCodeU8(cc, best.last_opcode_U8);

        if (best.has_ModrM)
            AOTStoreCodeU8(cc, best.ModrM);
        if (best.has_SIB)
            AOTStoreCodeU8(cc, best.SIB);

        if (best.disp.U8_count)
        {
            best.disp.rel = aotc->rip + best.disp.U8_count + best.imm.U8_count;
            if (!AsmStoreNum(cc, &best.disp, 1, U8_avail))
                return FALSE;
        }

        if (best.imm.U8_count)
        {
            best.imm.rel = aotc->rip + best.imm.U8_count;
            if (!AsmStoreNum(cc, &best.imm, 1, U8_avail))
                return FALSE;
        }
        if (tmpins->flags & IEF_ENDING_ZERO) //ENTER instruction
            AOTStoreCodeU8(cc, 0);
        return TRUE;
    }
    LexExcept(cc, "Invalid instruction at ");
}

U0 ParseAsmDefine(CCompCtrl *cc, I64 U8_count)
{
    Bool         is_dup;
    I64          i, dup_val;
    U8          *ptr;
    CAsmNum2     num2;

    num2.U8_count = U8_count;

    while (cc->token && cc->token != ';')
    {
        num2.num.local_asm_undef_hash = NULL;
        num2.num.global_asm_undef_hash = NULL;
        if (cc->token == TK_STR)
        {
            ptr = cc->cur_str;
            i = cc->cur_str_len - 1;
            while (i--)
                AOTStoreCodeU8(cc, *ptr++);
            Lex(cc);    //Skip Str
        }
        else
        {
            is_dup = FALSE;
            cc->abs_counts = 0;
            cc->asm_undef_hash = NULL;
            cc->flags &= ~(CCF_UNRESOLVED + CCF_LOCAL);
            if (!IsLexExpression2Bin(cc, &num2.num.machine_code))
                LexSkipEol(cc);
            else
            {
                if (cc->abs_counts.externs)
                    LexExcept(cc, "Extern Not Allowed at ");
                if (cc->flags & CCF_UNRESOLVED)
                {
                    if (cc->flags & CCF_LOCAL)
                    {
                        num2.num.local_asm_undef_hash = cc->asm_undef_hash;
                        cc->asm_undef_hash = NULL;
                    }
                    else
                    {
                        num2.num.global_asm_undef_hash = cc->asm_undef_hash;
                        cc->asm_undef_hash = NULL;
                    }
                }
                else
                {
                    i = Call(num2.num.machine_code);
                    Free(num2.num.machine_code);
                }
            }
            if (cc->token == TK_IDENT && cc->hash_entry)
            {
                if (cc->hash_entry->type & HTT_ASM_KEYWORD && cc->hash_entry->user_data0 == AKW_DUP)
                {
                    is_dup = TRUE;
                    if (Lex(cc) != '(')
                        LexExcept(cc, "Expecting '(' at ");
                    Lex(cc); //skip (
                    dup_val = AsmLexExpression(cc);
                    if (cc->token != ')')
                        LexExcept(cc, "Expecting ')' at ");
                    Lex(cc); //SKIP )
                }
            }
            num2.rel = 0;
            num2.imm_flag = TRUE;
            num2.num.abs_counts = cc->abs_counts;
            if (is_dup)
            {
                if (num2.num.local_asm_undef_hash || num2.num.global_asm_undef_hash)
                    LexExcept(cc, "Undefined DUP count at ");
                num2.num.i = dup_val;
                AsmStoreNum(cc, &num2, i, FALSE);
            }
            else
            {
                num2.num.i = i;
                AsmStoreNum(cc, &num2, 1, FALSE);
            }
        }
        if (cc->token == ',')
            Lex(cc);
    }
    if (cc->token != ';')
        LexExcept(cc, "Missing ';' at");
    Lex(cc);
}

U0 ParseBinLoad(CCompCtrl *cc)
{
    I64 i, size;
    U8 *buf, *st;

    if (cc->token != TK_STR)
        LexExcept(cc, "Expecting string at ");
    st = ExtDefault(cc->cur_str, "BIN");
    buf = FileRead(st, &size);
    Free(st);
    for (i = 0; i < size; i++)
        AOTStoreCodeU8(cc, buf[i]);
    if (Lex(cc) != ';')
        LexExcept(cc, "Missing ';' at");
    Lex(cc);
}

U0 ParseAsmBlk(CCompCtrl *cc, I64 comp_flags)
{
    CAOTCtrl *aotc = cc->aotc;
    I64 i, j, k, argcount, old_flags = cc->flags & CCF_ASM_EXPRESSIONS;
    CHashOpcode *tmpo;
    CHashExport *tmpex;
    U8 *next_last_label;
    CCodeMisc *g_lb;

    aotc->seg_size = 64;
    cc->flags |= CCF_ASM_EXPRESSIONS;
    if (!(comp_flags & CMPF_ONE_ASM_INS))
    {
        if (cc->token != '{')
            LexExcept(cc, "Expecting '{' at ");
        Lex(cc);
    }
    while (cc->token && cc->token != '}')
    {
        AsmLineList(cc);
        if (cc->token == TK_IDENT && cc->hash_entry)
        {
            if (cc->hash_entry->type & HTT_ASM_KEYWORD)
            {
                i = cc->hash_entry->user_data0;
                Lex(cc); //skip keyword
                switch (i)
                {
                    case AKW_IMPORT:
                        while (cc->token && cc->token != ';')
                        {
                            if (cc->token != TK_IDENT)
                                LexExcept(cc, "Expecting identifier at ");
                            else
                            {
                                tmpex = NULL;
                                tmpex = CAlloc(sizeof(CHashExport));
                                tmpex->str = cc->cur_str;
                                cc->cur_str = 0;
                                tmpex->type = HTT_EXPORT_SYS_SYM | HTF_UNRESOLVED;
                                HashAdd(tmpex, cc->htc.global_hash_table);
                                tmpex->type |= HTF_IMPORT;
                                if (Lex(cc) == ',')
                                    Lex(cc); //skip ','
                            }
                        }
                        if (cc->token != ';')
                            LexExcept(cc, "Missing ';' at");
                        Lex(cc); //skip ';';
                        break;

                    case AKW_ORG:
                        if (cc->htc.local_var_list)
                            LexExcept(cc, "ORG not allowed in function asm block ");
                        if (aotc->org != INVALID_PTR)
                            LexExcept(cc, "Just one org allowed ");
                        if (aotc->rip)
                            LexExcept(cc, "ORG must be at beginning ");
                        aotc->org = AsmLexExpression(cc);
                        break;

                    case AKW_ALIGN:
                        if (cc->htc.local_var_list)
                            LexExcept(cc, "ALIGN not allowed in function asm block ");
                        i = AsmLexExpression(cc);
                        j = Bsf(i);
                        if (!i || j != Bsr(i))
                            LexExcept(cc, "ALIGN must be power of two at ");
                        if (!(cc->flags & CCF_AOT_COMPILE) && i > 8)
                            LexExcept(cc, "In JIT mode, max ALIGN is 8 ");
                        if (j > aotc->max_align_bits)
                            aotc->max_align_bits = j;
                        i = CeilU64(aotc->rip, i);
                        if (cc->token != ',')
                            LexExcept(cc, "Expecting ',' at ");
                        Lex(cc);
                        k = AsmLexExpression(cc);
                        for (j = aotc->rip; j < i; j++)
                            AOTStoreCodeU8(cc, k);
                        break;

                    case AKW_DU8:
                        ParseAsmDefine(cc, 1);
                        break;

                    case AKW_DU16:
                        ParseAsmDefine(cc, 2);
                        break;

                    case AKW_DU32:
                        ParseAsmDefine(cc, 4);
                        break;

                    case AKW_DU64:
                        ParseAsmDefine(cc, 8);
                        break;

                    case AKW_BINLOAD:
                        ParseBinLoad(cc);
                        break;

                    case AKW_LIST:
                        aotc->list = TRUE;
                        break;

                    case AKW_NOLIST:
                        aotc->list = FALSE;
                        break;

                    case AKW_USE16:
                        aotc->seg_size = 16;
                        break;

                    case AKW_USE32:
                        aotc->seg_size = 32;
                        break;

                    case AKW_USE64:
                        aotc->seg_size = 64;
                        break;

                    default:
                        LexExcept(cc, "Syntax error at ");
                }
            }
            else if (cc->hash_entry->type & HTT_OPCODE)
            {
                tmpo = cc->hash_entry;
                Lex(cc); //skip opcode
                argcount = 0;
                if (tmpo->ins[0].arg1)
                {
                    argcount++;
                    if (ARGT_REL8 <= tmpo->ins[0].arg1 <= ARGT_REL32)
                        ParseAsmArg(cc, &aotc->arg1, TRUE);
                    else
                        ParseAsmArg(cc, &aotc->arg1, FALSE);
                    if (tmpo->ins[0].arg2)
                    {
                        argcount++;
                        if (cc->token != ',')
                            LexExcept(cc, "Expecting ',' at ");
                        else
                        {
                            Lex(cc); //skip ','
                            if (ARGT_REL8 <= tmpo->ins[0].arg2 <= ARGT_REL32)
                                ParseAsmArg(cc, &aotc->arg2, TRUE);
                            else
                                ParseAsmArg(cc, &aotc->arg2, FALSE);

                            if (tmpo->ins[0].arg3)
                            {
                                argcount++;
                                if (cc->token != ',')
                                    LexExcept(cc, "Expecting ',' at ");
                                else
                                {
                                    Lex(cc); //skip ','
                                    if (ARGT_REL8 <= tmpo->ins[0].arg3 <= ARGT_REL32)
                                        ParseAsmArg(cc, &aotc->arg3, TRUE);
                                    else
                                        ParseAsmArg(cc, &aotc->arg3, FALSE);
                                }
                            }


                        }
                    }
                }
                ParseAsmInst(cc, tmpo, argcount);
            }
            else if (cc->hash_entry->type & HTT_EXPORT_SYS_SYM)
            {
                if (Btr(&cc->hash_entry->type, HTf_UNRESOLVED))
                {
                    if (cc->hash_entry->type & HTF_LOCAL)
                    {
                        cc->hash_entry(CHashExport *)->val = aotc->rip;
                        if (Lex(cc) != ':')
                            LexExcept(cc, "Expecting ':' at ");
                        Lex(cc);
                    }
                    else
                    {
                        if (cc->hash_entry->type & HTF_IMPORT)
                            LexExcept(cc, "attempt to define import at ");
                        cc->hash_entry(CHashExport *)->val = aotc->rip;
                        next_last_label = cc->hash_entry->str;
                        Lex(cc); //Skip cur_str
                        if (cc->token != ':' && cc->token != TK_DBL_COLON)
                            LexExcept(cc, "Expecting ':' at ");
                        if (cc->token == TK_DBL_COLON)
                        {
                            cc->hash_entry->type |= HTF_EXPORT;
                            HashSrcFileSet(cc, cc->hash_entry);

                            AOTLocalsResolve(cc);
                            aotc->last_label = next_last_label;
                        }
                        Lex(cc);
                    }
                }
                else if (cc->hash_entry(CHashExport *)->val == aotc->rip)
                {
                    Lex(cc); //Skip cur_str
                    if (cc->token != ':' && cc->token != TK_DBL_COLON)
                        LexExcept(cc, "Expecting ':' at ");
                    Lex(cc);
                }
                else
                    LexExcept(cc, "Redefinition at ");
            }
            else
                LexExcept(cc, "Syntax error at ");
        }
        else if (cc->token == TK_IDENT)
        {
            tmpex = CAlloc(sizeof(CHashExport));
            tmpex->str = cc->cur_str;
            cc->cur_str = 0;
            tmpex->type = HTT_EXPORT_SYS_SYM;
            tmpex->val = aotc->rip;
            Lex(cc);    //Skip cur_str
            if (cc->token != ':' && cc->token != TK_DBL_COLON)
                LexExcept(cc, "Expecting ':' at ");
            else
            {
                if (*tmpex->str == '@' && tmpex->str[1] == '@')
                {
                    if (cc->token == TK_DBL_COLON)
                        LexExcept(cc, "No local global exports at ");
                    HashAdd(tmpex, cc->htc.local_hash_table);
                }
                else
                    HashAdd(tmpex,cc->htc.global_hash_table);
                if (cc->htc.local_var_list)
                {//AsmBlk in function? Also add goto-like label.
                    if (!(g_lb = COCGoToLabelFind(cc, tmpex->str)))
                    {
                        g_lb = COCMiscNew(cc, CMT_ASM_LABEL);
                        g_lb->str = StrNew(tmpex->str);
                    }
                    else if (g_lb->flags & CMF_DEFINED)
                        LexExcept(cc, "Duplicate goto label at ");
                    g_lb->type = CMT_ASM_LABEL;
                    g_lb->flags |= CMF_DEFINED;
                    g_lb->rip = aotc->rip;
                    g_lb->use_count++; //Disable warning on unused labels.
                    ICAdd(cc, IC_LABEL, g_lb, 0);
                }
                if (cc->token == TK_DBL_COLON)
                {
                    tmpex->type |= HTF_EXPORT;
                    HashSrcFileSet(cc, tmpex);

                    AOTLocalsResolve(cc);
                    aotc->last_label = tmpex->str;
                }
                Lex(cc);
            }
        }
        else if (cc->token == ';')
            Lex(cc);
        else
            LexExcept(cc, "Syntax error at ");
        if (comp_flags & CMPF_ONE_ASM_INS && (cc->token != TK_IDENT || !(tmpo=cc->hash_entry) ||
                !(tmpo->type & (HTT_OPCODE | HTT_ASM_KEYWORD))))
            break;
    }
    AOTLocalsResolve(cc);
    aotc->list = FALSE;
    cc->flags &= cc->flags & ~CCF_ASM_EXPRESSIONS | old_flags;
}