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;
}
