CHashClass *ParseClass(CCompCtrl *cc, I64 keyword, I64 fsp_flags, Bool is_extern)
{
    CHashClass *tmpc, *base_class;

    if (cc->token != TK_IDENT)
        LexExcept(cc, "Expecting identifier at ");
    if (is_extern)
    {
        tmpc = ParseClassNew;
        tmpc->str = cc->cur_str;
        cc->cur_str = NULL;
        HashAdd(tmpc, cc->htc.global_hash_table);
        LBts(&tmpc->flags, Cf_EXTERN);
        HashSrcFileSet(cc, tmpc);
        Lex(cc);
    }
    else
    {
        if (cc->flags & CCF_AOT_COMPILE)
            tmpc = HashFind(cc->cur_str, cc->htc.global_hash_table, HTT_CLASS);
        else
            tmpc = HashSingleTableFind(cc->cur_str, cc->htc.global_hash_table, HTT_CLASS);
        if (tmpc)
        {
            if (!Bt(&tmpc->flags, Cf_EXTERN))
                tmpc = NULL;
            else if (tmpc->use_count < 3)
                UnusedExternWarning(cc, tmpc);
        }
        if (tmpc)
        {
            Free(tmpc->src_link);
            tmpc->src_link = NULL;
            Free(tmpc->idx);
            tmpc->idx = NULL;
        }
        else
        {
            tmpc = ParseClassNew;
            tmpc->str = cc->cur_str;
            cc->cur_str = NULL;
            HashAdd(tmpc, cc->htc.global_hash_table);
        }
        LBtr(&tmpc->flags, Cf_EXTERN);
        if (fsp_flags & FSF_PUBLIC)
            tmpc->type |= HTF_PUBLIC;
        tmpc->use_count = 0;
        if (cc->last_U16 == '\n')
            HashSrcFileSet(cc, tmpc, -1);
        else
            HashSrcFileSet(cc, tmpc,0);
        if (Lex(cc) == ':')
        {
            if (Lex(cc) != TK_IDENT || !(base_class = cc->hash_entry) || !(base_class->type & HTT_CLASS))
                LexExcept(cc, "Invalid class at ");
            if (Lex(cc) == ',')
                LexExcept(cc, "Only one base class allowed at this time at ");
            tmpc->base_class = base_class;
            tmpc->size += base_class->size;
        }
        if (keyword == KW_UNION)
            ParseVarList(cc, tmpc, PRS0_NULL | PRS1_CLASS | PRSF_UNION);
        else
            ParseVarList(cc, tmpc, PRS0_NULL | PRS1_CLASS);
        tmpc->size += tmpc->neg_offset;
    }
    return tmpc;
}

CHashFun *ParseFunJoin(CCompCtrl *cc, CHashClass *tmp_return, U8 *name, I64 fsp_flags)
{
    CMemberList *tmpm, *header_list;
    CAOTCtrl    *aotc = cc->aotc;
    CHashClass  *header_return;
    CHashFun    *tmpf;
    I64          header_arg_count;

    if (name)
    {//if not fun_ptr
        if (cc->flags & CCF_AOT_COMPILE)
        {
            if ((tmpf = HashFind(name, cc->htc.global_hash_table, HTT_FUN)) && tmpf->type & HTF_IMPORT)
                tmpf=NULL;
        }
        else
            if ((tmpf = HashSingleTableFind(name, cc->htc.global_hash_table, HTT_FUN)) && !Bt(&tmpf->flags, Cf_EXTERN))
                tmpf = NULL;
        if (tmpf && tmpf->use_count < 3)
            UnusedExternWarning(cc, tmpf);
    }
    else
        tmpf = NULL;
    if (tmpf)
    {
        tmpf->used_reg_mask = REGG_CLOBBERED + REGG_SAVED + REGG_STACK_TMP;
        Free(tmpf->src_link);
        tmpf->src_link = NULL;
        Free(tmpf->idx);
        tmpf->idx = NULL;
        Free(name);
        header_arg_count = tmpf->arg_count;
        header_list = tmpf->member_list_and_root;
        header_return = tmpf->return_class;
        tmpf->member_list_and_root = NULL;
        ClassMemberListDel(tmpf);
    }
    else
    {
        tmpf = ParseFunNew;
        header_return = NULL;
        tmpf->used_reg_mask = REGG_CLOBBERED + REGG_SAVED + REGG_STACK_TMP;
        tmpf->clobbered_reg_mask = REGG_CLOBBERED + REGG_STACK_TMP;
        tmpf->str = name;
        if (cc->flags & CCF_AOT_COMPILE)
            tmpf->exe_addr = aotc->rip;
        else
            tmpf->exe_addr = &UndefinedExtern;
        LBts(&tmpf->flags, Cf_EXTERN);
        tmpf->flags |= fsp_flags & FSG_FUN_FLAGS1;
        if (name) //if not fun_ptr
            HashAdd(tmpf, cc->htc.global_hash_table);
    }
    BEqual(&tmpf->type, HTf_PUBLIC, fsp_flags & FSF_PUBLIC);
    tmpf->return_class = tmp_return;
    tmpf->use_count = 0;
    HashSrcFileSet(cc, tmpf);
    ParseVarList(cc, tmpf, PRS0_NULL | PRS1_FUN_ARG);
    tmpf->arg_count = tmpf->member_count;
    if (0 < tmpf->arg_count << 3 <= I16_MAX && !Bt(&tmpf->flags, Ff_DOT_DOT_DOT))
        LBts(&tmpf->flags, Ff_RET1);
    tmpm = tmpf->member_list_and_root;
    while (tmpm)
    {
        tmpm->offset += 16; //RBP+RETURN
        tmpm = tmpm->next;
    }
    tmpf->size = 0;
    if (header_return)
    {
        if (OptionGet(OPTf_WARN_HEADER_MISMATCH))
        {
            if (tmpf->return_class != header_return)
            {
                PrintWarn("Fun Header return mismatch '%s'\n", tmpf->str);
                cc->warning_count++;
            }
            if (!MemberListCmp(tmpf->member_list_and_root, header_list, header_arg_count))
            {
                PrintWarn("Fun header args mismatch '%s'\n", tmpf->str);
                cc->warning_count++;
            }
        }
        MemberListDel(header_list);
    }

    return tmpf;
}

