CLexFile *LexFilePush(CCompCtrl *cc)
{//#include file push.
    CLexFile *res = CAlloc(sizeof(CLexFile));

    if (res->next = cc->lex_include_stack)
        res->depth = res->next->depth + 1;
    else
        res->depth = -1; //Include depth starts with -1.
    return cc->lex_include_stack = res;
}

CLexFile *LexFilePop(CCompCtrl *cc)
{//#include file pop.
    CLexFile *tmpf;
    if (tmpf = cc->lex_include_stack)
    {
        if ((cc->lex_include_stack = tmpf->next) || !(cc->flags & CCF_DONT_FREE_BUF))
        {
            if (tmpf->flags & LFSF_DOC)
            {
                if (tmpf->doc)
                    DocDel(tmpf->doc);
            }
            else
                Free(tmpf->buf);;
        }
        Free(tmpf->full_name);
        Free(tmpf);
    }
    return cc->lex_include_stack;
}

CCompCtrl *CompCtrlNew(U8 *buf=NULL, I64 flags=0, U8 *filename=NULL)
{//MAlloc and Init CCompCtrl.
    //Frees buf in CompCtrlDel unless CCF_DONT_FREE_BUF flag is set.
    //FileName is for error reporting.  If files are #included,
    //new names are used.  See Psalmody CompCtrlNew.
    CCompCtrl *cc = CAlloc(sizeof(CCompCtrl));
    CLexFile  *tmpf;

    QueueInit(cc);
    cc->flags = flags;
    cc->opts = 1 << OPTf_WARN_UNUSED_VAR | 1 << OPTf_WARN_HEADER_MISMATCH;
    cc->htc.hash_mask = HTG_TYPE_MASK - HTT_IMPORT_SYS_SYM;
    cc->htc.define_hash_table = cc->htc.hash_table_list = 
        cc->htc.global_hash_table = cc->htc.local_hash_table = Fs->hash_table;
    if (flags & CCF_KEEP_AT_SIGN)
        cc->char_bmp_alpha_numeric = char_bmp_alpha_numeric_no_at;
    else
        cc->char_bmp_alpha_numeric = char_bmp_alpha_numeric;
    tmpf = LexFilePush(cc);
    QueueInit(&cc->next_stream_blk);
    if (filename)
        tmpf->full_name = FileNameAbs(filename);
    else
        tmpf->full_name = StrNew(blkdev.tmp_filename);
    if (flags & CCF_PROMPT)
        buf = CAlloc(8);
    tmpf->buf = tmpf->buf_ptr = tmpf->line_start = cc->cur_buf_ptr = buf;
    tmpf->line_num = 1;
    return cc;
}

U0 CompCtrlDel(CCompCtrl *cc)
{//Free CCompCtrl.
    while (LexFilePop(cc));
    LinkedListDel(cc->lex_parse_stack);
    LinkedListDel(cc->htc.next);
    Free(cc->ps);
    Free(cc->cur_str);
    Free(cc->cur_help_idx);
    Free(cc->dollar_buf);
    Free(cc);
}

I64 CompCtrlSize(CCompCtrl *cc)
{//Mem size of CCompCtrl and its members.
    CLexFile    *tmpf = cc->lex_include_stack;
    I64          res = 0;

    while (tmpf)
    {
        if (tmpf->next || !(cc->flags & CCF_DONT_FREE_BUF))
        {
            if (tmpf->flags & LFSF_DOC)
            {
                if (tmpf->doc)
                    res += DocSize(tmpf->doc);
            }
            else
                res += MSize2(tmpf->buf);
        }
        res += MSize2(tmpf->full_name);
        res += MSize2(tmpf);
        tmpf = tmpf->next;
    }
    res += MSize2(cc->cur_str);
    res += MSize2(cc);
    return res;
}

U32 lex_zeros = 0;

Bool LexDollar(CCompCtrl *cc, CDoc *doc, CDocEntry *doc_e)
{
    U8 *st;

    if (cc->flags & CCF_IN_QUOTES)
    {
        Free(cc->dollar_buf);
        st = Doc2PlainText(doc, doc_e);
        cc->dollar_buf = MStrPrint("$%$Q$", st);
        cc->dollar_count = 2;
        Free(st);
        return TRUE;
    }
    else
        return FALSE;
}

