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

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

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

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

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

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

I64 ParseKeyWord(CCompCtrl *cc)
{//Convert cur token to $LK,"KEYWORD",A="FF:::/Compiler/OpCodes.DD,KEYWORD"$ or -1.
	CHashGeneric *tmph;

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

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

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

	return res;
}

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

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

	return res;
}

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

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

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

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

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

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

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

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

	return tmpcbh;
}

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

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

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

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

	return res;
}

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

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

	return NULL;
}

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

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

	return cm->addr;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	return res;
}