U0 ParseFun(CCompCtrl *cc, CHashClass *tmp_return, U8 *name, I64 fsp_flags)
{
    CMemberList *tmpm;
    CCodeMisc   *saved_leave_label;
    I64          i, j, size, *r;
    Bool         old_trace;

    cc->fun_lex_file = cc->lex_include_stack;
    cc->min_line=cc->max_line = cc->lex_include_stack->line_num;

    cc->flags &= ~CCF_NO_REG_OPT;
    cc->htc.local_var_list = cc->htc.fun = ParseFunJoin(cc, tmp_return, name, fsp_flags);

    COCPush(cc);
    Btr(&cc->flags, CCf_PASS_TRACE_PRESENT);
    COCInit(cc);
    ICAdd(cc, IC_ENTER, 0, 0);
    saved_leave_label = cc->lb_leave;
    cc->lb_leave = COCMiscNew(cc,CMT_LABEL);
    cc->flags &= ~CCF_HAS_RETURN;
    ParseStatement(cc,,, 0);

    if (cc->max_line < cc->min_line)
        cc->max_line = cc->min_line;

    if (cc->htc.fun->return_class->size && !(cc->flags & CCF_HAS_RETURN))
        LexWarn(cc, "Function should return val ");
    ICAdd(cc, IC_LABEL, cc->lb_leave, 0);
    cc->lb_leave = saved_leave_label;
    ICAdd(cc, IC_LEAVE, 0, cc->htc.fun->return_class);
    cc->htc.fun->size &= ~7;
    if (cc->flags & CCF_AOT_COMPILE)
    {
        cc->htc.fun->exe_addr = cc->aotc->rip;
        cc->htc.fun->type |= HTF_EXPORT | HTF_RESOLVE;
        r = COCCompile(cc, &size, &cc->htc.fun->debug_info, NULL);
        if (r)
        {
            j = (size + 7) >> 3;
            for (i = 0; i < j; i++)
                AOTStoreCodeU64(cc, r[i]);
            Free(r);
        }
    }
    else
    {
        old_trace = Btr(&cc->opts, OPTf_TRACE);
        cc->htc.fun->exe_addr = COCCompile(cc, &size, &cc->htc.fun->debug_info, NULL);
        if (old_trace)
        {
            Bts(&cc->opts, OPTf_TRACE);
            Un(cc->htc.fun->exe_addr, size, 64);
        }
        SysSymImportsResolve(cc->htc.fun->str);
    }
    LBtr(&cc->htc.fun->flags, Cf_EXTERN);
    COCPop(cc);
    tmpm = cc->htc.fun->member_list_and_root;
    while (tmpm)
    {
        if (tmpm->flags & MLF_NO_UNUSED_WARN)
        {
            if (tmpm->use_count > 1 && StrCompare(tmpm->str, "_anon_"))
                PrintWarn("Unneeded no_warn\n $LK,\"FL:%s,%d\"$ '%s' in '%s'\n",
                            cc->lex_include_stack->full_name, cc->lex_include_stack->line_num, tmpm->str, cc->htc.fun->str);
        }
        else if (!tmpm->use_count && OptionGet(OPTf_WARN_UNUSED_VAR))
            PrintWarn("Unused var\n $LK,\"FL:%s,%d\"$ '%s' in '%s'\n",
                        cc->lex_include_stack->full_name, cc->lex_include_stack->line_num, tmpm->str, cc->htc.fun->str);
        tmpm = tmpm->next;
    }
    cc->htc.local_var_list = cc->htc.fun=cc->fun_lex_file = NULL;
}