I64 LexCharGet(CCompCtrl *cc)
{//Get one char from stream. Allow put-back one.
    U8          *ptr, *src;
    CLexFile    *tmpf;
    CDoc        *doc;
    CDocEntry   *doc_e;

    if (!Btr(&cc->flags, CCf_USE_LAST_U16))
    {
lgc_start1:
        if (!(src = cc->cur_buf_ptr++))
        {
            cc->cur_buf_ptr = NULL;
            goto lgc_here;
        }
        switch [cc->last_U16 = *src++]
        {
            case 0:
lgc_here:
                tmpf = cc->lex_include_stack;
                if (tmpf->flags & LFSF_DOC)
                {
                    doc = tmpf->doc;
                    doc_e = tmpf->cur_entry;
                    doc_e = doc_e->next;
lgc_start2:
                    if (doc_e != doc)
                    {
                        tmpf->cur_entry = doc_e;
                        switch [doc_e->type_u8]
                        {
                            case DOCT_TEXT:
                                if (doc_e->de_flags &
                                    ~(DOCEF_TAG | DOCEF_DEFINE | DOCEF_TAG_CB | DOCG_BL_IV_UL | DOCEF_WORD_WRAP |
                                    DOCEF_HIGHLIGHT | DOCEF_SKIP | DOCEF_FILTER_SKIP) &&
                                    LexDollar(cc, doc, doc_e) && *(src = cc->dollar_buf))
                                {
                                    tmpf->line_num = doc_e->y + 1;
                                    tmpf->buf_ptr = cc->cur_buf_ptr = src;
                                }
                                else if (*(src = doc_e->tag))
                                    tmpf->buf_ptr = cc->cur_buf_ptr = src;
                                else
                                {
                                    doc_e = doc_e->next;
                                    goto lgc_start2;
                                }
                                break;

                            case DOCT_NEW_LINE:
                                tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                tmpf->line_start = doc_e->next;
                                tmpf->line_num = doc_e->y + 2;//+1 because NEW_LINE is on prev line
                                                              //+1 because doc y starts at zero
                                cmp.compiled_lines++;
                                cc->last_U16 = '\n';
                                goto lgc_done;

                            case DOCT_TAB:
                                tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                tmpf->line_num = doc_e->y + 1;
                                cc->last_U16 = '\t';
                                goto lgc_done;

                            case DOCT_INS_BIN:
                                tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                tmpf->line_num = doc_e->y + 1;
                                Free(cc->cur_str);
                                cc->cur_str = NULL;
                                cc->cur_str_len = 0;
                                if (doc_e->bin_data)
                                {
                                    ptr = MAlloc(doc_e->bin_data->size);
                                    if (doc_e->bin_data->data)
                                        MemCopy(ptr, doc_e->bin_data->data, doc_e->bin_data->size);
                                    cc->cur_str = ptr;
                                    cc->cur_str_len = doc_e->bin_data->size;
                                }
                                cc->last_U16 = TK_INS_BIN;
                                goto lgc_done;

                            case DOCT_INS_BIN_SIZE:
                                tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                if (doc_e->bin_data)
                                    cc->cur_i64 = doc_e->bin_data->size;
                                else
                                    cc->cur_i64 = 0;
                                tmpf->line_num = doc_e->y + 1;
                                cc->last_U16 = TK_INS_BIN_SIZE;
                                goto lgc_done;

                            case DOCT_SHIFTED_Y:
                                if (LexDollar(cc, doc, doc_e) && *(src = cc->dollar_buf))
                                {
                                    tmpf->line_num = doc_e->y + 1;
                                    tmpf->buf_ptr = cc->cur_buf_ptr = src;
                                }
                                else
                                {
                                    tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                    tmpf->line_num = doc_e->y + 1;
                                    if (doc_e->attr < 0)
                                        cc->last_U16 = TK_SUPERSCRIPT;
                                    else if (doc_e->attr > 0)
                                        cc->last_U16 = TK_SUBSCRIPT;
                                    else
                                        cc->last_U16 = TK_NORMALSCRIPT;
                                    goto lgc_done;
                                }
                                break;

                            case DOCT_MARKER:
                            case DOCT_CURSOR:
                                doc_e = doc_e->next;
                                goto lgc_start2;

                            case 0xFF: // nobound switch
                            default:
                                if (LexDollar(cc, doc, doc_e) && *(src = cc->dollar_buf))
                                {
                                    tmpf->line_num = doc_e->y + 1;
                                    tmpf->buf_ptr = cc->cur_buf_ptr = src;
                                }
                                else
                                {
                                    doc_e = doc_e->next;
                                    goto lgc_start2;
                                }
                        }
                    }
                    if (doc_e != doc)
                        goto lgc_start1;
                    tmpf->cur_entry = doc->head.last; // When take next, will still be end.
                }
                tmpf = cc->lex_include_stack;
                if (tmpf->next)
                {
                    tmpf = LexFilePop(cc);
                    cc->cur_buf_ptr = tmpf->buf_ptr;
                    cc->flags &= ~CCF_USE_LAST_U16;
                    if (!(cc->last_U16 = tmpf->last_U16))
                        goto lgc_start1;
                }
                else
                {
                    if (cc->flags & CCF_PROMPT)
                    {
                        Free(tmpf->buf);
                        ptr = CmdLinePrompt;
                        if (StrCompare(ptr, "\n") && !cc->prompt_line++ && 
                            !StrCompare(ptr, "?\n") && cc->flags & CCF_QUESTION_HELP)
                        {
                            Free(ptr);
                            ptr = StrNew("Help;;\n");
                        }
                        tmpf->buf = tmpf->buf_ptr = tmpf->line_start = cc->cur_buf_ptr = ptr;
                        goto lgc_start1;
                    }
                    else
                    {
                        if (src)
                            cc->cur_buf_ptr = src - 1;
                        cc->last_U16 = TK_EOF;
                    }
                }
                break;

            case CH_CURSOR:
                goto lgc_start1;

            case '\n':
                tmpf = cc->lex_include_stack;
                if (!(tmpf->flags & LFSF_DOC))
                {
                    tmpf->line_num++;
                    cmp.compiled_lines++;
                    tmpf->line_start = src;
                }
                break;

            case 0xFF: //nobound switch
        }
lgc_done:
        if (cc->opts & OPTF_ECHO && cc->last_U16 < 256 && Bt(char_bmp_printable, cc->last_U16))
            '' cc->last_U16;
    }

    return cc->last_U16;
}

