U0 LexBackupLastChar(CCompCtrl *cc)
{
	CLexFile *tmpf = cc->lex_include_stack;

	tmpf->buf_ptr = cc->cur_buf_ptr;
	if (cc->flags & CCF_USE_LAST_U16)
	{
		tmpf->last_U16 = cc->last_U16;
		cc->flags &= ~CCF_USE_LAST_U16;
	}
	else
		tmpf->last_U16 = 0;
}

U0 LexPush(CCompCtrl *cc)
{//Create token-stream save point.
	CLexFile *tmpf;

	LexBackupLastChar(cc);
	if (cc->lex_include_stack->last_U16)
		cc->flags |= CCF_USE_LAST_U16;
	tmpf = MAllocIdent(cc->lex_include_stack);
	tmpf->next = cc->lex_parse_stack;
	cc->lex_parse_stack = tmpf;
}

U0 LexPopRestore(CCompCtrl *cc)
{//Restore token-stream saved-point.
//Bad things can happen if you cross an #include file boundary.
	CLexFile *tmpf = cc->lex_parse_stack;

	cc->cur_buf_ptr = tmpf->buf_ptr;
	if (cc->last_U16 = tmpf->last_U16)
		cc->flags |= CCF_USE_LAST_U16;
	else
		cc->flags &= ~CCF_USE_LAST_U16;
	MemCopy(cc->lex_include_stack(U8 *) + sizeof(U8 *), tmpf(U8 *) + sizeof(U8 *), sizeof(CLexFile) - sizeof(U8 *));
	cc->lex_parse_stack = tmpf->next;
	Free(tmpf);
}

U0 LexPopNoRestore(CCompCtrl *cc)
{//Don't restore token-stream saved-point.
	CLexFile *tmpf = cc->lex_parse_stack;

	cc->lex_parse_stack = tmpf->next;
	Free(tmpf);
}

I64 MemberMetaData(U8 *needle_str, CMemberList *haystack_member_list)
{//Find meta data name, return meta data val. See $LK,"::/Demo/ClassMeta.CC"$.
	CMemberListMeta *meta = haystack_member_list->meta;

	while (meta)
	{
		if (!StrCompare(meta->str, needle_str))
			return meta->user_data;
		meta = meta->next;
	}

	return 0;
}

CMemberListMeta *MemberMetaFind(U8 *needle_str, CMemberList *haystack_member_list)
{//Find meta data name, return meta data struct. See $LK,"::/Demo/ClassMeta.CC"$.
	CMemberListMeta *meta = haystack_member_list->meta;

	while (meta)
	{
		if (!StrCompare(meta->str, needle_str))
			return meta;
		meta = meta->next;
	}

	return NULL;
}

CMemberList *MemberFind(U8 *needle_str, CHashClass *haystack_class)
{//Find class member. See $LK,"ClassRep",A="MN:ClassRep"$() and $LK,"DocForm",A="MN:DocForm"$().
	I64			 i;
	CMemberList	*tmpm;

	do
	{
		tmpm = haystack_class->member_list_and_root;
		while (tmpm)
		{
			if (!(i = StrCompare(tmpm->str, needle_str)))
			{
				tmpm->use_count++;
				return tmpm;
			}
			if (i <= 0)
				tmpm = tmpm->left;
			else
				tmpm = tmpm->right;
		}
	}
	while (haystack_class = haystack_class->base_class);

	return NULL;
}

CMemberList *MemberClassBaseFind(CHashClass *needle_class, CHashClass *haystack_class)
{//Find class member class base. For finding dup class local vars.
	CMemberList *tmpm;

	tmpm = haystack_class->member_class_base_root;
	while (tmpm)
	{
		if (needle_class == tmpm->member_class_base)
			return tmpm;
		if (needle_class < tmpm->member_class_base)
			tmpm = tmpm->left_class_base;
		else
			tmpm = tmpm->right_class_base;
	}

	return NULL;
}

U0 MemberAdd(CCompCtrl *cc, CMemberList *tmpm, CHashClass *tmpc, I64 mode)
{
	U8			 *st = tmpm->str;
	CMemberList	**tmpm1, *tmpm2;

	if (MemberFind(st, tmpc) && StrCompare(st, "pad") && StrCompare(st, "reserved") && StrCompare(st, "_anon_"))
		LexExcept(cc, "Duplicate member at ");
	tmpm1 = &tmpc->member_list_and_root;
	while (tmpm2 = *tmpm1)
	{
		if (StrCompare(tmpm2->str, st) <= 0)
			tmpm1 = &tmpm2->left;
		else
			tmpm1 = &tmpm2->right;
	}
	*tmpm1 = tmpm;

	if (mode == PRS1B_LOCAL_VAR)
	{
		tmpm->member_class_base = tmpm->member_class - tmpm->member_class->ptr_stars_count;
		if (Bt(&cc->opts, OPTf_WARN_DUP_TYPES) && MemberClassBaseFind(tmpm->member_class_base, tmpc))
			LexWarn(cc, "Duplicate type at ");
		tmpm1 = &tmpc->member_class_base_root;
		while (tmpm2 = *tmpm1)
		{
			if (tmpm->member_class_base < tmpm2->member_class_base)
				tmpm1 = &tmpm2->left_class_base;
			else if (tmpm->member_class_base > tmpm2->member_class_base)
				tmpm1 = &tmpm2->right_class_base;
			else
			{
				tmpm1 = NULL;
				break;
			}
		}
		if (tmpm1)
			*tmpm1 = tmpm;
	}
	else
		tmpm->member_class_base = NULL;

	tmpm->left = NULL;
	tmpm->right = NULL;
	tmpm->left_class_base = NULL;
	tmpm->right_class_base = NULL;
	tmpm2 = tmpc->last_in_member_list;
	tmpm2->next = tmpc->last_in_member_list = tmpm;
}