U0 ParseGlobalVarList(CCompCtrl *cc, I64 saved_mode, CHashClass *saved_tmpc, I64 saved_val, I64 fsp_flags)
{
    I64              i, j, mode, k, val;
    U8              *st;
    CHashExport     *tmpex;
    CHashGlobalVar  *tmpg;
    CAOTCtrl        *aotc = cc->aotc;
    CAOTHeapGlobal  *tmphg;
    CHashClass      *tmpc;
    CHashFun        *tmpf, *tmpf_fun_ptr;
    CArrayDim        tmpad;
    Bool             has_alias, undef_array_size, is_array;

    while (TRUE)
    {
        tmpc = ParseType(cc, &saved_tmpc, &saved_mode, NULL, &st, &tmpf_fun_ptr, &tmpex, &tmpad, fsp_flags);

        if (!st)
            return;
        if (tmpad.next)
            is_array = TRUE;
        else if (tmpad.total_count < 0)
        {
            is_array = TRUE;
            tmpc--;
        }
        else
            is_array = FALSE;

        val = saved_val;
        mode = saved_mode;
        if (tmpex && mode & 255 == PRS0_EXTERN && !(cc->flags & CCF_AOT_COMPILE) && tmpex->type & HTT_EXPORT_SYS_SYM)
        {
            val = tmpex->val;
            mode = PRS0__EXTERN | PRS1_NOT_REALLY__EXTERN;
        }
        if (cc->token == '(')
        {
            switch (mode & 255)
            {
                case PRS0__INTERN:
                    tmpf = ParseFunJoin(cc, tmpc, st, fsp_flags);
                    tmpf->exe_addr = val;
                    Bts(&tmpf->flags, Ff_INTERNAL);
                    LBtr(&tmpf->flags, Cf_EXTERN);
                    return;

                case PRS0__EXTERN:
                    if (!(fsp_flags & FSF__) && !(mode & PRS1_NOT_REALLY__EXTERN))
                        LexExcept(cc, "Expecting label with underscore at ");
                    tmpf = ParseFunJoin(cc, tmpc, st, fsp_flags);
                    tmpf->exe_addr = val;
                    SysSymImportsResolve(tmpf->str);
                    LBtr(&tmpf->flags, Cf_EXTERN);
                    if (saved_mode & 255 == PRS0__EXTERN)
                        LBts(&tmpf->flags, Ff__EXTERN);
                    if (cc->flags & CCF_AOT_COMPILE)
                        tmpf->type |= HTF_RESOLVE;
                    return;

                case PRS0_EXTERN:
                    ParseFunJoin(cc, tmpc, st, fsp_flags);
                    return;

                case PRS0__IMPORT:
                    if (!(fsp_flags & FSF__))
                        LexExcept(cc, "Expecting label with underscore at ");

                case PRS0_IMPORT:
                    if (!(cc->flags & CCF_AOT_COMPILE))
                        LexExcept(cc, "import not needed at ");
                    else
                    {
                        tmpf = ParseFunJoin(cc, tmpc, st, fsp_flags);
                        tmpf->type |= HTF_IMPORT;
                        if (mode & 255 == PRS0__IMPORT)
                            tmpf->import_name = StrNew(val);
                        else
                            tmpf->import_name = StrNew(st);
                    }
                    return;

                default:
                    ParseFun(cc, tmpc, st, fsp_flags);
                    return;
            }
        }
        else
        {
            if (tmpad.total_count < 0)
            {
                i = 0;
                undef_array_size = TRUE;
            }
            else
            {
                i = tmpad.total_count;
                undef_array_size = FALSE;
            }
            if (tmpf_fun_ptr)
                j = sizeof(U8 *);
            else
                j = tmpc->size;
            j *= i;
            has_alias = FALSE;
            tmphg = NULL;
            switch (mode & 255)
            {
                case PRS0__EXTERN:
                    if (cc->flags & CCF_AOT_COMPILE)
                    {
                        tmpg = CAlloc(sizeof(CHashGlobalVar));
                        tmpg->data_addr_rip = val;
                        tmpg->type = HTT_GLOBAL_VAR | HTF_EXPORT;
                    }
                    else
                    {
                        tmpg = CAlloc(sizeof(CHashGlobalVar), Fs->code_heap);
                        tmpg->data_addr = val;
                        tmpg->type = HTT_GLOBAL_VAR;
                    }
                    tmpg->flags |= GVF_ALIAS;
                    break;

                case PRS0__IMPORT:
                case PRS0_IMPORT:
                    if (!(cc->flags & CCF_AOT_COMPILE))
                        LexExcept(cc, "import not needed at ");
                    else
                    {
                        tmpg = CAlloc(sizeof(CHashGlobalVar));
                        tmpg->type = HTT_GLOBAL_VAR | HTF_IMPORT;
                        if (mode & 255 == PRS0__IMPORT)
                            tmpg->import_name = StrNew(val);
                        else
                            tmpg->import_name = StrNew(st);
                    }
                    break;

                case PRS0_EXTERN:
                    if (cc->flags & CCF_AOT_COMPILE)
                    {
                        tmpg = CAlloc(sizeof(CHashGlobalVar));
                        tmpg->type = HTT_GLOBAL_VAR;
                    }
                    else
                    {
                        tmpg = CAlloc(sizeof(CHashGlobalVar), Fs->code_heap);
                        tmpg->type = HTT_GLOBAL_VAR | HTF_UNRESOLVED;
                    }
                    break;

                default:
                    if (cc->flags & CCF_AOT_COMPILE)
                    {
                        if (Bt(&cc->opts, OPTf_GLOBALS_ON_DATA_HEAP)) {
                            if (cc->token == '=')
                                LexExcept(cc, "Can't init global var on data heap in AOT module ");
                            tmpg = CAlloc(sizeof(CHashGlobalVar));
                            tmphg = tmpg->heap_global=CAlloc(sizeof(CAOTHeapGlobal));
                            tmphg->size = j;
                            tmphg->str = StrNew(st);
                            tmphg->next = aotc->heap_globals;
                            aotc->heap_globals = tmphg;
                            tmpg->flags = GVF_DATA_HEAP;
                            tmpg->type = HTT_GLOBAL_VAR; //TODO: HTF_EXPORT
                            if (tmpex && tmpex->type & HTT_GLOBAL_VAR) //TODO!! extern
                                LexExcept(cc, "Feature not implemented ");
                        }
                        else
                        {
                            tmpg = CAlloc(sizeof(CHashGlobalVar));
                            if (cc->token == '=')
                                tmpg->data_addr = CAlloc(j);
                            if (tmpc->size >= 8) //align
                                while (aotc->rip & 7)
                                    AOTStoreCodeU8(cc, 0);
                            else if (tmpc->size == 4)
                                while (aotc->rip & 3)
                                    AOTStoreCodeU8(cc, 0);
                            else if (tmpc->size == 2)
                                while (aotc->rip & 1)
                                    AOTStoreCodeU8(cc, 0);
                            tmpg->data_addr_rip = aotc->rip;
                            tmpg->type = HTT_GLOBAL_VAR | HTF_EXPORT;
                            if (tmpex && tmpex->type & HTT_GLOBAL_VAR)
                                has_alias = TRUE;
                            for (k = 0; k < j; k++)
                                AOTStoreCodeU8(cc, 0); //Init AOT global to zero.
                        }
                    }
                    else
                    {
                        if (Bt(&cc->opts, OPTf_GLOBALS_ON_DATA_HEAP))
                        {
                            tmpg = CAlloc(sizeof(CHashGlobalVar), Fs->code_heap);
                            tmpg->data_addr = MAlloc(j);
                            tmpg->flags = GVF_DATA_HEAP;
                        }
                        else
                        {
                            tmpg = CAlloc(sizeof(CHashGlobalVar), Fs->code_heap);
                            tmpg->data_addr = MAlloc(j, Fs->code_heap);
                        }
                        tmpg->type = HTT_GLOBAL_VAR;
                        if (tmpex && tmpex->type & HTT_GLOBAL_VAR && tmpex->type & HTF_UNRESOLVED &&
                                MHeapCtrl(tmpex) == MHeapCtrl(tmpg))
                            has_alias = TRUE;
                        if (sys_var_init_flag)
                            MemSet(tmpg->data_addr, sys_var_init_val, j);
                    }
            }
            tmpg->dim.next = tmpad.next;
            if (fsp_flags & FSF_PUBLIC)
                tmpg->type |= HTF_PUBLIC;
            tmpg->var_class = tmpc;
            tmpg->str = st;
            tmpg->size = j;
            tmpg->dim.total_count = i;
            tmpg->use_count = 0;
            if (cc->last_U16 == '\n')
                HashSrcFileSet(cc, tmpg, -1);
            else
                HashSrcFileSet(cc, tmpg, 0);
            if (mode & 255 == PRS0_IMPORT || mode & 255 == PRS0__IMPORT)
                tmpg->flags |= GVF_IMPORT;
            if (mode & 255 == PRS0_EXTERN)
                tmpg->flags |= GVF_EXTERN;
            if (tmpf_fun_ptr)
            {
                tmpg->fun_ptr = tmpf_fun_ptr;
                tmpg->flags |= GVF_FUN;
            }
            if (is_array)
                tmpg->flags |= GVF_ARRAY;
            HashAdd(tmpg, cc->htc.global_hash_table);
            if (!(cc->flags & CCF_AOT_COMPILE) && !(tmpg->flags & GVF_EXTERN))
                SysSymImportsResolve(tmpg->str);
            if (cc->token == '=')
            {
                if (undef_array_size)
                {
                    LexPush(cc);
                    LexPush(cc);
                    Lex(cc);
                    ParseGlobalInit(cc, tmpg, 1);
                    LexPopNoRestore(cc);
                    tmpg->size = tmpg->dim.total_count * tmpc->size;
                    if (tmphg)
                        tmphg->size = tmpg->size;
                    if (cc->flags & CCF_AOT_COMPILE)
                        for (k = 0; k < tmpg->size; k++)
                            AOTStoreCodeU8(cc, 0);
                    else
                        if (sys_var_init_flag)
                            MemSet(tmpg->data_addr, sys_var_init_val, k);
                    LexPopRestore(cc);
                }
                LexPush(cc);
                Lex(cc);
                ParseGlobalInit(cc, tmpg, 2);
                if (cc->flags & CCF_AOT_COMPILE)
                    for (k = 0; k < tmpg->size; k++)
                        AOTStoreCodeU8At(cc, tmpg->data_addr_rip + k, tmpg->data_addr[k]);
                LexPopNoRestore(cc);
            }
            if (has_alias)
            {
                if (tmpex(CHashGlobalVar *)->use_count < 2)
                {
                    PrintWarn("Unused extern '%s'\n", tmpex(CHashGlobalVar *)->str);
                    cc->warning_count++;
                }
                tmpex(CHashGlobalVar *)->flags |= GVF_ALIAS;
                tmpex(CHashGlobalVar *)->data_addr = tmpg->data_addr;
                tmpex(CHashGlobalVar *)->data_addr_rip = tmpg->data_addr_rip;
            }
            if (cc->token == ',')
                Lex(cc);
            else
            {
                if (cc->token != ';')
                    LexExcept(cc, "Missing ';' at");
                Lex(cc);
                return;
            }
        }
    }
}