U0 LexSkipEol(CCompCtrl *cc)
{//LexCharGet to NULL until end-of-line.
    I64 ch;

    do ch = LexCharGet(cc);
    while (Bt(char_bmp_non_eol, ch));
}

U8 *LexFirstRemove(CCompCtrl *cc, U8 *marker, I64 _len=NULL)
{//LexCharGet() chars making str until marker.
    U8              *res, *ptr;
    CQueueVectU8    *tmpv = QueueVectU8New;
    I64              i, len = 0;

    while (TRUE)
    {
        i = LexCharGet(cc);
        if (!i || StrOcc(marker, i))
            break;
        QueueVectU8Put(tmpv, len++, i);
    }
    if (i)
        Bts(&cc->flags, CCf_USE_LAST_U16);
    res = ptr = MAlloc(len + 1);
    for (i = 0; i < len; i++)
        *ptr++ = QueueVectU8Get(tmpv, i);
    *ptr = 0;
    QueueVectU8Del(tmpv);
    if (_len)
        *_len = len;

    return res;
}

U0 LexIncludeStr(CCompCtrl *cc, U8 *abs_filename, U8 *src, Bool actual_file)
{
    LexBackupLastChar(cc);
    CLexFile *tmpf = LexFilePush(cc);

    if (actual_file)
        tmpf->full_name = StrNew(abs_filename);
    else
        tmpf->full_name = StrNew(blkdev.tmp_filename);
    tmpf->line_num = 1;
    tmpf->buf = tmpf->buf_ptr = tmpf->line_start = cc->cur_buf_ptr = src;
}

CDoc *LexDocRead(U8 *abs_filename, I64 flags)
{
    CDoc    *doc = DocNew(abs_filename);
    U8      *src;
    I64      size = 0;

    doc->flags |= flags;
    src = FileRead(abs_filename, &size);
    if (!src || !size)
    {
        Free(src);
        src = CAlloc(1);
        size = 0;
    }
    DocLoad(doc, src, size);
    Free(src);

    return doc;
}

I64 comp_type_flags_src_code[(DOCT_TYPES_NUM + 63) / 64] = {
    1 << DOCT_TEXT | 1 << DOCT_TAB | 1 << DOCT_INS_BIN | 1 << DOCT_INS_BIN_SIZE};

U0 LexAttachDoc(CCompCtrl *cc, CLexFile *tmpf=NULL, CDoc *doc=NULL, U8 *abs_filename=NULL, CDocEntry *doc_e=NULL, I64 col=0)
{//Start lexing doc. Give either doc or abs_filename.
    if (!doc)
        doc = LexDocRead(abs_filename, DOCF_DBL_DOLLARS);
    if (!tmpf)
    {
        LexBackupLastChar(cc);
        tmpf = LexFilePush(cc);
    }
    if (!doc_e)
        doc_e = doc->head.next;
    tmpf->full_name = StrNew(doc->filename.name);
    tmpf->doc = doc;
    while (doc_e != doc)
    {
        if (Bt(comp_type_flags_src_code, doc_e->type_u8))
            break;
        doc_e = doc_e->next;
        col = doc_e->min_col;
    }
    if (doc_e != doc)
    {
        col = ClampI64(col, doc_e->min_col, doc_e->max_col);
        tmpf->line_start = doc_e;
        tmpf->buf = NULL;
        tmpf->line_num = doc_e->y + 1;
        if (doc_e->type_u8 == DOCT_TEXT)
        {
            tmpf->cur_entry = doc_e;
            tmpf->buf_ptr = doc_e->tag;
        }
        else
        {
            tmpf->cur_entry = doc_e->last; //TODO: might be problem at begin of file
            tmpf->buf_ptr = &lex_zeros;
        }
        tmpf->flags = LFSF_DOC;
    }
    else
    {//TODO: DocDel(doc)?
        col = 0;
        tmpf->buf = tmpf->buf_ptr = tmpf->line_start = CAlloc(1);
        tmpf->line_num = 1;
        tmpf->flags = 0;
    }
    cc->cur_buf_ptr = tmpf->buf_ptr + col;
    tmpf->last_U16 = 0;
}

I64 LexInStr(CCompCtrl *cc, U8 *buf, I64 size, Bool *done)
{
    I64 i = 0, j, k, ch;

    *done = TRUE;
    while (i < size - 1)
    {
        ch = LexCharGet(cc);
        if (!ch || ch== '"')
        {
            buf[i++] = 0;
            return i;
        }
        else if (ch == '\\')
        {
            switch (ch = LexCharGet(cc))
            {
                case '0':
                    buf[i++] = 0;
                    break;

                case '\'':
                    buf[i++] = '\'';
                    break;

                case '\`':
                    buf[i++] = '\`';
                    break;

                case '\\':
                    buf[i++] = '\\';
                    break;

                case '"':
                    buf[i++] = '"';
                    break;

                case 'd':
                    buf[i++] = '$';
                    break;

                case 'n':
                    buf[i++] = '\n';
                    break;

                case 'r':
                    buf[i++] = '\r';
                    break;

                case 't':
                    buf[i++] = '\t';
                    break;

                case 'x':
                case 'X':
                    j = 0;
                    for (k = 0; k < 2; k++)
                    {
                        ch = ToUpper(LexCharGet(cc));
                        if (Bt(char_bmp_hex_numeric, ch))
                        {
                            if (ch <= '9')
                                j = j << 4 + ch - '0';
                            else
                                j = j << 4 + ch - 'A' + 10;
                        }
                        else
                        {
                            cc->flags |= CCF_USE_LAST_U16;
                            break;
                        }
                    }
                    buf[i++] = j;
                    break;

                default:
                    cc->flags |= CCF_USE_LAST_U16;
                    buf[i++] = '\\';
            }
        }
        else if (ch == '$')
        {
            buf[i++] = '$';
            if (cc->dollar_count)
                cc->dollar_count--;
            else if (LexCharGet(cc) != '$')
            {
                cc->dollar_count = 1;
                cc->flags |= CCF_USE_LAST_U16;
            }
        }
        else
            buf[i++] = ch;
    }
    *done = FALSE;

    return i;
}