CMemberList *MemberListNew(I64 _reg)
{
	CMemberList *res = CAlloc(sizeof(CMemberList));

	res->reg = _reg;

	return res;
}

Bool MemberListCmp(CMemberList *tmpm1, CMemberList *tmpm2, I64 count=I64_MAX)
{
	while (tmpm1 && tmpm2 && count--)
	{
		if (StrCompare(tmpm1->str,tmpm2->str) ||
				tmpm1->member_class		 != tmpm2->member_class ||
				tmpm1->member_class_base != tmpm2->member_class_base)
			return FALSE;
		if (tmpm1->flags & MLF_DEFAULT_AVAILABLE || tmpm2->flags & MLF_DEFAULT_AVAILABLE)
		{
			if (tmpm1->flags & (MLF_DEFAULT_AVAILABLE | MLF_STR_DEFAULT_AVAILABLE) !=
					tmpm2->flags & (MLF_DEFAULT_AVAILABLE | MLF_STR_DEFAULT_AVAILABLE))
				return FALSE;
			if (tmpm1->flags & MLF_STR_DEFAULT_AVAILABLE)
			{
				if (StrCompare(tmpm1->default_val, tmpm2->default_val))
					return FALSE;
			}
			else if (tmpm1->default_val != tmpm2->default_val)
				return FALSE;
		}
		tmpm1 = tmpm1->next;
		tmpm2 = tmpm2->next;
	}
	if (count < 0 || !tmpm1 && !tmpm2)
		return TRUE;
	else
		return FALSE;
}

U0 MemberListDel(CMemberList *tmpm)
{
	CMemberList		*tmpm1;
	CMemberListMeta	*tmp_meta, *tmp_meta1;

	while (tmpm)
	{
		tmpm1 = tmpm->next;
		Free(tmpm->str);
		LinkedListDel(tmpm->dim.next);
		if (tmpm->flags & MLF_STR_DEFAULT_AVAILABLE)
			Free(tmpm->default_val);
		if (tmpm->flags & MLF_FUN)
			HashDel(tmpm->fun_ptr - tmpm->fun_ptr->ptr_stars_count);
		tmp_meta = tmpm->meta;
		while (tmp_meta)
		{
			tmp_meta1 = tmp_meta->next;
			Free(tmp_meta->str);
			if (tmp_meta->flags & MLMF_IS_STR)
				Free(tmp_meta->user_data);
			Free(tmp_meta);
			tmp_meta = tmp_meta1;
		}
		Free(tmpm);
		tmpm = tmpm1;
	}
}

U0 ClassMemberListDel(CHashClass *tmpc)
{
	MemberListDel(tmpc->member_list_and_root);
	tmpc->size = 0;
	tmpc->last_in_member_list = &tmpc->member_list_and_root;
	tmpc->member_list_and_root = NULL;
	tmpc->member_class_base_root = NULL;
	tmpc->member_count = 0;
	if (tmpc->type & HTT_FUN)
		tmpc(CHashFun *)->arg_count = 0;
}

I64 MemberListSize(CHashClass *tmpc)
{
	CMemberList		*tmpm;
	CMemberListMeta	*tmp_meta;
	I64				 res = 0;

	tmpm = tmpc->member_list_and_root;
	while (tmpm)
	{
		res += MSize2(tmpm->str);
		res += LinkedListSize(tmpm->dim.next);
		if (tmpm->flags & MLF_STR_DEFAULT_AVAILABLE)
			res += MSize2(tmpm->default_val);
		if (tmpm->flags & MLF_FUN)
			res += HashEntrySize2(tmpm->fun_ptr - tmpm->fun_ptr->ptr_stars_count);
		tmp_meta = tmpm->meta;
		while (tmp_meta)
		{
			res += MSize2(tmp_meta->str);
			if (tmp_meta->flags & MLMF_IS_STR)
				res += MSize2(tmp_meta->user_data);
			res += MSize2(tmp_meta);
			tmp_meta = tmp_meta->next;
		}
		res += MSize2(tmpm);
		tmpm = tmpm->next;
	}

	return res;
}

U8 *LexExtStr(CCompCtrl *cc, I64 *_size=NULL, Bool lex_next=TRUE)
{//Lex $LK,"TK_STR",A="MN:TK_STR"$'s to one combined str. _size includes terminator.
	I64 len = cc->cur_str_len, len1, len2;
	U8 *st = cc->cur_str, *st1, *st2;

	cc->cur_str = NULL;
	while (cc->token == TK_STR)
	{
		st1 = st;
		len1 = len;
		if (!lex_next && LexCharGet(cc) != '\\')
		{
			cc->flags |= CCF_USE_LAST_U16;
			break;
		}
		if (Lex(cc) == TK_STR)
		{
			len2 = cc->cur_str_len;
			st2 = cc->cur_str;
			cc->cur_str = NULL;
			len = len1 + len2 - 1;
			st = MAlloc(len);
			if (len1 > 1)
				MemCopy(st, st1, len1 - 1);
			MemCopy(st + len1 - 1, st2, len2);
			Free(st1);
			Free(st2);
		}
	}
	if (_size)
		*_size = len;

	return st;
}