U0 ParseIf(CCompCtrl *cc, I64 try_count, CCodeMisc *lb_break)
{
    CCodeMisc   *lb, *lb1;
    I64          k;

    if (cc->token != '(')
        LexExcept(cc, "Expecting '(' at ");
    Lex(cc);
    if (!ParseExpression(cc, NULL, FALSE))
        throw('Compiler');
    if (cc->token != ')')
        LexExcept(cc, "Missing ')' at ");
    Lex(cc);
    lb = COCMiscNew(cc, CMT_LABEL);
    ICAdd(cc, IC_BR_ZERO, lb, 0);
    ParseStatement(cc, try_count, lb_break);
    k = ParseKeyWord(cc);
    if (k == KW_ELSE)
    {
        Lex(cc);
        lb1 = COCMiscNew(cc, CMT_LABEL);
        ICAdd(cc, IC_JMP, lb1, 0);
        ICAdd(cc, IC_LABEL, lb, 0);
        ParseStatement(cc, try_count, lb_break);
        ICAdd(cc, IC_LABEL, lb1, 0);
    }
    else
        ICAdd(cc, IC_LABEL, lb, 0);
}

U0 ParseWhile(CCompCtrl *cc, I64 try_count)
{
    CCodeMisc *lb, *lb_done;

    if (cc->token != '(')
        LexExcept(cc, "Expecting '(' at ");
    Lex(cc);
    lb = COCMiscNew(cc, CMT_LABEL);
    ICAdd(cc, IC_LABEL, lb, 0);
    if (!ParseExpression(cc, NULL,FALSE))
        throw('Compiler');
    if (cc->token != ')')
        LexExcept(cc, "Missing ')' at ");
    Lex(cc);
    lb_done = COCMiscNew(cc, CMT_LABEL);
    ICAdd(cc, IC_BR_ZERO, lb_done, 0);
    ParseStatement(cc, try_count, lb_done);
    ICAdd(cc, IC_JMP, lb, 0);
    ICAdd(cc, IC_LABEL, lb_done, 0);
}

U0 ParseDoWhile(CCompCtrl *cc, I64 try_count)
{
    CCodeMisc *lb, *lb_done;

    lb = COCMiscNew(cc, CMT_LABEL);
    lb_done = COCMiscNew(cc, CMT_LABEL);
    ICAdd(cc, IC_LABEL, lb, 0);
    ParseStatement(cc, try_count, lb_done);
    if (ParseKeyWord(cc) != KW_WHILE)
        LexExcept(cc, "Missing 'while' at");
    if (Lex(cc) != '(')
        LexExcept(cc, "Expecting '(' at ");
    Lex(cc);
    if (!ParseExpression(cc, NULL, FALSE))
        throw('Compiler');
    if (cc->token != ')')
        LexExcept(cc, "Missing ')' at ");
    ICAdd(cc, IC_BR_NOT_ZERO, lb, 0);
    ICAdd(cc, IC_LABEL, lb_done, 0);
    if (Lex(cc) != ';')
        LexExcept(cc, "Missing ';' at");
    Lex(cc);
}

U0 ParseFor(CCompCtrl *cc, I64 try_count)
{
    CCodeCtrl *tmpcbh;
    CCodeMisc *lb, *lb_done;

    if (cc->token != '(')
        LexExcept(cc, "Expecting '(' at ");
    Lex(cc);
    ParseStatement(cc, try_count);

    lb = COCMiscNew(cc, CMT_LABEL);
    ICAdd(cc, IC_LABEL, lb, 0);
    if (!ParseExpression(cc, NULL, FALSE))
        throw('Compiler');
    lb_done = COCMiscNew(cc, CMT_LABEL);
    ICAdd(cc, IC_BR_ZERO, lb_done, 0);
    if (cc->token != ';')
        LexExcept(cc, "Missing ';' at");
    Lex(cc);

    COCPush(cc);
    COCInit(cc);
    if (cc->token != ')')
        ParseStatement(cc, try_count, NULL, 0);
    COCPush(cc);
    tmpcbh = COCPopNoFree(cc);
    COCPop(cc);
    if (cc->token != ')')
        LexExcept(cc, "Missing ')' at ");
    Lex(cc);

    ParseStatement(cc, try_count, lb_done);
    COCAppend(cc, tmpcbh);
    ICAdd(cc, IC_JMP, lb, 0);
    ICAdd(cc, IC_LABEL, lb_done, 0);
}

class CSubSwitch
{
    CSubSwitch *next, *last;
    CCodeMisc  *lb_start, *lb_break;
};

class CSwitchCase
{
    CSwitchCase *next;
    CCodeMisc   *label;
    I64          val;
    CSubSwitch  *ss;
};