I64 Lex(CCompCtrl *cc)
{//Fetch next token.
    I64      i, j, k, l, ch;
    CHash   *tmph;
    Bool     str_done, in_str, neg_e;
    U8      *fbuf, *buf2, *buf3, buf[STR_LEN];

    cc->last_line_num = cc->lex_include_stack->line_num;
    while (TRUE)
    {
lex_cont:
        switch [ch = LexCharGet(cc)]
        {
            case 0:
                return cc->token = TK_EOF;

            case TK_SUPERSCRIPT:
                ch = '>';
                goto lex_ident;

            case TK_SUBSCRIPT:
                ch = '<';
                goto lex_ident;

            case TK_NORMALSCRIPT:
                ch = '=';
                goto lex_ident;

            case '@':
                if (cc->flags & CCF_KEEP_AT_SIGN)
                {
                    cc->token = ch;
                    goto lex_end;
                }
            case 'A'...'Z':
            case 'a'...'z':
            case '_':
            case 128...255:
lex_ident:
                i = 0;
                buf[i++] = ch;
                while (TRUE) {
                    if (i >= STR_LEN)
                        LexExcept(cc, "Ident limited to STR_LEN chars at ");
                    else if (!(ch = LexCharGet(cc)))
                        break;
                    else if (Bt(cc->char_bmp_alpha_numeric, ch))
                        buf[i++] = ch;
                    else if (ch == TK_SUPERSCRIPT)
                        buf[i++] = '>';
                    else if (ch == TK_SUBSCRIPT)
                        buf[i++] = '<';
                    else if (ch == TK_NORMALSCRIPT)
                        buf[i++] = '=';
                    else
                    {
                        cc->flags |= CCF_USE_LAST_U16;
                        break;
                    }
                }
                buf[i++] = 0;
                tmph = NULL;
                if (cc->htc.local_var_list)
                    cc->local_var_entry = MemberFind(buf, cc->htc.local_var_list);
                else
                    cc->local_var_entry = NULL;
                if (!cc->local_var_entry && cc->htc.hash_table_list)
                    tmph = HashFind(buf, cc->htc.hash_table_list, cc->htc.hash_mask);
                if (tmph)
                    j = tmph->type;
                else
                    j = 0;
                if (j & HTT_DEFINE_STR && !(cc->flags & CCF_NO_DEFINES))
                {
                    LexIncludeStr(cc, tmph->str, StrNew(tmph(CHashDefineStr *)->data), FALSE);
                    cc->lex_include_stack->flags |= LFSF_DEFINE;
                }
                else
                {
                    cc->hash_entry = tmph;
                    Free(cc->cur_str);
                    cc->cur_str = StrNew(buf);
                    cc->cur_str_len = i;
                    cc->token = TK_IDENT;
                    goto lex_end;
                }
                break;

            case '0'...'9':
                i = ch - '0';
                ch = ToUpper(LexCharGet(cc));
                if (!Bt(&cc->opts, OPTf_DECIMAL_ONLY))
                {
                    if (ch == 'X')
                    {
                        while (TRUE)
                        {
                            ch = ToUpper(LexCharGet(cc));
                            if (Bt(char_bmp_hex_numeric, ch))
                            {
                                if (ch <= '9')
                                    i = i << 4 + ch - '0';
                                else
                                    i = i << 4 + ch - 'A' + 10;
                            }
                            else
                            {
                                cc->cur_i64 = i;
                                cc->flags |= CCF_USE_LAST_U16;
                                cc->token = TK_I64;
                                goto lex_end;
                            }
                        }
                    }
                    else if (ch == 'B')
                    {
                        while (TRUE)
                        {
                            ch = LexCharGet(cc);
                            if (ch == '0')
                                i = i << 1;
                            else if (ch == '1')
                                i = i << 1 + 1;
                            else
                            {
                                cc->cur_i64 = i;
                                cc->flags |= CCF_USE_LAST_U16;
                                cc->token = TK_I64;
                                goto lex_end;
                            }
                        }
                    }
                }
                while (TRUE)
                {
                    if (Bt(char_bmp_dec_numeric, ch))
                        i = i * 10 + ch - '0';
                    else
                    {
                        if (ch == '.' || ch == 'e' || ch == 'E')
                            break;
lex_is_int:
                        cc->cur_i64 = i;
                        cc->flags |= CCF_USE_LAST_U16;
                        cc->token = TK_I64;
                        goto lex_end;
                    }
                    ch = LexCharGet(cc);
                }
                if (ch == '.')
                {
                    ch = LexCharGet(cc);
                    if (ch == '.') {
                        cc->flags |= CCF_LAST_WAS_DOT;
                        goto lex_is_int;
                    }
                }
lex_float_start:
                k = 0;
                while (TRUE)
                {
                    if (Bt(char_bmp_dec_numeric, ch))
                    {
                        i = i * 10 + ch - '0';
                        k++;
                    }
                    else
                    {
                        if (ch == 'e' || ch == 'E')
                            break;
                        cc->cur_f64 = i * Pow10I64(-k);
                        cc->flags |= CCF_USE_LAST_U16;
                        cc->token = TK_F64;
                        goto lex_end;
                    }
                    ch = LexCharGet(cc);
                }
                ch = LexCharGet(cc);
                neg_e = FALSE;
                if (ch == '-') {
                    neg_e = TRUE;
                    ch = LexCharGet(cc);
                }
                j = 0;
                while (TRUE)
                {
                    if (Bt(char_bmp_dec_numeric, ch))
                        j = j * 10 + ch - '0';
                    else
                    {
                        if (neg_e)
                            cc->cur_f64 = i * Pow10I64(-j-k);
                        else
                            cc->cur_f64 = i * Pow10I64(j-k);
                        cc->flags |= CCF_USE_LAST_U16;
                        cc->token = TK_F64;
                        goto lex_end;
                    }
                    ch = LexCharGet(cc);
                }
                break;

            case '"':
                cc->flags |= CCF_IN_QUOTES;
                buf2 = NULL;
                i = 0;
                do
                {
                    j = LexInStr(cc, buf, STR_LEN, &str_done);
                    buf3 = MAlloc(i + j);
                    if (buf2)
                    {
                        MemCopy(buf3, buf2, i);
                        Free(buf2);
                        buf2 = buf3;
                        MemCopy(buf2 + i, buf, j);
                    }
                    else
                    {
                        buf2 = buf3;
                        MemCopy(buf2, buf, j);
                    }
                    i += j;
                }
                while (!str_done);

                Free(cc->cur_str);
                cc->cur_str = MAlloc(i);
                MemCopy(cc->cur_str, buf2, i);
                Free(buf2);
                cc->cur_str_len = i;
                cc->flags &= ~CCF_IN_QUOTES;
                cc->token = TK_STR;
                goto lex_end;

            case '\'':
                if (cc->flags & CCF_NO_CHAR_CONST)
                    break;
                k = 0;
                for (j = 0; j < 8; j++)
                {
                    if (!(ch = LexCharGet(cc)) || ch == '\'')
                        break;
                    if (ch == '\\')
                    {
                        switch (ch = LexCharGet(cc))
                        {
                            case '0':   k.u8[j] = 0;    break;
                            case '\'':  k.u8[j] = '\''; break;
                            case '\`':  k.u8[j] = '\`'; break;
                            case '"':   k.u8[j] = '"';  break;
                            case '\\':  k.u8[j] = '\\'; break;
                            case 'd':   k.u8[j] = '$';  break;
                            case 'n':   k.u8[j] = '\n'; break;
                            case 'r':   k.u8[j] = '\r'; break;
                            case 't':   k.u8[j] = '\t'; break;
                            case 'x':
                            case 'X':
                                i = 0;
                                for (l = 0; l < 2; l++)
                                {
                                    ch = ToUpper(LexCharGet(cc));
                                    if (Bt(char_bmp_hex_numeric, ch))
                                    {
                                        if (ch <= '9')
                                            i = i << 4 + ch - '0';
                                        else
                                            i = i << 4 + ch - 'A' + 10;
                                    }
                                    else
                                    {
                                        cc->flags |= CCF_USE_LAST_U16;
                                        break;
                                    }
                                }
                                k.u8[j] = i;
                                break;

                            default:
                                k.u8[j] = '\\';
                                cc->flags |= CCF_USE_LAST_U16;
                        }
                    }
                    else if (ch == '$')
                    {
                        ch = LexCharGet(cc);
                        k.u8[j] = '$';
                        if (ch != '$')
                            cc->flags |= CCF_USE_LAST_U16;
                    }
                    else
                        k.u8[j] = ch;
                }
                if (ch != '\'' && (ch = LexCharGet(cc)) && ch != '\'')
                    LexExcept(cc, "Char const limited to 8 chars at ");
                cc->cur_i64 = k;
                cc->token = TK_CHAR_CONST;
                goto lex_end;

            case '#':
                if (cc->flags & CCF_KEEP_SIGN_NUM)
                {
                    cc->token = ch;
                    goto lex_end;
                }
                if (Lex(cc) != TK_IDENT)    //skip '#'
                    goto lex_end;
                if (!(tmph = cc->hash_entry))
                    goto lex_end;
                if (!(tmph->type & HTT_KEYWORD))
                    goto lex_end;
                switch (i = tmph(CHashGeneric *)->user_data0)
                {
                    case KW_INCLUDE:
                        if (Lex(cc) != TK_STR)
                            goto lex_end;
                        fbuf = ExtDefault(cc->cur_str, "ZC");
                        buf2 = FileNameAbs(fbuf);
                        Free(fbuf);
                        if (Bt(&sys_run_level, RLf_DOC))
                            LexAttachDoc(cc,,, buf2);
                        else
                            LexIncludeStr(cc, buf2, FileRead(buf2), TRUE);
                        Free(buf2);
                        break;

                    case KW_DEFINE:
                        cc->flags |= CCF_NO_DEFINES;
                        if (Lex(cc) == TK_IDENT)
                        {
                            tmph = CAlloc(sizeof(CHashDefineStr));
                            tmph->str = cc->cur_str;
                            cc->cur_str = 0;
                            tmph->type = HTT_DEFINE_STR;
                            HashSrcFileSet(cc,tmph);

                            do ch = LexCharGet(cc); //skip space between define name and start
                            while (Bt(char_bmp_non_eol_white_space, ch));

                            i = j = 0;
                            buf2 = NULL;
                            if (ch)
                            {
                                in_str = FALSE;
                                do
                                {
                                    if (ch == '\\')
                                    {
                                        if (ch = LexCharGet(cc))
                                        {
                                            if (ch != '\r' && ch != '\n')
                                            {
                                                buf[j++] = '\\';
                                                buf[j++] = ch;
                                            }
                                            else if (ch == '\r' && LexCharGet(cc) != '\n')
                                                cc->flags|=CCF_USE_LAST_U16;
                                        }
                                        else
                                        {
                                            buf[j++] = '\\';
                                            break;
                                        }
                                    }
                                    else if (ch != '\n')
                                    {
                                        if (ch == '\"')
                                            in_str = !in_str;
                                        buf[j++] = ch;
                                    }
                                    else
                                        break;
                                    while (ch = LexCharGet(cc))
                                    {
                                        if (ch == '/') {
                                            ch = LexCharGet(cc);
                                            if (ch == '/' && !in_str)
                                            {
                                                do ch = LexCharGet(cc);
                                                while (Bt(char_bmp_non_eol, ch));
                                                break;
                                            }
                                            else
                                            {
                                                buf[j++] = '/';
                                                cc->flags |= CCF_USE_LAST_U16;
                                            }
                                        }
                                        else if (ch == '\\')
                                        {
                                            if (ch = LexCharGet(cc))
                                            {
                                                if (ch == '\"')
                                                {
                                                    buf[j++] = '\\';
                                                    buf[j++] = ch;
                                                }
                                                else
                                                {
                                                    cc->flags |= CCF_USE_LAST_U16;
                                                    ch = '\\';
                                                    break;
                                                }
                                            }
                                        }
                                        else if (Bt(char_bmp_non_eol, ch))
                                        {
                                            if (ch == '\"')
                                                in_str = !in_str;
                                            buf[j++] = ch;
                                        }
                                        else
                                            break;
                                        if (j >= STR_LEN - 4)
                                        {//Spot for ['\'][ch],[ch],[0]
                                            buf[j++] = 0;
                                            buf3 = MAlloc(i+j);
                                            if (buf2)
                                            {
                                                MemCopy(buf3, buf2, i);
                                                Free(buf2);
                                                buf2 = buf3;
                                                MemCopy(buf2 + i, buf, j);
                                            }
                                            else
                                            {
                                                buf2 = buf3;
                                                MemCopy(buf2, buf, j);
                                            }
                                            i += j - 1;
                                            j = 0;
                                        }
                                    }
                                }
                                while (ch == '\\');

                            }
                            buf[j++] = 0;
                            buf3 = MAlloc(i + j);
                            if (buf2)
                            {
                                MemCopy(buf3, buf2, i);
                                Free(buf2);
                                buf2 = buf3;
                                MemCopy(buf2 + i, buf, j);
                            }
                            else
                            {
                                buf2 = buf3;
                                MemCopy(buf2, buf, j);
                            }
                            tmph(CHashDefineStr *)->data = buf2;
                            tmph(CHashDefineStr *)->count = -1;
                            HashAdd(tmph,cc->htc.define_hash_table);
                        }
                        cc->flags &= ~CCF_NO_DEFINES;
                        break;

                    case KW_ELSE:
                        if (cc->flags & CCF_IN_IF)
                        {
                            cc->token = TK_ELSE;
                            goto lex_end;
                        }
lex_else:
                        j = 1;
                        do
                        {
                            if (ch = LexCharGet(cc))
                            {
                                if (ch == '#')
                                {
                                    if (!Lex(cc))
                                        goto lex_end;
                                    i = ParseKeyWord(cc);
                                    if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                        j++;
                                    else if (i == KW_ENDIF)
                                        j--;
                                }
                            }
                            else
                            {
                                cc->token = TK_EOF;
                                goto lex_end;
                            }
                        }
                        while (j);

                        break;

                    case KW_IF:
                        if (cc->flags & CCF_IN_IF)
                        {
                            cc->token = TK_IF;
                            goto lex_end;
                        }
lex_if:
                        cc->flags |= CCF_IN_IF;
                        if (!Lex(cc))
                        {
                            cc->flags &= ~CCF_IN_IF;
                            goto lex_end;
                        }
                        if (LexExpression(cc))
                        {
                            cc->flags &= ~CCF_IN_IF;
                            switch (cc->token)
                            {
                                case TK_IF:     goto lex_if;
                                case TK_IFDEF:  goto lex_ifdef;
                                case TK_IFNDEF: goto lex_ifndef;
                                case TK_IFAOT:  goto lex_ifaot;
                                case TK_IFJIT:  goto lex_ifjit;
                                case TK_ELSE:   goto lex_else;
                                case TK_ENDIF:  goto lex_cont;
                                default:        goto lex_end;
                            }
                        }
                        else
                        {
                            cc->flags &= ~CCF_IN_IF;
                            if (cc->token != TK_ENDIF && cc->token != TK_ELSE)
                            {
                                if (cc->token == TK_IF || cc->token == TK_IFDEF ||
                                        cc->token == TK_IFNDEF || cc->token == TK_IFAOT ||
                                        cc->token == TK_IFJIT)
                                    j = 2;
                                else
                                    j = 1;
                                do
                                {
                                    if (ch = LexCharGet(cc))
                                    {
                                        if (ch == '#')
                                        {
                                            if (!Lex(cc))
                                                goto lex_end;
                                            i = ParseKeyWord(cc);
                                            if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF ||
                                                    i == KW_IFAOT || i == KW_IFJIT)
                                                j++;
                                            else if (i == KW_ENDIF)
                                                j--;
                                            else if (i == KW_ELSE && j == 1)
                                                break;
                                        }
                                    }
                                    else
                                    {
                                        cc->token = TK_EOF;
                                        goto lex_end;
                                    }
                                }
                                while (j);

                            }
                        }
                        break;

                    case KW_IFDEF:
                        if (cc->flags & CCF_IN_IF)
                        {
                            cc->token = TK_IFDEF;
                            goto lex_end;
                        }
lex_ifdef:
                        cc->flags |= CCF_NO_DEFINES;
                        if (!Lex(cc))
                        {
                            cc->flags &= ~CCF_NO_DEFINES;
                            goto lex_end;
                        }
                        cc->flags &= ~CCF_NO_DEFINES;
                        if (cc->token != TK_IDENT)
                            goto lex_end;
                        if (cc->hash_entry)
                            goto lex_cont;
                        j = 1;
                        do
                        {
                            if (ch = LexCharGet(cc))
                            {
                                if (ch == '#')
                                {
                                    if (!Lex(cc))
                                        goto lex_end;
                                    i = ParseKeyWord(cc);
                                    if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                        j++;
                                    else if (i == KW_ENDIF)
                                        j--;
                                    else if (i == KW_ELSE && j == 1)
                                        break;
                                }
                            }
                            else
                            {
                                cc->token = TK_EOF;
                                goto lex_end;
                            }
                        }
                        while (j);

                        break;

                    case KW_IFNDEF:
                        if (cc->flags & CCF_IN_IF)
                        {
                            cc->token = TK_IFNDEF;
                            goto lex_end;
                        }
lex_ifndef:
                        cc->flags |= CCF_NO_DEFINES;
                        if (!Lex(cc))
                        {
                            cc->flags &= ~CCF_NO_DEFINES;
                            goto lex_end;
                        }
                        cc->flags &= ~CCF_NO_DEFINES;
                        if (cc->token != TK_IDENT)
                            goto lex_end;
                        if (!cc->hash_entry)
                            goto lex_cont;
                        j = 1;
                        do
                        {
                            if (ch = LexCharGet(cc))
                            {
                                if (ch == '#')
                                {
                                    if (!Lex(cc))
                                        goto lex_end;
                                    i = ParseKeyWord(cc);
                                    if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                        j++;
                                    else if (i == KW_ENDIF)
                                        j--;
                                    else if (i == KW_ELSE && j == 1)
                                        break;
                                }
                            }
                            else
                            {
                                cc->token = TK_EOF;
                                goto lex_end;
                            }
                        }
                        while (j);

                        break;

                    case KW_IFAOT:
                        if (cc->flags & CCF_IN_IF)
                        {
                            cc->token = TK_IFAOT;
                            goto lex_end;
                        }
lex_ifaot:
                        if (cc->flags & CCF_AOT_COMPILE)
                            goto lex_cont;
                        j = 1;
                        do
                        {
                            if (ch = LexCharGet(cc))
                            {
                                if (ch == '#')
                                {
                                    if (!Lex(cc))
                                        goto lex_end;
                                    i = ParseKeyWord(cc);
                                    if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                        j++;
                                    else if (i == KW_ENDIF)
                                        j--;
                                    else if (i == KW_ELSE && j == 1)
                                        break;
                                }
                            }
                            else
                            {
                                cc->token = TK_EOF;
                                goto lex_end;
                            }
                        }
                        while (j);

                        break;

                    case KW_IFJIT:
                        if (cc->flags & CCF_IN_IF)
                        {
                            cc->token = TK_IFAOT;
                            goto lex_end;
                        }
lex_ifjit:
                        if (!(cc->flags & CCF_AOT_COMPILE))
                            goto lex_cont;
                        j = 1;
                        do
                        {
                            if (ch = LexCharGet(cc))
                            {
                                if (ch == '#')
                                {
                                    if (!Lex(cc))
                                        goto lex_end;
                                    i = ParseKeyWord(cc);
                                    if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                        j++;
                                    else if (i == KW_ENDIF)
                                        j--;
                                    else if (i == KW_ELSE && j == 1)
                                        break;
                                }
                            }
                            else
                            {
                                cc->token = TK_EOF;
                                goto lex_end;
                            }
                        }
                        while (j);

                        break;

                    case KW_ENDIF:
                        if (cc->flags & CCF_IN_IF)
                        {
                            cc->token = TK_ENDIF;
                            goto lex_end;
                        }
                        break;

                    case KW_ASSERT:
                        if (!Lex(cc))
                            goto lex_end;
                        if (!LexExpression(cc))
                        {
                            PrintWarn("Assert Failed at ");
                            PutFileLink(cc->lex_include_stack->full_name,, cc->lex_include_stack->line_num);
                            '\n';
                        }
                        goto lex_end;

                    case KW_EXE:
                        if (!Lex(cc))
                            goto lex_end;
                        ParseStreamBlk(cc);
                        goto lex_end;

                    case KW_HELP_INDEX:
                        if (Lex(cc) != TK_STR)
                            goto lex_end;
                        Free(cc->cur_help_idx);
                        cc->cur_help_idx = LexExtStr(cc,, FALSE);
                        break;

                    case KW_HELP_FILE:
                        if (Lex(cc) != TK_STR)
                            goto lex_end;
                        tmph = CAlloc(sizeof(CHashSrcSym));
                        fbuf = ExtDefault(cc->cur_str, "DD");
                        tmph->str = FileNameAbs(fbuf);
                        Free(fbuf);
                        tmph->type = HTT_HELP_FILE | HTF_PUBLIC;
                        HashSrcFileSet(cc, tmph);
                        HashAdd(tmph, cc->htc.global_hash_table);
                        break;
                }
                break;

            case '\n':
                if (!(cc->flags & CCF_KEEP_NEW_LINES))
                    break; //else fall through

            case TK_INS_BIN:
            case TK_INS_BIN_SIZE:
                cc->token = ch;
                goto lex_end;

            case '.':
                if (cc->flags & CCF_KEEP_DOT)
                {
                    cc->token = ch;
                    goto lex_end;
                }
                if (cc->flags & CCF_LAST_WAS_DOT)
                {
                    cc->flags &= ~CCF_LAST_WAS_DOT;
                    goto lex_dot_dot;
                }
                ch = LexCharGet(cc);
                if ('0' <= ch <= '9')
                {
                    i = 0;
                    goto lex_float_start;
                }
                else if (ch == '.')
                {
lex_dot_dot:
                    cc->token = TK_DOT_DOT;
                    if (LexCharGet(cc) == '.')
                        cc->token = TK_ELLIPSIS;
                    else
                        cc->flags |= CCF_USE_LAST_U16;
                    goto lex_end;
                }
                cc->flags |= CCF_USE_LAST_U16;
                cc->token = '.';
                goto lex_end;

            case '!':
            case '$'...'&':
            case '('...'-':
            case '/':
            case ':'...'?':
            case '[':
            case ']'...'^':
            case '{'...'~':
            case '`':
                if (!(i = cmp.dual_U16_tokens1[ch]))
                {
                    if (ch == '$')
                    {
                        ch = LexCharGet(cc);
                        if (ch == '$') {
                            cc->token = '$';
                            goto lex_end;
                        }
                        else if (ch)
                        {
                            do ch = LexCharGet(cc);
                            while (ch && ch != '$');
                            if (!ch)
                            {
                                cc->token = TK_EOF;
                                goto lex_end;
                            }
                            else
                                goto lex_cont;
                        }
                        else
                        {
                            cc->flags |= CCF_USE_LAST_U16;
                            cc->token = '$';
                            goto lex_end;
                        }
                    }
                    else
                    {
                        cc->token = ch;
                        goto lex_end;
                    }
                }
                else
                {
                    j = LexCharGet(cc);
                    if (i.u16[0] == j)
                    {
                        i >>= 16;
                        if (!i)
                        {// "/*"
                            j = 1;
                            do
                            {
                                if (!(ch = LexCharGet(cc)))
                                    return cc->token = TK_EOF;
lex_check_comment:
                                if (ch == '*')
                                {
                                    if (!(ch = LexCharGet(cc)))
                                        return cc->token = TK_EOF;
                                    if (ch == '/')
                                        j--;
                                    else
                                        goto lex_check_comment;
                                }
                                else if (ch == '/')
                                {
                                    if (!(ch = LexCharGet(cc)))
                                        return cc->token = TK_EOF;
                                    if (ch == '*')
                                        j++;
                                    else
                                        goto lex_check_comment;
                                }
                            }
                            while (j);

                            goto lex_cont;
                        }
                        else
                        {
                            cc->token = i;
                            goto lex_end;
                        }
                    }
                    if (i = cmp.dual_U16_tokens2[ch])
                    {
                        if (i.u16[0] == j)
                        {
                            i >>= 16;
                            if (!i)
                            {// "//"
                                LexSkipEol(cc);
                                if (cc->flags & CCF_KEEP_NEW_LINES)
                                {
                                    cc->token = '\n';
                                    goto lex_end;
                                }
                                else
                                    goto lex_cont;
                            }
                            else
                            {
                                if (i == TK_SHL || i == TK_SHR)
                                {
                                    j = LexCharGet(cc);
                                    if (j == '=')
                                    {
                                        if (i == TK_SHL)
                                            i = TK_SHL_EQU;
                                        else
                                            i = TK_SHR_EQU;
                                    }
                                    else
                                        cc->flags |= CCF_USE_LAST_U16;
                                }
                                cc->token = i;
                                goto lex_end;
                            }
                        }
                        if (i = cmp.dual_U16_tokens3[ch])
                        {
                            if (i.u16[0] == j)
                            {
                                cc->token = i.u16[1];
                                goto lex_end;
                            }
                        }
                    }
                    cc->flags |= CCF_USE_LAST_U16;
                    cc->token = ch;
                    goto lex_end;
                }
            case TK_TKS_NUM:
                break;
        }
    }
lex_end:
    LexCharGet(cc); //Do this so WAS_NEW_LINE is right
    cc->flags |= CCF_USE_LAST_U16;

    return cc->token;
}