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 value. See ::/Demo/ClassMeta.ZC.
    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 ::/Demo/ClassMeta.ZC.
    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 ClassRep() and 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 duplicate class local variables.
    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 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;
}