U0 ParseSwitch(CCompCtrl *cc, I64 try_count)
{
    CSwitchCase         *header = NULL, *tmps, *tmps1;  //Leaks on except
    CSubSwitch           head, *tmpss;                  //Leaks on except
    CCodeMisc           *lb_default, *lb_fwd_case, *mc_jt, *lb_entry, **jmp_table;
    CIntermediateCode   *tmpi_sub, *tmpi_cmp, *tmpi_jmp, *tmpi_start;
    Bool                 default_found = FALSE, nobound;
    I64                  i, k_start = I64_MIN, k_end, lo = I64_MAX, hi = I64_MIN, range;

    if (cc->token == '(')
        nobound = FALSE;
    else if (cc->token == '[')
        nobound = TRUE;
    else
        LexExcept(cc, "Expecting '(' or '[' at ");
    Lex(cc);
    QueueInit(&head);

    head.last->lb_break = COCMiscNew(cc, CMT_LABEL);
    head.last->lb_break->use_count++;
    lb_default = COCMiscNew(cc, CMT_LABEL);
    lb_default->use_count++;
    mc_jt = COCMiscNew(cc, CMT_JMP_TABLE);
    mc_jt->begin = COCMiscNew(cc, CMT_LABEL);
    mc_jt->begin->use_count++;
    if (!ParseExpression(cc, NULL, FALSE))
        throw('Compiler');
    tmpi_sub = ICAdd(cc, IC_IMM_I64, 0, cmp.internal_types[RT_I64]);
    ICAdd(cc, IC_SUB, 0, cmp.internal_types[RT_I64]);
    tmpi_cmp = ICAdd(cc, IC_IMM_I64, 0, cmp.internal_types[RT_I64]);
    if (nobound)
    {
        ICAdd(cc, IC_NOBOUND_SWITCH, mc_jt, 0);
        if (cc->token != ']')
            LexExcept(cc, "Missing ']' at ");
    }
    else
    {
        ICAdd(cc, IC_SWITCH, mc_jt, 0);
        if (cc->token != ')')
            LexExcept(cc, "Missing ')' at ");
    }
    if (Lex(cc) != '{')
        LexExcept(cc, "Expecting '{' at ");
    Lex(cc);
    ICAdd(cc, IC_LABEL, mc_jt->begin, 0);
    while (TRUE)
    {
        while (cc->token && cc->token != '}')
        {
sw_cont:
            switch (ParseKeyWord(cc))
            {
                case KW_END:
                    goto sw_sub_end;

                case KW_START:
                    if (Lex(cc) == ':')
                        Lex(cc);
                    else
                        LexExcept(cc, "Expecting ':' at ");
                    tmpss = MAlloc(sizeof(CSubSwitch));
                    QueueInsert(tmpss, head.last);
                    head.last->lb_break = COCMiscNew(cc, CMT_LABEL);
                    head.last->lb_break->use_count++;
                    lb_fwd_case = COCMiscNew(cc, CMT_LABEL);
                    tmpi_jmp = ICAdd(cc, IC_JMP, lb_fwd_case, 0);

                    tmpss->lb_start = COCMiscNew(cc, CMT_LABEL);
                    tmpi_start = ICAdd(cc, IC_LABEL, tmpss->lb_start, 0);
                    while (cc->token && cc->token != '}')
                    {
                        switch (ParseKeyWord(cc))
                        {
                            case KW_END:
                                OptFree(tmpi_jmp);
                                goto sw_sub_end;

                            case KW_START:
                            case KW_CASE:
                            case KW_DEFAULT:
                                if (cc->coc.coc_head.last == tmpi_start)
                                {
                                    OptFree(tmpi_jmp);
                                    tmpss->lb_start = NULL;
                                }
                                else
                                {
                                    ICAdd(cc, IC_RET, 0, 0);
                                    ICAdd(cc, IC_LABEL, lb_fwd_case, 0);
                                    ICAdd(cc, IC_SUB_CALL, tmpss->lb_start, 0);//In case fall-thru
                                }
                                goto sw_cont;

                            default:
                                ParseStatement(cc, try_count);
                        }
                    }
                    break;

                case KW_CASE:
                    if (head.next != &head)
                    {
                        lb_fwd_case = COCMiscNew(cc, CMT_LABEL);
                        tmpi_jmp = ICAdd(cc, IC_JMP, lb_fwd_case, 0);//In case fall-thru
                    }
                    Lex(cc);
                    lb_entry = COCMiscNew(cc, CMT_LABEL);
                    ICAdd(cc, IC_LABEL, lb_entry, 0);
                    lb_entry->use_count++;
                    if (head.next != &head)
                    {
                        tmpss = head.next;
                        while (tmpss != &head)
                        {
                            if (tmpss->lb_start)
                                ICAdd(cc, IC_SUB_CALL, tmpss->lb_start, 0);
                            tmpss = tmpss->next;
                        }
                        ICAdd(cc, IC_LABEL, lb_fwd_case, 0);
                    }
                    if (cc->token == ':')
                    {
                        if (k_start == I64_MIN)
                            k_start = 0;
                        else
                            k_start++;
                    }
                    else
                        k_start = LexExpressionI64(cc);
                    if (k_start < lo)
                        lo = k_start;
                    if (k_start > hi)
                        hi = k_start;
                    if (cc->token == ':')
                    {
                        Lex(cc);
                        tmps = MAlloc(sizeof(CSwitchCase));
                        tmps->label = lb_entry;
                        tmps->val = k_start;
                        tmps->next = header;
                        header = tmps;
                    }
                    else if (cc->token == TK_ELLIPSIS)
                    {
                        Lex(cc);
                        k_end = LexExpressionI64(cc);
                        if (cc->token == ':')
                        {
                            Lex(cc);
                            if (k_end < lo)
                                lo = k_end;
                            if (k_end > hi)
                                hi = k_end;
                            if (k_start > k_end)
                                SwapI64(&k_start, &k_end);
                            for (i = k_start; i <= k_end; i++)
                            {
                                tmps = MAlloc(sizeof(CSwitchCase));
                                tmps->label = lb_entry;
                                tmps->val = i;
                                tmps->next = header;
                                header = tmps;
                            }
                            k_start = k_end;
                        }
                        else
                            LexExcept(cc, "Expecting ':' at ");
                    }
                    else
                        LexExcept(cc, "Expecting ':' at ");
                    break;

                case KW_DEFAULT:
                    if (head.next != &head)
                    {
                        lb_fwd_case = COCMiscNew(cc, CMT_LABEL);
                        tmpi_jmp = ICAdd(cc, IC_JMP, lb_fwd_case, 0);//In case fall-thru
                    }
                    Lex(cc);
                    ICAdd(cc, IC_LABEL, lb_default, 0);
                    if (cc->token == ':')
                        Lex(cc);
                    else
                        LexExcept(cc, "Expecting ':' at ");
                    if (head.next != &head)
                    {
                        tmpss = head.next;
                        while (tmpss != &head)
                        {
                            if (tmpss->lb_start)
                                ICAdd(cc, IC_SUB_CALL, tmpss->lb_start, 0);
                            tmpss = tmpss->next;
                        }
                        ICAdd(cc, IC_LABEL, lb_fwd_case, 0);
                    }
                    default_found = TRUE;
                    break;

                default:
                    ParseStatement(cc, try_count, head.last->lb_break);
            }
        }
sw_sub_end:
        tmpss = head.last;
        ICAdd(cc, IC_LABEL, tmpss->lb_break, 0);
        if (tmpss == &head)
        {
            if (cc->token != '}')
                LexExcept(cc, "Missing '}' at ");
            Lex(cc);
            break;
        }
        else
        {
            QueueRemove(tmpss);
            Free(tmpss);
            if (ParseKeyWord(cc) != KW_END)
                LexExcept(cc, "Missing 'end' at ");
            if (Lex(cc) == ':')
                Lex(cc);
            else
                LexExcept(cc, "Expecting ':' at ");
        }
    }
    if (!default_found)
        ICAdd(cc, IC_LABEL, lb_default, 0);

    if (0 < lo <= 16)
        lo = 0;
    range = hi - lo + 1;
    if (lo > hi || !(0 < range <= 0xFFFF))
        LexExcept(cc, "switch range error at ");
    jmp_table = MAlloc((sizeof(CCodeMisc *) * range + 0x1FF) & ~0x1FF);
    MemSetI64(jmp_table, lb_default, range);
    tmpi_sub->ic_data = lo;
    tmpi_cmp->ic_data = range;
    tmps = header;
    while (tmps)
    {
        tmps1 = tmps->next;
        if (jmp_table[tmps->val - lo] != lb_default)
            LexExcept(cc, "Duplicate case at ");
        else
            jmp_table[tmps->val - lo] = tmps->label;
        Free(tmps);
        tmps = tmps1;
    }
    mc_jt->default = lb_default;
    mc_jt->jmp_table = jmp_table;
    mc_jt->range = range;
}

U0 ParseNoWarn(CCompCtrl *cc)
{
    CMemberList *tmpm;

    while (cc->token == TK_IDENT)
    {
        if (!(tmpm = cc->local_var_entry))
            LexExcept(cc, "Expecting local var at ");
        tmpm->flags |= MLF_NO_UNUSED_WARN;
        if (Lex(cc) == ',')
            Lex(cc);
        else if (cc->token != ';')
            LexExcept(cc, "Expecting ',' at ");
    }
}

U0 ParseStreamBlk(CCompCtrl *cc)
{
    CLexHashTableContext    *htc = MAlloc(sizeof(CLexHashTableContext));
    CStreamBlk              *tmpe = MAlloc(sizeof(CStreamBlk));

    tmpe->body = StrNew("");
    QueueInsert(tmpe, cc->last_stream_blk);
    COCPush(cc);
    QueueInit(&cc->coc.coc_next_misc);

    MemCopy(htc, &cc->htc, sizeof(CLexHashTableContext));
    htc->old_flags = cc->flags;
    cc->htc.next = htc;
    cc->htc.fun = cc->htc.local_var_list  =NULL;
    cc->htc.define_hash_table = cc->htc.hash_table_list =
        cc->htc.global_hash_table = cc->htc.local_hash_table = Fs->hash_table;
    cc->flags = cc->flags & ~(CCF_ASM_EXPRESSIONS | CCF_AOT_COMPILE) | CCF_EXE_BLK;
    if (cc->token == '{')
        Lex(cc);
    else
        LexExcept(cc, "Missing '}' at ");
    while (cc->token && cc->token != '}')
        ExeCmdLine(cc);

    MemCopy(&cc->htc, htc, sizeof(CLexHashTableContext));
    cc->flags = cc->flags & ~CCF_EXE_BLK | htc->old_flags & (CCF_ASM_EXPRESSIONS | CCF_EXE_BLK | CCF_AOT_COMPILE);
    Free(htc);
    COCPop(cc);
    QueueRemove(tmpe);
    if (*tmpe->body)
        LexIncludeStr(cc, "StreamBlk", tmpe->body, FALSE);
    else
        Free(tmpe->body);
    Free(tmpe);
    Lex(cc); //Skip '}'
}

U0 ParseTryBlk(CCompCtrl *cc, I64 try_count)
{
    CCodeMisc   *lb_catch, *lb_done, *lb_untry;
    CHashClass  *tmpc = cmp.internal_types[RT_PTR];
    CHashFun    *tmp_try   = HashFind("SysTry", cc->htc.hash_table_list, HTT_FUN),
                *tmp_untry = HashFind("SysUntry", cc->htc.hash_table_list, HTT_FUN);

    if (!tmp_try || !tmp_untry)
        LexExcept(cc, "Missing header for SysTry() and SysUntry() at ");

    cc->flags |= CCF_NO_REG_OPT; //TODO:Currently no reg vars in funs with try/catch

    lb_catch = COCMiscNew(cc, CMT_LABEL);
    lb_done  = COCMiscNew(cc, CMT_LABEL);
    lb_untry = COCMiscNew(cc, CMT_LABEL);

    ICAdd(cc, IC_CALL_START, 0, 0);
    ICAdd(cc, IC_GET_LABEL, lb_untry, tmpc, ICF_PUSH_RES);
    ICAdd(cc, IC_GET_LABEL, lb_catch, tmpc, ICF_PUSH_RES);
    if (Bt(&tmp_try->flags, Cf_EXTERN))
    {
        cc->abs_counts.externs++;
        if (cc->flags & CCF_AOT_COMPILE)
            ICAdd(cc, IC_CALL_IMPORT, tmp_try, tmpc);
        else
            ICAdd(cc, IC_CALL_INDIRECT2, &tmp_try->exe_addr, tmpc);
    }
    else
        ICAdd(cc, IC_CALL, tmp_try->exe_addr, tmpc);
    if ((Bt(&tmp_try->flags, Ff_RET1) || Bt(&tmp_try->flags, Ff_ARGPOP)) && !Bt(&tmp_try->flags, Ff_NOARGPOP))
        ICAdd(cc, IC_ADD_RSP1, 16, tmpc);
    else
        ICAdd(cc, IC_ADD_RSP, 16, tmpc);
    ICAdd(cc, IC_CALL_END, 0, tmpc);
    ICAdd(cc, IC_END_EXP, 0, 0, ICF_RES_NOT_USED);

    ParseStatement(cc, try_count + 1);

    ICAdd(cc, IC_LABEL, lb_untry, 0);
    ICAdd(cc, IC_CALL_START, 0, 0);
    if (Bt(&tmp_untry->flags, Cf_EXTERN))
    {
        cc->abs_counts.externs++;
        if (cc->flags & CCF_AOT_COMPILE)
            ICAdd(cc, IC_CALL_IMPORT, tmp_untry, tmpc);
        else
            ICAdd(cc, IC_CALL_INDIRECT2, &tmp_untry->exe_addr, tmpc);
    }
    else
        ICAdd(cc, IC_CALL, tmp_untry->exe_addr, tmpc);
    ICAdd(cc, IC_CALL_END, 0, tmpc);
    ICAdd(cc, IC_END_EXP, 0, 0, ICF_RES_NOT_USED);

    ICAdd(cc, IC_JMP, lb_done, 0);

    if (ParseKeyWord(cc) != KW_CATCH)
        LexExcept(cc, "Missing 'catch' at");

    Lex(cc);
    ICAdd(cc, IC_LABEL, lb_catch, 0);
    ParseStatement(cc, try_count + 1);
    ICAdd(cc, IC_RET, 0, tmpc);
    ICAdd(cc, IC_LABEL, lb_done, 0);
}

Bool ParseStatement(CCompCtrl *cc, I64 try_count=0, CCodeMisc *lb_break=NULL, I64 comp_flags=CMPF_PRS_SEMICOLON)
{
    I64          i, fsp_flags = 0;
    CHashExport *tmpex;
    CCodeMisc   *g_lb;
    U8          *import_name;
    CHashFun    *tmp_untry;
    CAOT        *tmpaot;

    if (comp_flags & CMPF_ONE_ASM_INS)
    {
        if (cc->flags & CCF_AOT_COMPILE || cc->aot_depth)
            ParseAsmBlk(cc, CMPF_ONE_ASM_INS);
        else if (tmpaot = CompJoin(cc, CMPF_ASM_BLK | CMPF_ONE_ASM_INS))
            CompFixUpJITAsm(cc, tmpaot);
        fsp_flags = FSF_ASM;
    }
    else
        while (TRUE)
        {
            while (cc->token == ',')
                Lex(cc);
            if (cc->token == '{')
            {
                Lex(cc);
                while (cc->token != '}' && cc->token != TK_EOF)
                    ParseStatement(cc, try_count, lb_break);
                if (cc->lex_include_stack == cc->fun_lex_file)
                    cc->max_line = cc->lex_include_stack->line_num;
                if (Lex(cc) != ',')
                    goto sm_done;
            }
            else if (cc->token == ';')
            {
                if (comp_flags & CMPF_PRS_SEMICOLON)
                    Lex(cc);
                if (cc->token != ',')
                    goto sm_done;
            }
            else
            {
                if (cc->token == TK_IDENT)
                {
                    if (tmpex = cc->hash_entry)
                    {
                        if (tmpex->type & HTT_KEYWORD)
                        {
                            i = tmpex(CHashGeneric *)->user_data0;
                            switch [i]
                            {
                                case KW_KWS_NUM - 1: //nobound switch
                                default: //A keyword that is not valid here is just a symbol.
                                    goto sm_not_keyword_afterall;
                                start:
                                    case KW_ASM:
                                        if (cc->htc.fun)
                                        {
                                            if (tmpaot = CompJoin(cc, CMPF_ASM_BLK))
                                                ICAdd(cc, IC_ASM, tmpaot, 0);
                                            Lex(cc); //Skip '}' of asm{}
                                        }
                                        else
                                        {
                                            if (cc->flags & CCF_AOT_COMPILE || cc->aot_depth)
                                            {
                                                Lex(cc);
                                                ParseAsmBlk(cc, 0);
                                                if (cc->flags & CCF_AOT_COMPILE && cc->aot_depth == 1)
                                                    Lex(cc); //Skip '}' of asm{}
                                            }
                                            else
                                            {
                                                if (tmpaot = CompJoin(cc, CMPF_ASM_BLK))
                                                    CompFixUpJITAsm(cc, tmpaot);
                                                Lex(cc); //Skip '}' of asm{}
                                            }
                                            fsp_flags = FSF_ASM;
                                        }
                                        break;
                                    start:
                                        Lex(cc);
                                        case KW_LOCK:
                                            cc->lock_count++;
                                            ParseStatement(cc, try_count);
                                            cc->lock_count--;
                                            break;

                                        case KW_TRY:
                                            ParseTryBlk(cc, try_count);
                                            break;

                                        case KW_IF:
                                            ParseIf(cc, try_count, lb_break);
                                            break;

                                        case KW_FOR:
                                            ParseFor(cc, try_count);
                                            break;

                                        case KW_WHILE:
                                            ParseWhile(cc, try_count);
                                            break;

                                        case KW_DO:
                                            ParseDoWhile(cc, try_count);
                                            break;

                                        case KW_SWITCH:
                                            ParseSwitch(cc, try_count);
                                            break;
                                    end:
                                end:
                                    if (cc->token != ',')
                                        goto sm_done;
                                    break;
                                start:
                                    if (cc->htc.fun)
                                        LexExcept(cc, "Not allowed in fun");
                                    Lex(cc);
                                    case KW__EXTERN:
                                        if (Bt(&cc->opts, OPTf_EXTERNS_TO_IMPORTS))
                                            goto sm_underscore_import;
                                        if (cc->token != TK_IDENT || !(tmpex = cc->hash_entry) ||
                                                !(tmpex->type & HTT_EXPORT_SYS_SYM))
                                            LexExcept(cc, "Expecting system sym at ");
                                        if (*cc->cur_str == '_')
                                            fsp_flags |= FSF__;
                                        i = tmpex->val;
                                        Lex(cc);
                                        if (cc->token != TK_IDENT || !(tmpex = cc->hash_entry) ||
                                                !(tmpex->type & (HTT_CLASS | HTT_INTERNAL_TYPE)))
                                            LexExcept(cc, "Expecting type at ");
                                        Lex(cc);
                                        ParseGlobalVarList(cc, PRS0__EXTERN | PRS1_NULL, tmpex, i, fsp_flags);
                                        break;

                                    case KW__IMPORT:
sm_underscore_import:
                                        if (cc->token != TK_IDENT)
                                            LexExcept(cc, "Expecting system sym at ");
                                        if (*cc->cur_str == '_')
                                            fsp_flags |= FSF__;
                                        import_name = cc->cur_str;
                                        cc->cur_str = 0;
                                        if (Lex(cc) != TK_IDENT || !(tmpex = cc->hash_entry) ||
                                                !(tmpex->type & (HTT_CLASS | HTT_INTERNAL_TYPE)))
                                            LexExcept(cc, "Expecting type at ");
                                        Lex(cc);
                                        ParseGlobalVarList(cc, PRS0__IMPORT | PRS1_NULL, tmpex, import_name, fsp_flags);
                                        Free(import_name);
                                        break;

                                    case KW_EXTERN:
                                        if (cc->token != TK_IDENT)
                                            LexExcept(cc, "Expecting type at ");
                                        tmpex = cc->hash_entry;
                                        i = ParseKeyWord(cc);
                                        if (i == KW_CLASS || i == KW_UNION)
                                        {
                                            Lex(cc);
                                            ParseClass(cc, i, fsp_flags, TRUE);
                                            fsp_flags &= FSF_ASM;
                                            goto sm_semicolon;
                                        }
                                        if (!tmpex || !(tmpex->type & (HTT_CLASS | HTT_INTERNAL_TYPE)))
                                            LexExcept(cc, "Expecting type at ");
                                        if (Bt(&cc->opts, OPTf_EXTERNS_TO_IMPORTS))
                                            goto sm_import;
                                        Lex(cc);
                                        ParseGlobalVarList(cc, PRS0_EXTERN | PRS1_NULL, tmpex, 0, fsp_flags);
                                        break;

                                    case KW_IMPORT:
                                        if (cc->token != TK_IDENT || !(tmpex = cc->hash_entry) ||
                                                !(tmpex->type & (HTT_CLASS | HTT_INTERNAL_TYPE)))
                                            LexExcept(cc, "Expecting type at ");
sm_import:
                                        Lex(cc);
                                        ParseGlobalVarList(cc, PRS0_IMPORT | PRS1_NULL, tmpex, 0, fsp_flags);
                                        break;

                                    case KW__INTERN:
                                        i = LexExpressionI64(cc);
                                        if (cc->token != TK_IDENT || !(tmpex = cc->hash_entry) ||
                                                !(tmpex->type & (HTT_CLASS | HTT_INTERNAL_TYPE)))
                                            LexExcept(cc, "Expecting type at ");
                                        Lex(cc);
                                        ParseGlobalVarList(cc, PRS0__INTERN | PRS1_NULL, tmpex, i, fsp_flags);
                                        break;
                                end:
                                    fsp_flags &= FSF_ASM;
                                    break;
                                start:
                                    case KW_STATIC:
                                        fsp_flags = FSF_STATIC | fsp_flags & FSF_ASM;
                                        break;

                                    case KW_INTERRUPT:
                                        fsp_flags = FSF_INTERRUPT | FSF_NOARGPOP | fsp_flags & (FSG_FUN_FLAGS2 | FSF_ASM);
                                        break;

                                    case KW_HASERRCODE:
                                        fsp_flags = FSF_HASERRCODE | fsp_flags & (FSG_FUN_FLAGS2 | FSF_ASM);
                                        break;

                                    case KW_ARGPOP:
                                        fsp_flags = FSF_ARGPOP | fsp_flags & (FSG_FUN_FLAGS2 | FSF_ASM);
                                        break;

                                    case KW_NOARGPOP:
                                        fsp_flags = FSF_NOARGPOP | fsp_flags & (FSG_FUN_FLAGS2 | FSF_ASM);
                                        break;

                                    case KW_PUBLIC:
                                        fsp_flags = FSF_PUBLIC | fsp_flags & (FSG_FUN_FLAGS2 | FSF_ASM);
                                        break;
                                end:
                                    Lex(cc);
                                    break;

                                case KW_RETURN:
                                    if (!cc->htc.fun)
                                        LexExcept(cc, "Not in fun.  Can't return a val ");
                                    if (try_count)
                                    {
                                        tmp_untry = HashFind("SysUntry", cc->htc.hash_table_list, HTT_FUN);
                                        for (i = 0; i < try_count; i++)
                                        {
                                            if (Bt(&tmp_untry->flags, Cf_EXTERN))
                                            {
                                                cc->abs_counts.externs++;
                                                if (cc->flags & CCF_AOT_COMPILE)
                                                    ICAdd(cc, IC_CALL_IMPORT, tmp_untry, cmp.internal_types[RT_PTR]);
                                                else
                                                    ICAdd(cc, IC_CALL_INDIRECT2, &tmp_untry->exe_addr,
                                                          cmp.internal_types[RT_PTR]);
                                            }
                                            else
                                                ICAdd(cc, IC_CALL, tmp_untry->exe_addr, cmp.internal_types[RT_PTR]);
                                        }
                                    }
                                    if (Lex(cc) != ';')
                                    {
                                        if (!cc->htc.fun->return_class->size)
                                            LexWarn(cc, "Function should NOT return val ");
                                        if (!ParseExpression(cc, NULL, FALSE))
                                            throw('Compiler');
                                        ICAdd(cc, IC_RETURN_VAL, 0, cc->htc.fun->return_class);
                                        cc->flags |= CCF_HAS_RETURN;
                                    }
                                    else if (cc->htc.fun->return_class->size)
                                        LexWarn(cc, "Function should return val ");
                                    ICAdd(cc, IC_JMP, cc->lb_leave, 0);
                                    goto sm_semicolon;

                                case KW_GOTO:
                                    if (Lex(cc) != TK_IDENT)
                                        LexExcept(cc, "Expecting identifier at ");
                                    if (!(g_lb = COCGoToLabelFind(cc, cc->cur_str)))
                                    {
                                        g_lb = COCMiscNew(cc, CMT_GOTO_LABEL);
                                        g_lb->str = cc->cur_str;
                                        cc->cur_str = NULL;
                                    }
                                    g_lb->use_count++;
                                    ICAdd(cc, IC_JMP, g_lb, 0);
                                    Lex(cc);
                                    goto sm_semicolon;

                                case KW_BREAK:
                                    Lex(cc);
                                    if (!lb_break)
                                        LexExcept(cc, "'break' not allowed\n");
                                    ICAdd(cc, IC_JMP, lb_break, 0);
                                    goto sm_semicolon;

                                case KW_NO_WARN:
                                    Lex(cc);
                                    ParseNoWarn(cc);
                                    goto sm_semicolon;

                                case KW_UNION:
                                case KW_CLASS:
                                    Lex(cc);
                                    tmpex = ParseClass(cc, i, fsp_flags, FALSE);
                                    if (!cc->htc.fun && cc->token != ';') {
                                        ParseGlobalVarList(cc, PRS0_NULL | PRS1_NULL, tmpex, 0, fsp_flags);
                                        fsp_flags &= FSF_ASM;
                                        break;
                                    }
                                    else
                                    {
                                        fsp_flags &= FSF_ASM;
                                        goto sm_semicolon;
                                    }
                            }
                        }
                        else
                        {//Ident, found in hash table, not keyword
sm_not_keyword_afterall:
                            if (tmpex->type & (HTT_CLASS | HTT_INTERNAL_TYPE))
                            {
                                if (cc->htc.fun)
                                {
                                    if (fsp_flags & FSF_STATIC)
                                        ParseVarList(cc, cc->htc.fun, PRS0_NULL | PRS1_STATIC_LOCAL_VAR);
                                    else
                                        ParseVarList(cc, cc->htc.fun, PRS0_NULL | PRS1_LOCAL_VAR);
                                    if (cc->token == '}')
                                        goto sm_done;
                                }
                                else
                                {
                                    Lex(cc);
                                    ParseGlobalVarList(cc, PRS0_NULL | PRS1_NULL, tmpex, 0, fsp_flags);
                                }
                            }
                            else
                            {
                                if (tmpex->type & (HTT_OPCODE | HTT_ASM_KEYWORD))
                                {
                                    if (cc->htc.fun)
                                    {
                                        if (tmpaot = CompJoin(cc, CMPF_ASM_BLK | CMPF_ONE_ASM_INS))
                                            ICAdd(cc, IC_ASM, tmpaot, 0);
                                    }
                                    else
                                        LexExcept(cc, "Use Asm Blk at ");
                                    if (cc->token != ',')
                                        goto sm_done;
                                }
                                else
                                    goto sm_parse_exp;
                            }
                            fsp_flags &= FSF_ASM;
                        }
                    }
                    else
                    {//Ident, not in hash table
                        if (cc->local_var_entry)
                            goto sm_parse_exp;
                        if (!(g_lb = COCGoToLabelFind(cc, cc->cur_str)))
                        {
                            g_lb = COCMiscNew(cc, CMT_GOTO_LABEL);
                            g_lb->str = cc->cur_str;
                            cc->cur_str = NULL;
                        }
                        else if (g_lb->flags & CMF_DEFINED)
                            LexExcept(cc, "Duplicate goto label at ");
                        g_lb->flags |= CMF_DEFINED;
                        ICAdd(cc, IC_LABEL, g_lb, 0);
                        if (Lex(cc) == ':') //skip cur_str
                            Lex(cc); //skip colon
                        else
                            LexExcept(cc, "Undefined identifier at ");
                        if (!cc->htc.fun)
                            LexExcept(cc, "No global labels at ");
                        if (cc->token != ',')
                            goto sm_done;
                    }
                }
                else if (cc->token == TK_STR || cc->token == TK_CHAR_CONST)
                {
                    ParseFunCall(cc, NULL, FALSE, NULL);
                    goto sm_semicolon;
                }
                else if (cc->token != TK_EOF)
                {//Non-cur_str symbol, num or something
sm_parse_exp:
                    if (!ParseExpression(cc, NULL, TRUE))
                        throw('Compiler');
sm_semicolon:
                    if (comp_flags & CMPF_PRS_SEMICOLON)
                    {
                        if (cc->token == ';')
                            Lex(cc);
                        else if (cc->token != ',')
                            LexExcept(cc, "Missing ';' at");
                    }
                    if (cc->token != ',')
                        goto sm_done;
                }
                else
                    goto sm_done; //TK_EOF
            }
        }
sm_done:

    return fsp_flags & FSF_ASM;
}